Blame view

sound/pci/hda/patch_realtek.c 167 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
  /*
   * Universal Interface for Intel High Definition Audio Codec
   *
1d045db96   Takashi Iwai   ALSA: hda - Split...
4
   * HD audio interface patch for Realtek ALC codecs
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   *
df694daa3   Kailang Yang   [ALSA] hda-codec ...
6
7
   * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
   *                    PeiSen Hou <pshou@realtek.com.tw>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   *                    Takashi Iwai <tiwai@suse.de>
7cf51e483   Jonathan Woithe   [ALSA] hda: ALC26...
9
   *                    Jonathan Woithe <jwoithe@physics.adelaide.edu.au>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   *
   *  This driver is free software; you can redistribute it and/or modify
   *  it under the terms of the GNU General Public License as published by
   *  the Free Software Foundation; either version 2 of the License, or
   *  (at your option) any later version.
   *
   *  This driver is distributed in the hope that it will be useful,
   *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *  GNU General Public License for more details.
   *
   *  You should have received a copy of the GNU General Public License
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
25
26
27
28
  #include <linux/init.h>
  #include <linux/delay.h>
  #include <linux/slab.h>
  #include <linux/pci.h>
da155d5b4   Paul Gortmaker   sound: Add module...
29
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #include <sound/core.h>
9ad0e4965   Kailang Yang   ALSA: hda - Add i...
31
  #include <sound/jack.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  #include "hda_codec.h"
  #include "hda_local.h"
680cd5365   Kusanagi Kouichi   ALSA: hda: Add di...
34
  #include "hda_beep.h"
1835a0f9a   Takashi Iwai   ALSA: hda - Cache...
35
  #include "hda_jack.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36

1d045db96   Takashi Iwai   ALSA: hda - Split...
37
38
39
40
41
  /* unsol event tags */
  #define ALC_FRONT_EVENT		0x01
  #define ALC_DCVOL_EVENT		0x02
  #define ALC_HP_EVENT		0x04
  #define ALC_MIC_EVENT		0x08
d4a86d819   Takashi Iwai   ALSA: hda - Add m...
42

df694daa3   Kailang Yang   [ALSA] hda-codec ...
43
44
  /* for GPIO Poll */
  #define GPIO_MASK	0x03
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
45
46
47
48
49
50
51
52
  /* extra amp-initialization sequence types */
  enum {
  	ALC_INIT_NONE,
  	ALC_INIT_DEFAULT,
  	ALC_INIT_GPIO1,
  	ALC_INIT_GPIO2,
  	ALC_INIT_GPIO3,
  };
da00c2449   Kailang Yang   ALSA: hda - Add p...
53
54
55
56
57
58
59
60
61
62
  struct alc_customize_define {
  	unsigned int  sku_cfg;
  	unsigned char port_connectivity;
  	unsigned char check_sum;
  	unsigned char customization;
  	unsigned char external_amp;
  	unsigned int  enable_pcbeep:1;
  	unsigned int  platform_type:1;
  	unsigned int  swap:1;
  	unsigned int  override:1;
906229174   David Henningsson   ALSA: HDA: Enable...
63
  	unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
da00c2449   Kailang Yang   ALSA: hda - Add p...
64
  };
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
65
  struct alc_fixup;
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
66
67
68
69
70
  struct alc_multi_io {
  	hda_nid_t pin;		/* multi-io widget pin NID */
  	hda_nid_t dac;		/* DAC to be connected */
  	unsigned int ctl_in;	/* cached input-pin control value */
  };
d922b51da   Takashi Iwai   ALSA: hda - Conso...
71
  enum {
3b8510ce9   Takashi Iwai   ALSA: hda - Add c...
72
73
74
  	ALC_AUTOMUTE_PIN,	/* change the pin control */
  	ALC_AUTOMUTE_AMP,	/* mute/unmute the pin AMP */
  	ALC_AUTOMUTE_MIXER,	/* mute/unmute mixer widget AMP */
d922b51da   Takashi Iwai   ALSA: hda - Conso...
75
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76
77
  struct alc_spec {
  	/* codec parameterization */
a9111321f   Takashi Iwai   ALSA: hda - Const...
78
  	const struct snd_kcontrol_new *mixers[5];	/* mixer arrays */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  	unsigned int num_mixers;
a9111321f   Takashi Iwai   ALSA: hda - Const...
80
  	const struct snd_kcontrol_new *cap_mixer;	/* capture mixer */
45bdd1c1b   Takashi Iwai   ALSA: hda - Creat...
81
  	unsigned int beep_amp;	/* beep amp value, set via set_beep_amp() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82

2d9c64829   Takashi Iwai   ALSA: hda - Fix o...
83
  	const struct hda_verb *init_verbs[10];	/* initialization verbs
9c7f852e8   Takashi Iwai   [ALSA] Fix/add su...
84
85
  						 * don't forget NULL
  						 * termination!
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
86
87
  						 */
  	unsigned int num_init_verbs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88

aa563af76   Takashi Iwai   ALSA: hda - Incre...
89
  	char stream_name_analog[32];	/* analog PCM stream */
a9111321f   Takashi Iwai   ALSA: hda - Const...
90
91
92
93
  	const struct hda_pcm_stream *stream_analog_playback;
  	const struct hda_pcm_stream *stream_analog_capture;
  	const struct hda_pcm_stream *stream_analog_alt_playback;
  	const struct hda_pcm_stream *stream_analog_alt_capture;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94

aa563af76   Takashi Iwai   ALSA: hda - Incre...
95
  	char stream_name_digital[32];	/* digital PCM stream */
a9111321f   Takashi Iwai   ALSA: hda - Const...
96
97
  	const struct hda_pcm_stream *stream_digital_playback;
  	const struct hda_pcm_stream *stream_digital_capture;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
  
  	/* playback */
16ded5253   Takashi Iwai   [ALSA] hda-codec ...
100
101
102
103
  	struct hda_multi_out multiout;	/* playback set-up
  					 * max_channels, dacs must be set
  					 * dig_out_nid and hp_nid are optional
  					 */
6330079fc   Takashi Iwai   [ALSA] hda-codec ...
104
  	hda_nid_t alt_dac_nid;
6a05ac4af   Takashi Iwai   ALSA: hda - Suppo...
105
  	hda_nid_t slave_dig_outs[3];	/* optional - for auto-parsing */
8c441982f   Takashi Iwai   ALSA: hda - Assig...
106
  	int dig_out_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
  
  	/* capture */
  	unsigned int num_adc_nids;
4c6d72d13   Takashi Iwai   ALSA: hda - Const...
110
111
  	const hda_nid_t *adc_nids;
  	const hda_nid_t *capsrc_nids;
16ded5253   Takashi Iwai   [ALSA] hda-codec ...
112
  	hda_nid_t dig_in_nid;		/* digital-in NID; optional */
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
113
  	hda_nid_t mixer_nid;		/* analog-mixer NID */
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
114
115
  	DECLARE_BITMAP(vol_ctls, 0x20 << 1);
  	DECLARE_BITMAP(sw_ctls, 0x20 << 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116

840b64c08   Takashi Iwai   ALSA: hda - Add s...
117
  	/* capture setup for dynamic dual-adc switch */
840b64c08   Takashi Iwai   ALSA: hda - Add s...
118
119
120
  	hda_nid_t cur_adc;
  	unsigned int cur_adc_stream_tag;
  	unsigned int cur_adc_format;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121
  	/* capture source */
a1e8d2da0   Jonathan Woithe   [ALSA] HDA/Realte...
122
  	unsigned int num_mux_defs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
  	const struct hda_input_mux *input_mux;
  	unsigned int cur_mux[3];
21268961d   Takashi Iwai   ALSA: hda - More ...
125
126
127
  	hda_nid_t ext_mic_pin;
  	hda_nid_t dock_mic_pin;
  	hda_nid_t int_mic_pin;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128
129
  
  	/* channel model */
d2a6d7dc7   Takashi Iwai   [ALSA] hda-codec ...
130
  	const struct hda_channel_mode *channel_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  	int num_channel_mode;
4e195a7b7   Takashi Iwai   [ALSA] Fix noisy ...
132
  	int need_dac_fix;
3b315d70b   Hector Martin   ALSA: hda - Acer ...
133
134
  	int const_channel_count;
  	int ext_channel_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
  
  	/* PCM information */
4c5186ed6   Jonathan Woithe   [ALSA] hda: add P...
137
  	struct hda_pcm pcm_rec[3];	/* used in alc_build_pcms() */
41e41f1f3   Takashi Iwai   [ALSA] Fix the an...
138

e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
139
140
  	/* dynamic controls, init_verbs and input_mux */
  	struct auto_pin_cfg autocfg;
da00c2449   Kailang Yang   ALSA: hda - Add p...
141
  	struct alc_customize_define cdefine;
603c40199   Takashi Iwai   ALSA: hda - Use g...
142
  	struct snd_array kctls;
61b9b9b10   Herton Ronaldo Krzesinski   ALSA: hda - Consi...
143
  	struct hda_input_mux private_imux[3];
41923e441   Takashi Iwai   [ALSA] hda-codec ...
144
  	hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
4953550a6   Takashi Iwai   ALSA: hda - Merge...
145
146
  	hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS];
  	hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS];
21268961d   Takashi Iwai   ALSA: hda - More ...
147
148
149
  	hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
  	unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
  	int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */
834be88d1   Takashi Iwai   [ALSA] hda-codec ...
150

ae6b813a4   Takashi Iwai   [ALSA] hda-codec ...
151
152
153
  	/* hooks */
  	void (*init_hook)(struct hda_codec *codec);
  	void (*unsol_event)(struct hda_codec *codec, unsigned int res);
f5de24b06   Hector Martin   ALSA: HDA: add po...
154
  #ifdef CONFIG_SND_HDA_POWER_SAVE
c97259df3   Daniel T Chen   ALSA: hda: Refact...
155
  	void (*power_hook)(struct hda_codec *codec);
f5de24b06   Hector Martin   ALSA: HDA: add po...
156
  #endif
1c716153a   Takashi Iwai   ALSA: hda - Intro...
157
  	void (*shutup)(struct hda_codec *codec);
245199116   Takashi Iwai   ALSA: hda - Repla...
158
  	void (*automute_hook)(struct hda_codec *codec);
ae6b813a4   Takashi Iwai   [ALSA] hda-codec ...
159

834be88d1   Takashi Iwai   [ALSA] hda-codec ...
160
  	/* for pin sensing */
42cf0d015   David Henningsson   ALSA: HDA: Refact...
161
  	unsigned int hp_jack_present:1;
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
162
  	unsigned int line_jack_present:1;
e9427969f   Takashi Iwai   ALSA: hda - Conso...
163
  	unsigned int master_mute:1;
6c8194922   Takashi Iwai   ALSA: hda - Add a...
164
  	unsigned int auto_mic:1;
21268961d   Takashi Iwai   ALSA: hda - More ...
165
  	unsigned int auto_mic_valid_imux:1;	/* valid imux for auto-mic */
42cf0d015   David Henningsson   ALSA: HDA: Refact...
166
167
168
169
170
171
  	unsigned int automute_speaker:1; /* automute speaker outputs */
  	unsigned int automute_lo:1; /* automute LO outputs */
  	unsigned int detect_hp:1;	/* Headphone detection enabled */
  	unsigned int detect_lo:1;	/* Line-out detection enabled */
  	unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
  	unsigned int automute_lo_possible:1;	  /* there are line outs and HP */
cb53c626e   Takashi Iwai   [ALSA] hda-intel ...
172

e64f14f4e   Takashi Iwai   ALSA: hda - Allow...
173
174
  	/* other flags */
  	unsigned int no_analog :1; /* digital I/O only */
21268961d   Takashi Iwai   ALSA: hda - More ...
175
  	unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
584c0c4c3   Takashi Iwai   ALSA: hda - Initi...
176
  	unsigned int single_input_src:1;
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
177
  	unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */
53c334add   Takashi Iwai   ALSA: hda - Rewri...
178
  	unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */
24de183ed   Takashi Iwai   ALSA: hda/realtek...
179
  	unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */
3a93897ea   Takashi Iwai   ALSA: hda - Manag...
180
  	unsigned int use_jack_tbl:1; /* 1 for model=auto */
d922b51da   Takashi Iwai   ALSA: hda - Conso...
181
182
183
  
  	/* auto-mute control */
  	int automute_mode;
3b8510ce9   Takashi Iwai   ALSA: hda - Add c...
184
  	hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS];
d922b51da   Takashi Iwai   ALSA: hda - Conso...
185

4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
186
  	int init_amp;
d433a6783   Takashi Iwai   ALSA: hda - Optim...
187
  	int codec_variant;	/* flag for other variants */
e64f14f4e   Takashi Iwai   ALSA: hda - Allow...
188

2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
189
190
  	/* for virtual master */
  	hda_nid_t vmaster_nid;
cb53c626e   Takashi Iwai   [ALSA] hda-intel ...
191
192
193
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  	struct hda_loopback_check loopback;
  #endif
2c3bf9abb   Takashi Iwai   [ALSA] hda - Fix ...
194
195
196
197
  
  	/* for PLL fix */
  	hda_nid_t pll_nid;
  	unsigned int pll_coef_idx, pll_coef_bit;
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
198
  	unsigned int coef0;
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
199
200
201
202
203
  
  	/* fix-up list */
  	int fixup_id;
  	const struct alc_fixup *fixup_list;
  	const char *fixup_name;
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
204
205
206
207
  
  	/* multi-io */
  	int multi_ios;
  	struct alc_multi_io multi_io[4];
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
208
209
210
  
  	/* bind volumes */
  	struct snd_array bind_ctls;
df694daa3   Kailang Yang   [ALSA] hda-codec ...
211
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
212
  #define ALC_MODEL_AUTO		0	/* common for all chips */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213

44c024005   Takashi Iwai   ALSA: hda - Fix a...
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid,
  			   int dir, unsigned int bits)
  {
  	if (!nid)
  		return false;
  	if (get_wcaps(codec, nid) & (1 << (dir + 1)))
  		if (query_amp_caps(codec, nid, dir) & bits)
  			return true;
  	return false;
  }
  
  #define nid_has_mute(codec, nid, dir) \
  	check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE)
  #define nid_has_volume(codec, nid, dir) \
  	check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
  /*
   * input MUX handling
   */
9c7f852e8   Takashi Iwai   [ALSA] Fix/add su...
232
233
  static int alc_mux_enum_info(struct snd_kcontrol *kcontrol,
  			     struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
a1e8d2da0   Jonathan Woithe   [ALSA] HDA/Realte...
237
238
239
  	unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id);
  	if (mux_idx >= spec->num_mux_defs)
  		mux_idx = 0;
5311114d4   Takashi Iwai   ALSA: hda - Fix i...
240
241
  	if (!spec->input_mux[mux_idx].num_items && mux_idx > 0)
  		mux_idx = 0;
a1e8d2da0   Jonathan Woithe   [ALSA] HDA/Realte...
242
  	return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
  }
9c7f852e8   Takashi Iwai   [ALSA] Fix/add su...
244
245
  static int alc_mux_enum_get(struct snd_kcontrol *kcontrol,
  			    struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
247
248
249
250
251
252
253
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
  	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
  
  	ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
  	return 0;
  }
21268961d   Takashi Iwai   ALSA: hda - More ...
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
  static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
  {
  	struct alc_spec *spec = codec->spec;
  	hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
  
  	if (spec->cur_adc && spec->cur_adc != new_adc) {
  		/* stream is running, let's swap the current ADC */
  		__snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
  		spec->cur_adc = new_adc;
  		snd_hda_codec_setup_stream(codec, new_adc,
  					   spec->cur_adc_stream_tag, 0,
  					   spec->cur_adc_format);
  		return true;
  	}
  	return false;
  }
61071594f   Takashi Iwai   ALSA: hda/realtek...
270
271
272
273
274
  static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx)
  {
  	return spec->capsrc_nids ?
  		spec->capsrc_nids[idx] : spec->adc_nids[idx];
  }
24de183ed   Takashi Iwai   ALSA: hda/realtek...
275
  static void call_update_outputs(struct hda_codec *codec);
21268961d   Takashi Iwai   ALSA: hda - More ...
276
277
278
  /* select the given imux item; either unmute exclusively or select the route */
  static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx,
  			  unsigned int idx, bool force)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  	struct alc_spec *spec = codec->spec;
cd896c331   Takashi Iwai   ALSA: hda - Allow...
281
  	const struct hda_input_mux *imux;
cd896c331   Takashi Iwai   ALSA: hda - Allow...
282
  	unsigned int mux_idx;
dccc1810f   Takashi Iwai   ALSA: hda - Mute ...
283
  	int i, type, num_conns;
21268961d   Takashi Iwai   ALSA: hda - More ...
284
  	hda_nid_t nid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285

cd896c331   Takashi Iwai   ALSA: hda - Allow...
286
287
  	mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx;
  	imux = &spec->input_mux[mux_idx];
5311114d4   Takashi Iwai   ALSA: hda - Fix i...
288
289
  	if (!imux->num_items && mux_idx > 0)
  		imux = &spec->input_mux[0];
cce4aa378   Takashi Iwai   ALSA: hda/realtek...
290
291
  	if (!imux->num_items)
  		return 0;
cd896c331   Takashi Iwai   ALSA: hda - Allow...
292

21268961d   Takashi Iwai   ALSA: hda - More ...
293
294
295
296
297
  	if (idx >= imux->num_items)
  		idx = imux->num_items - 1;
  	if (spec->cur_mux[adc_idx] == idx && !force)
  		return 0;
  	spec->cur_mux[adc_idx] = idx;
24de183ed   Takashi Iwai   ALSA: hda/realtek...
298
299
300
301
302
303
304
305
306
307
308
309
  	/* for shared I/O, change the pin-control accordingly */
  	if (spec->shared_mic_hp) {
  		/* NOTE: this assumes that there are only two inputs, the
  		 * first is the real internal mic and the second is HP jack.
  		 */
  		snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0,
  				    AC_VERB_SET_PIN_WIDGET_CONTROL,
  				    spec->cur_mux[adc_idx] ?
  				    PIN_VREF80 : PIN_HP);
  		spec->automute_speaker = !spec->cur_mux[adc_idx];
  		call_update_outputs(codec);
  	}
21268961d   Takashi Iwai   ALSA: hda - More ...
310
311
312
313
  	if (spec->dyn_adc_switch) {
  		alc_dyn_adc_pcm_resetup(codec, idx);
  		adc_idx = spec->dyn_adc_idx[idx];
  	}
61071594f   Takashi Iwai   ALSA: hda/realtek...
314
  	nid = get_capsrc(spec, adc_idx);
21268961d   Takashi Iwai   ALSA: hda - More ...
315
316
  
  	/* no selection? */
dccc1810f   Takashi Iwai   ALSA: hda - Mute ...
317
318
  	num_conns = snd_hda_get_conn_list(codec, nid, NULL);
  	if (num_conns <= 1)
21268961d   Takashi Iwai   ALSA: hda - More ...
319
  		return 1;
a22d543a9   Takashi Iwai   ALSA: hda - Intro...
320
  	type = get_wcaps_type(get_wcaps(codec, nid));
0169b6b33   Takashi Iwai   ALSA: hda - Fix c...
321
  	if (type == AC_WID_AUD_MIX) {
54cbc9abe   Takashi Iwai   ALSA: hda - Unify...
322
  		/* Matrix-mixer style (e.g. ALC882) */
dccc1810f   Takashi Iwai   ALSA: hda - Mute ...
323
324
325
326
  		int active = imux->items[idx].index;
  		for (i = 0; i < num_conns; i++) {
  			unsigned int v = (i == active) ? 0 : HDA_AMP_MUTE;
  			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, i,
54cbc9abe   Takashi Iwai   ALSA: hda - Unify...
327
328
  						 HDA_AMP_MUTE, v);
  		}
54cbc9abe   Takashi Iwai   ALSA: hda - Unify...
329
330
  	} else {
  		/* MUX style (e.g. ALC880) */
21268961d   Takashi Iwai   ALSA: hda - More ...
331
332
333
  		snd_hda_codec_write_cache(codec, nid, 0,
  					  AC_VERB_SET_CONNECT_SEL,
  					  imux->items[idx].index);
54cbc9abe   Takashi Iwai   ALSA: hda - Unify...
334
  	}
21268961d   Takashi Iwai   ALSA: hda - More ...
335
336
337
338
339
340
341
342
343
344
  	return 1;
  }
  
  static int alc_mux_enum_put(struct snd_kcontrol *kcontrol,
  			    struct snd_ctl_elem_value *ucontrol)
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
  	return alc_mux_select(codec, adc_idx,
  			      ucontrol->value.enumerated.item[0], false);
54cbc9abe   Takashi Iwai   ALSA: hda - Unify...
345
  }
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
346

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  /*
23f0c048b   Takashi Iwai   ALSA: hda - Clean...
348
349
350
351
352
353
   * set up the input pin config (depending on the given auto-pin type)
   */
  static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid,
  			      int auto_pin_type)
  {
  	unsigned int val = PIN_IN;
86e2959a1   Takashi Iwai   ALSA: hda - Remov...
354
  	if (auto_pin_type == AUTO_PIN_MIC) {
23f0c048b   Takashi Iwai   ALSA: hda - Clean...
355
  		unsigned int pincap;
954a29c88   Takashi Iwai   ALSA: hda - Prefe...
356
357
358
  		unsigned int oldval;
  		oldval = snd_hda_codec_read(codec, nid, 0,
  					    AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
1327a32b8   Takashi Iwai   ALSA: hda - Cache...
359
  		pincap = snd_hda_query_pin_caps(codec, nid);
23f0c048b   Takashi Iwai   ALSA: hda - Clean...
360
  		pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
954a29c88   Takashi Iwai   ALSA: hda - Prefe...
361
362
  		/* if the default pin setup is vref50, we give it priority */
  		if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50)
23f0c048b   Takashi Iwai   ALSA: hda - Clean...
363
  			val = PIN_VREF80;
461c6c3a0   Takashi Iwai   ALSA: hda - Add m...
364
365
366
367
368
369
  		else if (pincap & AC_PINCAP_VREF_50)
  			val = PIN_VREF50;
  		else if (pincap & AC_PINCAP_VREF_100)
  			val = PIN_VREF100;
  		else if (pincap & AC_PINCAP_VREF_GRD)
  			val = PIN_VREFGRD;
23f0c048b   Takashi Iwai   ALSA: hda - Clean...
370
371
372
373
374
  	}
  	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val);
  }
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
375
376
377
   * Append the given mixer and verb elements for the later use
   * The mixer array is referred in build_controls(), and init_verbs are
   * called in init().
d88897eae   Takashi Iwai   ALSA: hda - Use m...
378
   */
a9111321f   Takashi Iwai   ALSA: hda - Const...
379
  static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix)
d88897eae   Takashi Iwai   ALSA: hda - Use m...
380
381
382
383
384
385
386
387
388
389
390
391
392
393
  {
  	if (snd_BUG_ON(spec->num_mixers >= ARRAY_SIZE(spec->mixers)))
  		return;
  	spec->mixers[spec->num_mixers++] = mix;
  }
  
  static void add_verb(struct alc_spec *spec, const struct hda_verb *verb)
  {
  	if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs)))
  		return;
  	spec->init_verbs[spec->num_init_verbs++] = verb;
  }
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
394
   * GPIO setup tables, used in initialization
df694daa3   Kailang Yang   [ALSA] hda-codec ...
395
   */
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
396
  /* Enable GPIO mask and set output */
a9111321f   Takashi Iwai   ALSA: hda - Const...
397
  static const struct hda_verb alc_gpio1_init_verbs[] = {
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
398
399
400
401
402
  	{0x01, AC_VERB_SET_GPIO_MASK, 0x01},
  	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
  	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
  	{ }
  };
a9111321f   Takashi Iwai   ALSA: hda - Const...
403
  static const struct hda_verb alc_gpio2_init_verbs[] = {
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
404
405
406
407
408
  	{0x01, AC_VERB_SET_GPIO_MASK, 0x02},
  	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
  	{0x01, AC_VERB_SET_GPIO_DATA, 0x02},
  	{ }
  };
a9111321f   Takashi Iwai   ALSA: hda - Const...
409
  static const struct hda_verb alc_gpio3_init_verbs[] = {
bdd148a30   Kailang Yang   [ALSA] hda-codec ...
410
411
412
413
414
  	{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
  	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03},
  	{0x01, AC_VERB_SET_GPIO_DATA, 0x03},
  	{ }
  };
2c3bf9abb   Takashi Iwai   [ALSA] hda - Fix ...
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
  /*
   * Fix hardware PLL issue
   * On some codecs, the analog PLL gating control must be off while
   * the default value is 1.
   */
  static void alc_fix_pll(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	unsigned int val;
  
  	if (!spec->pll_nid)
  		return;
  	snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
  			    spec->pll_coef_idx);
  	val = snd_hda_codec_read(codec, spec->pll_nid, 0,
  				 AC_VERB_GET_PROC_COEF, 0);
  	snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_COEF_INDEX,
  			    spec->pll_coef_idx);
  	snd_hda_codec_write(codec, spec->pll_nid, 0, AC_VERB_SET_PROC_COEF,
  			    val & ~(1 << spec->pll_coef_bit));
  }
  
  static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
  			     unsigned int coef_idx, unsigned int coef_bit)
  {
  	struct alc_spec *spec = codec->spec;
  	spec->pll_nid = nid;
  	spec->pll_coef_idx = coef_idx;
  	spec->pll_coef_bit = coef_bit;
  	alc_fix_pll(codec);
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
446
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
447
448
449
450
451
   * Jack detections for HP auto-mute and mic-switch
   */
  
  /* check each pin in the given array; returns true if any of them is plugged */
  static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins)
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
452
  {
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
453
  	int i, present = 0;
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
454

e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
455
456
  	for (i = 0; i < num_pins; i++) {
  		hda_nid_t nid = pins[i];
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
457
458
  		if (!nid)
  			break;
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
459
  		present |= snd_hda_jack_detect(codec, nid);
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
460
  	}
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
461
462
  	return present;
  }
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
463

1d045db96   Takashi Iwai   ALSA: hda - Split...
464
  /* standard HP/line-out auto-mute helper */
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
465
  static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
e9427969f   Takashi Iwai   ALSA: hda - Conso...
466
  			bool mute, bool hp_out)
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
467
468
469
  {
  	struct alc_spec *spec = codec->spec;
  	unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0;
e9427969f   Takashi Iwai   ALSA: hda - Conso...
470
  	unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT);
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
471
472
473
474
  	int i;
  
  	for (i = 0; i < num_pins; i++) {
  		hda_nid_t nid = pins[i];
a9fd4f3fc   Takashi Iwai   ALSA: hda - Clean...
475
476
  		if (!nid)
  			break;
3b8510ce9   Takashi Iwai   ALSA: hda - Add c...
477
478
  		switch (spec->automute_mode) {
  		case ALC_AUTOMUTE_PIN:
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
479
  			snd_hda_codec_write(codec, nid, 0,
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
480
481
  					    AC_VERB_SET_PIN_WIDGET_CONTROL,
  					    pin_bits);
3b8510ce9   Takashi Iwai   ALSA: hda - Add c...
482
483
  			break;
  		case ALC_AUTOMUTE_AMP:
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
484
  			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
485
  						 HDA_AMP_MUTE, mute_bits);
3b8510ce9   Takashi Iwai   ALSA: hda - Add c...
486
487
488
489
490
491
  			break;
  		case ALC_AUTOMUTE_MIXER:
  			nid = spec->automute_mixer_nid[i];
  			if (!nid)
  				break;
  			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0,
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
492
  						 HDA_AMP_MUTE, mute_bits);
3b8510ce9   Takashi Iwai   ALSA: hda - Add c...
493
  			snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1,
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
494
  						 HDA_AMP_MUTE, mute_bits);
3b8510ce9   Takashi Iwai   ALSA: hda - Add c...
495
  			break;
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
496
  		}
a9fd4f3fc   Takashi Iwai   ALSA: hda - Clean...
497
  	}
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
498
  }
42cf0d015   David Henningsson   ALSA: HDA: Refact...
499
500
  /* Toggle outputs muting */
  static void update_outputs(struct hda_codec *codec)
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
501
502
  {
  	struct alc_spec *spec = codec->spec;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
503
  	int on;
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
504

c0a20263d   Takashi Iwai   ALSA: hda - Fix i...
505
506
507
508
  	/* Control HP pins/amps depending on master_mute state;
  	 * in general, HP pins/amps control should be enabled in all cases,
  	 * but currently set only for master_mute, just to be safe
  	 */
24de183ed   Takashi Iwai   ALSA: hda/realtek...
509
510
  	if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */
  		do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
c0a20263d   Takashi Iwai   ALSA: hda - Fix i...
511
  		    spec->autocfg.hp_pins, spec->master_mute, true);
42cf0d015   David Henningsson   ALSA: HDA: Refact...
512
  	if (!spec->automute_speaker)
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
513
514
  		on = 0;
  	else
42cf0d015   David Henningsson   ALSA: HDA: Refact...
515
  		on = spec->hp_jack_present | spec->line_jack_present;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
516
  	on |= spec->master_mute;
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
517
  	do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
518
  		    spec->autocfg.speaker_pins, on, false);
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
519
520
  
  	/* toggle line-out mutes if needed, too */
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
521
522
523
  	/* if LO is a copy of either HP or Speaker, don't need to handle it */
  	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
  	    spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
524
  		return;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
525
  	if (!spec->automute_lo)
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
526
527
  		on = 0;
  	else
42cf0d015   David Henningsson   ALSA: HDA: Refact...
528
  		on = spec->hp_jack_present;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
529
  	on |= spec->master_mute;
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
530
  	do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
531
  		    spec->autocfg.line_out_pins, on, false);
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
532
  }
42cf0d015   David Henningsson   ALSA: HDA: Refact...
533
  static void call_update_outputs(struct hda_codec *codec)
245199116   Takashi Iwai   ALSA: hda - Repla...
534
535
536
537
538
  {
  	struct alc_spec *spec = codec->spec;
  	if (spec->automute_hook)
  		spec->automute_hook(codec);
  	else
42cf0d015   David Henningsson   ALSA: HDA: Refact...
539
  		update_outputs(codec);
245199116   Takashi Iwai   ALSA: hda - Repla...
540
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
541
  /* standard HP-automute helper */
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
542
543
544
  static void alc_hp_automute(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
545
  	spec->hp_jack_present =
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
546
547
  		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
  			     spec->autocfg.hp_pins);
42cf0d015   David Henningsson   ALSA: HDA: Refact...
548
  	if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
3c715a988   Takashi Iwai   ALSA: hda - Updat...
549
  		return;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
550
  	call_update_outputs(codec);
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
551
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
552
  /* standard line-out-automute helper */
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
553
554
555
  static void alc_line_automute(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
e0d32e335   Takashi Iwai   ALSA: hda/realtek...
556
557
558
  	/* check LO jack only when it's different from HP */
  	if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
  		return;
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
559
560
561
  	spec->line_jack_present =
  		detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
  			     spec->autocfg.line_out_pins);
42cf0d015   David Henningsson   ALSA: HDA: Refact...
562
  	if (!spec->automute_speaker || !spec->detect_lo)
3c715a988   Takashi Iwai   ALSA: hda - Updat...
563
  		return;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
564
  	call_update_outputs(codec);
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
565
  }
8d087c760   Takashi Iwai   ALSA: hda - Creat...
566
567
  #define get_connection_index(codec, mux, nid) \
  	snd_hda_get_conn_index(codec, mux, nid, 0)
6c8194922   Takashi Iwai   ALSA: hda - Add a...
568

1d045db96   Takashi Iwai   ALSA: hda - Split...
569
  /* standard mic auto-switch helper */
7fb0d78fb   Kailang Yang   ALSA: hda - Add a...
570
571
572
  static void alc_mic_automute(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
21268961d   Takashi Iwai   ALSA: hda - More ...
573
  	hda_nid_t *pins = spec->imux_pins;
6c8194922   Takashi Iwai   ALSA: hda - Add a...
574

21268961d   Takashi Iwai   ALSA: hda - More ...
575
  	if (!spec->auto_mic || !spec->auto_mic_valid_imux)
6c8194922   Takashi Iwai   ALSA: hda - Add a...
576
577
578
  		return;
  	if (snd_BUG_ON(!spec->adc_nids))
  		return;
21268961d   Takashi Iwai   ALSA: hda - More ...
579
  	if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0))
840b64c08   Takashi Iwai   ALSA: hda - Add s...
580
  		return;
6c8194922   Takashi Iwai   ALSA: hda - Add a...
581

21268961d   Takashi Iwai   ALSA: hda - More ...
582
583
584
585
586
587
588
  	if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx]))
  		alc_mux_select(codec, 0, spec->ext_mic_idx, false);
  	else if (spec->dock_mic_idx >= 0 &&
  		   snd_hda_jack_detect(codec, pins[spec->dock_mic_idx]))
  		alc_mux_select(codec, 0, spec->dock_mic_idx, false);
  	else
  		alc_mux_select(codec, 0, spec->int_mic_idx, false);
7fb0d78fb   Kailang Yang   ALSA: hda - Add a...
589
  }
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
590
591
592
  /* unsolicited event for HP jack sensing */
  static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res)
  {
3a93897ea   Takashi Iwai   ALSA: hda - Manag...
593
  	struct alc_spec *spec = codec->spec;
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
594
595
596
597
  	if (codec->vendor_id == 0x10ec0880)
  		res >>= 28;
  	else
  		res >>= 26;
3a93897ea   Takashi Iwai   ALSA: hda - Manag...
598
599
  	if (spec->use_jack_tbl)
  		res = snd_hda_jack_get_action(codec, res);
a9fd4f3fc   Takashi Iwai   ALSA: hda - Clean...
600
  	switch (res) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
601
  	case ALC_HP_EVENT:
d922b51da   Takashi Iwai   ALSA: hda - Conso...
602
  		alc_hp_automute(codec);
a9fd4f3fc   Takashi Iwai   ALSA: hda - Clean...
603
  		break;
1d045db96   Takashi Iwai   ALSA: hda - Split...
604
  	case ALC_FRONT_EVENT:
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
605
606
  		alc_line_automute(codec);
  		break;
1d045db96   Takashi Iwai   ALSA: hda - Split...
607
  	case ALC_MIC_EVENT:
7fb0d78fb   Kailang Yang   ALSA: hda - Add a...
608
  		alc_mic_automute(codec);
a9fd4f3fc   Takashi Iwai   ALSA: hda - Clean...
609
610
  		break;
  	}
01a61e12b   Takashi Iwai   ALSA: hda - Creat...
611
  	snd_hda_jack_report_sync(codec);
7fb0d78fb   Kailang Yang   ALSA: hda - Add a...
612
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
613
  /* call init functions of standard auto-mute helpers */
7fb0d78fb   Kailang Yang   ALSA: hda - Add a...
614
615
  static void alc_inithook(struct hda_codec *codec)
  {
d922b51da   Takashi Iwai   ALSA: hda - Conso...
616
  	alc_hp_automute(codec);
e6a5e1b70   Takashi Iwai   ALSA: hda - Add s...
617
  	alc_line_automute(codec);
7fb0d78fb   Kailang Yang   ALSA: hda - Add a...
618
  	alc_mic_automute(codec);
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
619
  }
f9423e7a9   Kailang Yang   [ALSA] hda - Fix ...
620
621
622
623
624
625
626
627
  /* additional initialization for ALC888 variants */
  static void alc888_coef_init(struct hda_codec *codec)
  {
  	unsigned int tmp;
  
  	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0);
  	tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
  	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
37db623ae   Takashi Iwai   ALSA: hda - Fix c...
628
  	if ((tmp & 0xf0) == 0x20)
f9423e7a9   Kailang Yang   [ALSA] hda - Fix ...
629
630
631
632
633
634
635
636
  		/* alc888S-VC */
  		snd_hda_codec_read(codec, 0x20, 0,
  				   AC_VERB_SET_PROC_COEF, 0x830);
  	 else
  		 /* alc888-VB */
  		 snd_hda_codec_read(codec, 0x20, 0,
  				    AC_VERB_SET_PROC_COEF, 0x3030);
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
637
  /* additional initialization for ALC889 variants */
87a8c3702   Jaroslav Kysela   ALSA: hda - Add b...
638
639
640
641
642
643
644
645
646
  static void alc889_coef_init(struct hda_codec *codec)
  {
  	unsigned int tmp;
  
  	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
  	tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
  	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 7);
  	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, tmp|0x2010);
  }
3fb4a508b   Takashi Iwai   ALSA: hda - Turn ...
647
648
649
650
651
652
653
654
655
  /* turn on/off EAPD control (only if available) */
  static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
  {
  	if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
  		return;
  	if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
  		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
  				    on ? 2 : 0);
  }
691f1fccf   Takashi Iwai   ALSA: hda - Refac...
656
657
658
659
  /* turn on/off EAPD controls of the codec */
  static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
  {
  	/* We currently only handle front, HP */
39fa84e94   Takashi Iwai   ALSA: hda - Simpl...
660
661
662
663
664
665
  	static hda_nid_t pins[] = {
  		0x0f, 0x10, 0x14, 0x15, 0
  	};
  	hda_nid_t *p;
  	for (p = pins; *p; p++)
  		set_eapd(codec, *p, on);
691f1fccf   Takashi Iwai   ALSA: hda - Refac...
666
  }
1c716153a   Takashi Iwai   ALSA: hda - Intro...
667
668
669
670
671
672
673
674
  /* generic shutup callback;
   * just turning off EPAD and a little pause for avoiding pop-noise
   */
  static void alc_eapd_shutup(struct hda_codec *codec)
  {
  	alc_auto_setup_eapd(codec, false);
  	msleep(200);
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
675
  /* generic EAPD initialization */
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
676
  static void alc_auto_init_amp(struct hda_codec *codec, int type)
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
677
  {
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
678
  	unsigned int tmp;
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
679

39fa84e94   Takashi Iwai   ALSA: hda - Simpl...
680
  	alc_auto_setup_eapd(codec, true);
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
681
682
  	switch (type) {
  	case ALC_INIT_GPIO1:
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
683
684
  		snd_hda_sequence_write(codec, alc_gpio1_init_verbs);
  		break;
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
685
  	case ALC_INIT_GPIO2:
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
686
687
  		snd_hda_sequence_write(codec, alc_gpio2_init_verbs);
  		break;
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
688
  	case ALC_INIT_GPIO3:
bdd148a30   Kailang Yang   [ALSA] hda-codec ...
689
690
  		snd_hda_sequence_write(codec, alc_gpio3_init_verbs);
  		break;
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
691
  	case ALC_INIT_DEFAULT:
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
  		switch (codec->vendor_id) {
  		case 0x10ec0260:
  			snd_hda_codec_write(codec, 0x1a, 0,
  					    AC_VERB_SET_COEF_INDEX, 7);
  			tmp = snd_hda_codec_read(codec, 0x1a, 0,
  						 AC_VERB_GET_PROC_COEF, 0);
  			snd_hda_codec_write(codec, 0x1a, 0,
  					    AC_VERB_SET_COEF_INDEX, 7);
  			snd_hda_codec_write(codec, 0x1a, 0,
  					    AC_VERB_SET_PROC_COEF,
  					    tmp | 0x2010);
  			break;
  		case 0x10ec0262:
  		case 0x10ec0880:
  		case 0x10ec0882:
  		case 0x10ec0883:
  		case 0x10ec0885:
4a5a4c56b   Takashi Iwai   ALSA: hda - Add m...
709
  		case 0x10ec0887:
20b67dddc   Takashi Iwai   ALSA: hda - Fix S...
710
  		/*case 0x10ec0889:*/ /* this causes an SPDIF problem */
87a8c3702   Jaroslav Kysela   ALSA: hda - Add b...
711
  			alc889_coef_init(codec);
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
712
  			break;
f9423e7a9   Kailang Yang   [ALSA] hda - Fix ...
713
  		case 0x10ec0888:
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
714
  			alc888_coef_init(codec);
f9423e7a9   Kailang Yang   [ALSA] hda - Fix ...
715
  			break;
0aea778ef   Takashi Iwai   ALSA: hda - Remov...
716
  #if 0 /* XXX: This may cause the silent output on speaker on some machines */
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
717
718
719
720
721
722
723
  		case 0x10ec0267:
  		case 0x10ec0268:
  			snd_hda_codec_write(codec, 0x20, 0,
  					    AC_VERB_SET_COEF_INDEX, 7);
  			tmp = snd_hda_codec_read(codec, 0x20, 0,
  						 AC_VERB_GET_PROC_COEF, 0);
  			snd_hda_codec_write(codec, 0x20, 0,
ea1fb29ac   Kailang Yang   ALSA: hda - fix s...
724
  					    AC_VERB_SET_COEF_INDEX, 7);
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
725
726
727
728
  			snd_hda_codec_write(codec, 0x20, 0,
  					    AC_VERB_SET_PROC_COEF,
  					    tmp | 0x3000);
  			break;
0aea778ef   Takashi Iwai   ALSA: hda - Remov...
729
  #endif /* XXX */
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
730
  		}
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
731
732
733
  		break;
  	}
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
734
735
736
  /*
   * Auto-Mute mode mixer enum support
   */
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
737
738
739
  static int alc_automute_mode_info(struct snd_kcontrol *kcontrol,
  				  struct snd_ctl_elem_info *uinfo)
  {
ae8a60a59   Takashi Iwai   ALSA: hda - Add A...
740
741
742
743
744
745
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
  	static const char * const texts2[] = {
  		"Disabled", "Enabled"
  	};
  	static const char * const texts3[] = {
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
746
747
  		"Disabled", "Speaker Only", "Line-Out+Speaker"
  	};
ae8a60a59   Takashi Iwai   ALSA: hda - Add A...
748
  	const char * const *texts;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
749
750
751
  
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  	uinfo->count = 1;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
752
  	if (spec->automute_speaker_possible && spec->automute_lo_possible) {
ae8a60a59   Takashi Iwai   ALSA: hda - Add A...
753
754
755
756
757
758
759
760
  		uinfo->value.enumerated.items = 3;
  		texts = texts3;
  	} else {
  		uinfo->value.enumerated.items = 2;
  		texts = texts2;
  	}
  	if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
  		uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
761
762
763
764
765
766
767
768
769
770
  	strcpy(uinfo->value.enumerated.name,
  	       texts[uinfo->value.enumerated.item]);
  	return 0;
  }
  
  static int alc_automute_mode_get(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol)
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
771
772
773
774
775
  	unsigned int val = 0;
  	if (spec->automute_speaker)
  		val++;
  	if (spec->automute_lo)
  		val++;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
776
777
778
779
780
781
782
783
784
785
786
787
  	ucontrol->value.enumerated.item[0] = val;
  	return 0;
  }
  
  static int alc_automute_mode_put(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol)
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
  
  	switch (ucontrol->value.enumerated.item[0]) {
  	case 0:
42cf0d015   David Henningsson   ALSA: HDA: Refact...
788
  		if (!spec->automute_speaker && !spec->automute_lo)
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
789
  			return 0;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
790
791
  		spec->automute_speaker = 0;
  		spec->automute_lo = 0;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
792
793
  		break;
  	case 1:
42cf0d015   David Henningsson   ALSA: HDA: Refact...
794
795
796
797
798
799
800
801
802
803
804
  		if (spec->automute_speaker_possible) {
  			if (!spec->automute_lo && spec->automute_speaker)
  				return 0;
  			spec->automute_speaker = 1;
  			spec->automute_lo = 0;
  		} else if (spec->automute_lo_possible) {
  			if (spec->automute_lo)
  				return 0;
  			spec->automute_lo = 1;
  		} else
  			return -EINVAL;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
805
806
  		break;
  	case 2:
42cf0d015   David Henningsson   ALSA: HDA: Refact...
807
  		if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
ae8a60a59   Takashi Iwai   ALSA: hda - Add A...
808
  			return -EINVAL;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
809
  		if (spec->automute_speaker && spec->automute_lo)
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
810
  			return 0;
42cf0d015   David Henningsson   ALSA: HDA: Refact...
811
812
  		spec->automute_speaker = 1;
  		spec->automute_lo = 1;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
813
814
815
816
  		break;
  	default:
  		return -EINVAL;
  	}
42cf0d015   David Henningsson   ALSA: HDA: Refact...
817
  	call_update_outputs(codec);
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
818
819
  	return 1;
  }
a9111321f   Takashi Iwai   ALSA: hda - Const...
820
  static const struct snd_kcontrol_new alc_automute_mode_enum = {
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
821
822
823
824
825
826
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "Auto-Mute Mode",
  	.info = alc_automute_mode_info,
  	.get = alc_automute_mode_get,
  	.put = alc_automute_mode_put,
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
827
828
829
830
831
  static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec)
  {
  	snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
  	return snd_array_new(&spec->kctls);
  }
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
  
  static int alc_add_automute_mode_enum(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	struct snd_kcontrol_new *knew;
  
  	knew = alc_kcontrol_new(spec);
  	if (!knew)
  		return -ENOMEM;
  	*knew = alc_automute_mode_enum;
  	knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL);
  	if (!knew->name)
  		return -ENOMEM;
  	return 0;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
847
848
849
850
  /*
   * Check the availability of HP/line-out auto-mute;
   * Set up appropriately if really supported
   */
42cf0d015   David Henningsson   ALSA: HDA: Refact...
851
  static void alc_init_automute(struct hda_codec *codec)
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
852
853
  {
  	struct alc_spec *spec = codec->spec;
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
854
  	struct auto_pin_cfg *cfg = &spec->autocfg;
1daf5f46c   Takashi Iwai   ALSA: hda - More ...
855
  	int present = 0;
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
856
  	int i;
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
857

1daf5f46c   Takashi Iwai   ALSA: hda - More ...
858
859
860
861
862
863
864
865
  	if (cfg->hp_pins[0])
  		present++;
  	if (cfg->line_out_pins[0])
  		present++;
  	if (cfg->speaker_pins[0])
  		present++;
  	if (present < 2) /* need two different output types */
  		return;
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
866

c48a8fb0d   Takashi Iwai   ALSA: hda - Fix d...
867
868
  	if (!cfg->speaker_pins[0] &&
  	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
869
870
871
872
  		memcpy(cfg->speaker_pins, cfg->line_out_pins,
  		       sizeof(cfg->speaker_pins));
  		cfg->speaker_outs = cfg->line_outs;
  	}
c48a8fb0d   Takashi Iwai   ALSA: hda - Fix d...
873
874
  	if (!cfg->hp_pins[0] &&
  	    cfg->line_out_type == AUTO_PIN_HP_OUT) {
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
875
876
877
  		memcpy(cfg->hp_pins, cfg->line_out_pins,
  		       sizeof(cfg->hp_pins));
  		cfg->hp_outs = cfg->line_outs;
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
878
  	}
42cf0d015   David Henningsson   ALSA: HDA: Refact...
879
  	spec->automute_mode = ALC_AUTOMUTE_PIN;
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
880
  	for (i = 0; i < cfg->hp_outs; i++) {
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
881
  		hda_nid_t nid = cfg->hp_pins[i];
06dec2282   Takashi Iwai   ALSA: hda - Use i...
882
  		if (!is_jack_detectable(codec, nid))
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
883
  			continue;
bb35febd1   Takashi Iwai   ALSA: hda - Suppo...
884
885
  		snd_printdd("realtek: Enable HP auto-muting on NID 0x%x
  ",
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
886
  			    nid);
1835a0f9a   Takashi Iwai   ALSA: hda - Cache...
887
  		snd_hda_jack_detect_enable(codec, nid, ALC_HP_EVENT);
42cf0d015   David Henningsson   ALSA: HDA: Refact...
888
889
890
891
892
893
894
895
896
897
898
899
  		spec->detect_hp = 1;
  	}
  
  	if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
  		if (cfg->speaker_outs)
  			for (i = 0; i < cfg->line_outs; i++) {
  				hda_nid_t nid = cfg->line_out_pins[i];
  				if (!is_jack_detectable(codec, nid))
  					continue;
  				snd_printdd("realtek: Enable Line-Out "
  					    "auto-muting on NID 0x%x
  ", nid);
1835a0f9a   Takashi Iwai   ALSA: hda - Cache...
900
901
  				snd_hda_jack_detect_enable(codec, nid,
  							   ALC_FRONT_EVENT);
42cf0d015   David Henningsson   ALSA: HDA: Refact...
902
  				spec->detect_lo = 1;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
903
  		}
42cf0d015   David Henningsson   ALSA: HDA: Refact...
904
  		spec->automute_lo_possible = spec->detect_hp;
ae8a60a59   Takashi Iwai   ALSA: hda - Add A...
905
  	}
42cf0d015   David Henningsson   ALSA: HDA: Refact...
906
907
908
909
910
911
912
  	spec->automute_speaker_possible = cfg->speaker_outs &&
  		(spec->detect_hp || spec->detect_lo);
  
  	spec->automute_lo = spec->automute_lo_possible;
  	spec->automute_speaker = spec->automute_speaker_possible;
  
  	if (spec->automute_speaker_possible || spec->automute_lo_possible) {
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
913
914
  		/* create a control for automute mode */
  		alc_add_automute_mode_enum(codec);
ae8a60a59   Takashi Iwai   ALSA: hda - Add A...
915
  		spec->unsol_event = alc_sku_unsol_event;
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
916
  	}
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
917
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
918
  /* return the position of NID in the list, or -1 if not found */
21268961d   Takashi Iwai   ALSA: hda - More ...
919
920
921
922
923
924
925
926
  static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
  {
  	int i;
  	for (i = 0; i < nums; i++)
  		if (list[i] == nid)
  			return i;
  	return -1;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
  /* check whether dynamic ADC-switching is available */
  static bool alc_check_dyn_adc_switch(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	struct hda_input_mux *imux = &spec->private_imux[0];
  	int i, n, idx;
  	hda_nid_t cap, pin;
  
  	if (imux != spec->input_mux) /* no dynamic imux? */
  		return false;
  
  	for (n = 0; n < spec->num_adc_nids; n++) {
  		cap = spec->private_capsrc_nids[n];
  		for (i = 0; i < imux->num_items; i++) {
  			pin = spec->imux_pins[i];
  			if (!pin)
  				return false;
  			if (get_connection_index(codec, cap, pin) < 0)
  				break;
  		}
  		if (i >= imux->num_items)
268ff6fbe   Takashi Iwai   ALSA: hda - Fix a...
948
  			return true; /* no ADC-switch is needed */
1d045db96   Takashi Iwai   ALSA: hda - Split...
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
  	}
  
  	for (i = 0; i < imux->num_items; i++) {
  		pin = spec->imux_pins[i];
  		for (n = 0; n < spec->num_adc_nids; n++) {
  			cap = spec->private_capsrc_nids[n];
  			idx = get_connection_index(codec, cap, pin);
  			if (idx >= 0) {
  				imux->items[i].index = idx;
  				spec->dyn_adc_idx[i] = n;
  				break;
  			}
  		}
  	}
  
  	snd_printdd("realtek: enabling ADC switching
  ");
  	spec->dyn_adc_switch = 1;
  	return true;
  }
21268961d   Takashi Iwai   ALSA: hda - More ...
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
  
  /* rebuild imux for matching with the given auto-mic pins (if not yet) */
  static bool alc_rebuild_imux_for_auto_mic(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	struct hda_input_mux *imux;
  	static char * const texts[3] = {
  		"Mic", "Internal Mic", "Dock Mic"
  	};
  	int i;
  
  	if (!spec->auto_mic)
  		return false;
  	imux = &spec->private_imux[0];
  	if (spec->input_mux == imux)
  		return true;
  	spec->imux_pins[0] = spec->ext_mic_pin;
  	spec->imux_pins[1] = spec->int_mic_pin;
  	spec->imux_pins[2] = spec->dock_mic_pin;
  	for (i = 0; i < 3; i++) {
  		strcpy(imux->items[i].label, texts[i]);
6759dc323   Takashi Iwai   ALSA: hda/realtek...
990
991
992
993
  		if (spec->imux_pins[i]) {
  			hda_nid_t pin = spec->imux_pins[i];
  			int c;
  			for (c = 0; c < spec->num_adc_nids; c++) {
61071594f   Takashi Iwai   ALSA: hda/realtek...
994
  				hda_nid_t cap = get_capsrc(spec, c);
6759dc323   Takashi Iwai   ALSA: hda/realtek...
995
996
997
998
999
1000
  				int idx = get_connection_index(codec, cap, pin);
  				if (idx >= 0) {
  					imux->items[i].index = idx;
  					break;
  				}
  			}
21268961d   Takashi Iwai   ALSA: hda - More ...
1001
  			imux->num_items = i + 1;
6759dc323   Takashi Iwai   ALSA: hda/realtek...
1002
  		}
21268961d   Takashi Iwai   ALSA: hda - More ...
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
  	}
  	spec->num_mux_defs = 1;
  	spec->input_mux = imux;
  	return true;
  }
  
  /* check whether all auto-mic pins are valid; setup indices if OK */
  static bool alc_auto_mic_check_imux(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	const struct hda_input_mux *imux;
  
  	if (!spec->auto_mic)
  		return false;
  	if (spec->auto_mic_valid_imux)
  		return true; /* already checked */
  
  	/* fill up imux indices */
  	if (!alc_check_dyn_adc_switch(codec)) {
  		spec->auto_mic = 0;
  		return false;
  	}
  
  	imux = spec->input_mux;
  	spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin,
  					spec->imux_pins, imux->num_items);
  	spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin,
  					spec->imux_pins, imux->num_items);
  	spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin,
  					spec->imux_pins, imux->num_items);
  	if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) {
  		spec->auto_mic = 0;
  		return false; /* no corresponding imux */
  	}
1835a0f9a   Takashi Iwai   ALSA: hda - Cache...
1037
  	snd_hda_jack_detect_enable(codec, spec->ext_mic_pin, ALC_MIC_EVENT);
21268961d   Takashi Iwai   ALSA: hda - More ...
1038
  	if (spec->dock_mic_pin)
1835a0f9a   Takashi Iwai   ALSA: hda - Cache...
1039
1040
  		snd_hda_jack_detect_enable(codec, spec->dock_mic_pin,
  					   ALC_MIC_EVENT);
21268961d   Takashi Iwai   ALSA: hda - More ...
1041
1042
1043
1044
1045
  
  	spec->auto_mic_valid_imux = 1;
  	spec->auto_mic = 1;
  	return true;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
1046
1047
1048
1049
  /*
   * Check the availability of auto-mic switch;
   * Set up if really supported
   */
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1050
1051
1052
1053
  static void alc_init_auto_mic(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	struct auto_pin_cfg *cfg = &spec->autocfg;
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
1054
  	hda_nid_t fixed, ext, dock;
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1055
  	int i;
24de183ed   Takashi Iwai   ALSA: hda/realtek...
1056
1057
  	if (spec->shared_mic_hp)
  		return; /* no auto-mic for the shared I/O */
21268961d   Takashi Iwai   ALSA: hda - More ...
1058
  	spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1;
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
1059
  	fixed = ext = dock = 0;
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
1060
1061
  	for (i = 0; i < cfg->num_inputs; i++) {
  		hda_nid_t nid = cfg->inputs[i].pin;
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1062
  		unsigned int defcfg;
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1063
  		defcfg = snd_hda_codec_get_pincfg(codec, nid);
99ae28bea   Takashi Iwai   ALSA: hda - Make ...
1064
1065
  		switch (snd_hda_get_input_pin_attr(defcfg)) {
  		case INPUT_PIN_ATTR_INT:
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1066
1067
  			if (fixed)
  				return; /* already occupied */
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
1068
1069
  			if (cfg->inputs[i].type != AUTO_PIN_MIC)
  				return; /* invalid type */
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1070
1071
  			fixed = nid;
  			break;
99ae28bea   Takashi Iwai   ALSA: hda - Make ...
1072
1073
  		case INPUT_PIN_ATTR_UNUSED:
  			return; /* invalid entry */
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
1074
1075
1076
1077
1078
1079
1080
  		case INPUT_PIN_ATTR_DOCK:
  			if (dock)
  				return; /* already occupied */
  			if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
  				return; /* invalid type */
  			dock = nid;
  			break;
99ae28bea   Takashi Iwai   ALSA: hda - Make ...
1081
  		default:
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1082
1083
  			if (ext)
  				return; /* already occupied */
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
1084
1085
  			if (cfg->inputs[i].type != AUTO_PIN_MIC)
  				return; /* invalid type */
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1086
1087
  			ext = nid;
  			break;
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1088
1089
  		}
  	}
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
1090
1091
1092
1093
  	if (!ext && dock) {
  		ext = dock;
  		dock = 0;
  	}
eaa9b3a74   Takashi Iwai   ALSA: hda - Fix c...
1094
1095
  	if (!ext || !fixed)
  		return;
e35d9d6a1   Takashi Iwai   ALSA: hda - Check...
1096
  	if (!is_jack_detectable(codec, ext))
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1097
  		return; /* no unsol support */
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
1098
1099
  	if (dock && !is_jack_detectable(codec, dock))
  		return; /* no unsol support */
21268961d   Takashi Iwai   ALSA: hda - More ...
1100
1101
1102
1103
1104
1105
1106
1107
1108
  
  	/* check imux indices */
  	spec->ext_mic_pin = ext;
  	spec->int_mic_pin = fixed;
  	spec->dock_mic_pin = dock;
  
  	spec->auto_mic = 1;
  	if (!alc_auto_mic_check_imux(codec))
  		return;
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
1109
1110
1111
  	snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x
  ",
  		    ext, fixed, dock);
6c8194922   Takashi Iwai   ALSA: hda - Add a...
1112
1113
  	spec->unsol_event = alc_sku_unsol_event;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
1114
1115
1116
  /* check the availabilities of auto-mute and auto-mic switches */
  static void alc_auto_check_switches(struct hda_codec *codec)
  {
42cf0d015   David Henningsson   ALSA: HDA: Refact...
1117
  	alc_init_automute(codec);
1d045db96   Takashi Iwai   ALSA: hda - Split...
1118
1119
1120
1121
1122
1123
  	alc_init_auto_mic(codec);
  }
  
  /*
   * Realtek SSID verification
   */
906229174   David Henningsson   ALSA: HDA: Enable...
1124
1125
1126
1127
  /* Could be any non-zero and even value. When used as fixup, tells
   * the driver to ignore any present sku defines.
   */
  #define ALC_FIXUP_SKU_IGNORE (2)
da00c2449   Kailang Yang   ALSA: hda - Add p...
1128
1129
1130
  static int alc_auto_parse_customize_define(struct hda_codec *codec)
  {
  	unsigned int ass, tmp, i;
7fb562232   Takashi Iwai   ALSA: hda - Fix u...
1131
  	unsigned nid = 0;
da00c2449   Kailang Yang   ALSA: hda - Add p...
1132
  	struct alc_spec *spec = codec->spec;
b6cbe517b   Takashi Iwai   ALSA: hda - Assum...
1133
  	spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
906229174   David Henningsson   ALSA: HDA: Enable...
1134
1135
1136
1137
1138
1139
  	if (spec->cdefine.fixup) {
  		ass = spec->cdefine.sku_cfg;
  		if (ass == ALC_FIXUP_SKU_IGNORE)
  			return -1;
  		goto do_sku;
  	}
da00c2449   Kailang Yang   ALSA: hda - Add p...
1140
  	ass = codec->subsystem_id & 0xffff;
b6cbe517b   Takashi Iwai   ALSA: hda - Assum...
1141
  	if (ass != codec->bus->pci->subsystem_device && (ass & 1))
da00c2449   Kailang Yang   ALSA: hda - Add p...
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
  		goto do_sku;
  
  	nid = 0x1d;
  	if (codec->vendor_id == 0x10ec0260)
  		nid = 0x17;
  	ass = snd_hda_codec_get_pincfg(codec, nid);
  
  	if (!(ass & 1)) {
  		printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x
  ",
  		       codec->chip_name, ass);
  		return -1;
  	}
  
  	/* check sum */
  	tmp = 0;
  	for (i = 1; i < 16; i++) {
  		if ((ass >> i) & 1)
  			tmp++;
  	}
  	if (((ass >> 16) & 0xf) != tmp)
  		return -1;
  
  	spec->cdefine.port_connectivity = ass >> 30;
  	spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
  	spec->cdefine.check_sum = (ass >> 16) & 0xf;
  	spec->cdefine.customization = ass >> 8;
  do_sku:
  	spec->cdefine.sku_cfg = ass;
  	spec->cdefine.external_amp = (ass & 0x38) >> 3;
  	spec->cdefine.platform_type = (ass & 0x4) >> 2;
  	spec->cdefine.swap = (ass & 0x2) >> 1;
  	spec->cdefine.override = ass & 0x1;
  
  	snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x
  ",
  		   nid, spec->cdefine.sku_cfg);
  	snd_printd("SKU: port_connectivity=0x%x
  ",
  		   spec->cdefine.port_connectivity);
  	snd_printd("SKU: enable_pcbeep=0x%x
  ", spec->cdefine.enable_pcbeep);
  	snd_printd("SKU: check_sum=0x%08x
  ", spec->cdefine.check_sum);
  	snd_printd("SKU: customization=0x%08x
  ", spec->cdefine.customization);
  	snd_printd("SKU: external_amp=0x%x
  ", spec->cdefine.external_amp);
  	snd_printd("SKU: platform_type=0x%x
  ", spec->cdefine.platform_type);
  	snd_printd("SKU: swap=0x%x
  ", spec->cdefine.swap);
  	snd_printd("SKU: override=0x%x
  ", spec->cdefine.override);
  
  	return 0;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
1199
  /* return true if the given NID is found in the list */
3af9ee6b8   Takashi Iwai   ALSA: hda - Check...
1200
1201
  static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
  {
21268961d   Takashi Iwai   ALSA: hda - More ...
1202
  	return find_idx_in_nid_list(nid, list, nums) >= 0;
3af9ee6b8   Takashi Iwai   ALSA: hda - Check...
1203
  }
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
  /* check subsystem ID and set up device-specific initialization;
   * return 1 if initialized, 0 if invalid SSID
   */
  /* 32-bit subsystem ID for BIOS loading in HD Audio codec.
   *	31 ~ 16 :	Manufacture ID
   *	15 ~ 8	:	SKU ID
   *	7  ~ 0	:	Assembly ID
   *	port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
   */
  static int alc_subsystem_id(struct hda_codec *codec,
  			    hda_nid_t porta, hda_nid_t porte,
6227cdced   Kailang Yang   ALSA: hda - Add A...
1215
  			    hda_nid_t portd, hda_nid_t porti)
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1216
1217
1218
1219
  {
  	unsigned int ass, tmp, i;
  	unsigned nid;
  	struct alc_spec *spec = codec->spec;
906229174   David Henningsson   ALSA: HDA: Enable...
1220
1221
1222
1223
1224
1225
  	if (spec->cdefine.fixup) {
  		ass = spec->cdefine.sku_cfg;
  		if (ass == ALC_FIXUP_SKU_IGNORE)
  			return 0;
  		goto do_sku;
  	}
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1226
1227
1228
1229
1230
1231
  	ass = codec->subsystem_id & 0xffff;
  	if ((ass != codec->bus->pci->subsystem_device) && (ass & 1))
  		goto do_sku;
  
  	/* invalid SSID, check the special NID pin defcfg instead */
  	/*
def319f9e   Sasha Alexandr   ALSA: HDA - Corre...
1232
  	 * 31~30	: port connectivity
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
  	 * 29~21	: reserve
  	 * 20		: PCBEEP input
  	 * 19~16	: Check sum (15:1)
  	 * 15~1		: Custom
  	 * 0		: override
  	*/
  	nid = 0x1d;
  	if (codec->vendor_id == 0x10ec0260)
  		nid = 0x17;
  	ass = snd_hda_codec_get_pincfg(codec, nid);
  	snd_printd("realtek: No valid SSID, "
  		   "checking pincfg 0x%08x for NID 0x%x
  ",
cb6605c1e   Takashi Iwai   ALSA: hda - Fix a...
1246
  		   ass, nid);
6227cdced   Kailang Yang   ALSA: hda - Add A...
1247
  	if (!(ass & 1))
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
  		return 0;
  	if ((ass >> 30) != 1)	/* no physical connection */
  		return 0;
  
  	/* check sum */
  	tmp = 0;
  	for (i = 1; i < 16; i++) {
  		if ((ass >> i) & 1)
  			tmp++;
  	}
  	if (((ass >> 16) & 0xf) != tmp)
  		return 0;
  do_sku:
  	snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x
  ",
  		   ass & 0xffff, codec->vendor_id);
  	/*
  	 * 0 : override
  	 * 1 :	Swap Jack
  	 * 2 : 0 --> Desktop, 1 --> Laptop
  	 * 3~5 : External Amplifier control
  	 * 7~6 : Reserved
  	*/
  	tmp = (ass & 0x38) >> 3;	/* external Amp control */
  	switch (tmp) {
  	case 1:
  		spec->init_amp = ALC_INIT_GPIO1;
  		break;
  	case 3:
  		spec->init_amp = ALC_INIT_GPIO2;
  		break;
  	case 7:
  		spec->init_amp = ALC_INIT_GPIO3;
  		break;
  	case 5:
5a8cfb4e8   Takashi Iwai   ALSA: hda - Use A...
1283
  	default:
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1284
  		spec->init_amp = ALC_INIT_DEFAULT;
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
1285
1286
  		break;
  	}
ea1fb29ac   Kailang Yang   ALSA: hda - fix s...
1287

8c427226e   Kailang Yang   [ALSA] hda-codec ...
1288
  	/* is laptop or Desktop and enable the function "Mute internal speaker
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
1289
1290
  	 * when the external headphone out jack is plugged"
  	 */
8c427226e   Kailang Yang   [ALSA] hda-codec ...
1291
  	if (!(ass & 0x8000))
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1292
  		return 1;
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
1293
1294
1295
1296
1297
1298
1299
  	/*
  	 * 10~8 : Jack location
  	 * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
  	 * 14~13: Resvered
  	 * 15   : 1 --> enable the function "Mute internal speaker
  	 *	        when the external headphone out jack is plugged"
  	 */
5fe6e0151   Takashi Iwai   ALSA: hda/realtek...
1300
1301
1302
  	if (!spec->autocfg.hp_pins[0] &&
  	    !(spec->autocfg.line_out_pins[0] &&
  	      spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) {
01d4825df   Takashi Iwai   ALSA: hda - Don't...
1303
  		hda_nid_t nid;
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
1304
1305
  		tmp = (ass >> 11) & 0x3;	/* HP to chassis */
  		if (tmp == 0)
01d4825df   Takashi Iwai   ALSA: hda - Don't...
1306
  			nid = porta;
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
1307
  		else if (tmp == 1)
01d4825df   Takashi Iwai   ALSA: hda - Don't...
1308
  			nid = porte;
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
1309
  		else if (tmp == 2)
01d4825df   Takashi Iwai   ALSA: hda - Don't...
1310
  			nid = portd;
6227cdced   Kailang Yang   ALSA: hda - Add A...
1311
1312
  		else if (tmp == 3)
  			nid = porti;
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
1313
  		else
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1314
  			return 1;
3af9ee6b8   Takashi Iwai   ALSA: hda - Check...
1315
1316
1317
  		if (found_in_nid_list(nid, spec->autocfg.line_out_pins,
  				      spec->autocfg.line_outs))
  			return 1;
01d4825df   Takashi Iwai   ALSA: hda - Don't...
1318
  		spec->autocfg.hp_pins[0] = nid;
c9b58006b   Kailang Yang   [ALSA] hda-codec ...
1319
  	}
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1320
1321
  	return 1;
  }
ea1fb29ac   Kailang Yang   ALSA: hda - fix s...
1322

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
1323
1324
1325
  /* Check the validity of ALC subsystem-id
   * ports contains an array of 4 pin NIDs for port-A, E, D and I */
  static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1326
  {
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
1327
  	if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) {
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1328
1329
1330
1331
1332
  		struct alc_spec *spec = codec->spec;
  		snd_printd("realtek: "
  			   "Enable default setup for auto mode as fallback
  ");
  		spec->init_amp = ALC_INIT_DEFAULT;
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
1333
  	}
21268961d   Takashi Iwai   ALSA: hda - More ...
1334
  }
1a1455de1   Takashi Iwai   ALSA: hda - Add s...
1335

41e41f1f3   Takashi Iwai   [ALSA] Fix the an...
1336
  /*
f8f25ba35   Takashi Iwai   ALSA: hda - Add a...
1337
   * Fix-up pin default configurations and add default verbs
f95474ec0   Takashi Iwai   [ALSA] hda-codec ...
1338
1339
1340
1341
1342
1343
   */
  
  struct alc_pincfg {
  	hda_nid_t nid;
  	u32 val;
  };
e1eb5f100   Todd Broch   ALSA: hda: Add mo...
1344
1345
1346
1347
  struct alc_model_fixup {
  	const int id;
  	const char *name;
  };
f8f25ba35   Takashi Iwai   ALSA: hda - Add a...
1348
  struct alc_fixup {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1349
  	int type;
361fe6e90   Takashi Iwai   ALSA: hda - Rearr...
1350
1351
  	bool chained;
  	int chain_id;
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1352
1353
1354
1355
1356
1357
1358
1359
  	union {
  		unsigned int sku;
  		const struct alc_pincfg *pins;
  		const struct hda_verb *verbs;
  		void (*func)(struct hda_codec *codec,
  			     const struct alc_fixup *fix,
  			     int action);
  	} v;
f8f25ba35   Takashi Iwai   ALSA: hda - Add a...
1360
  };
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
  enum {
  	ALC_FIXUP_INVALID,
  	ALC_FIXUP_SKU,
  	ALC_FIXUP_PINS,
  	ALC_FIXUP_VERBS,
  	ALC_FIXUP_FUNC,
  };
  
  enum {
  	ALC_FIXUP_ACT_PRE_PROBE,
  	ALC_FIXUP_ACT_PROBE,
587011202   Takashi Iwai   ALSA: hda - Add f...
1372
  	ALC_FIXUP_ACT_INIT,
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1373
1374
1375
  };
  
  static void alc_apply_fixup(struct hda_codec *codec, int action)
f95474ec0   Takashi Iwai   [ALSA] hda-codec ...
1376
  {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1377
1378
  	struct alc_spec *spec = codec->spec;
  	int id = spec->fixup_id;
aa1d0c526   Takashi Iwai   ALSA: hda - Fix "...
1379
  #ifdef CONFIG_SND_DEBUG_VERBOSE
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1380
  	const char *modelname = spec->fixup_name;
aa1d0c526   Takashi Iwai   ALSA: hda - Fix "...
1381
  #endif
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1382
  	int depth = 0;
f95474ec0   Takashi Iwai   [ALSA] hda-codec ...
1383

b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
  	if (!spec->fixup_list)
  		return;
  
  	while (id >= 0) {
  		const struct alc_fixup *fix = spec->fixup_list + id;
  		const struct alc_pincfg *cfg;
  
  		switch (fix->type) {
  		case ALC_FIXUP_SKU:
  			if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku)
e53de8f00   Jesper Juhl   ALSA: hda/realtek...
1394
  				break;
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
  			snd_printdd(KERN_INFO "hda_codec: %s: "
  				    "Apply sku override for %s
  ",
  				    codec->chip_name, modelname);
  			spec->cdefine.sku_cfg = fix->v.sku;
  			spec->cdefine.fixup = 1;
  			break;
  		case ALC_FIXUP_PINS:
  			cfg = fix->v.pins;
  			if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg)
  				break;
  			snd_printdd(KERN_INFO "hda_codec: %s: "
  				    "Apply pincfg for %s
  ",
  				    codec->chip_name, modelname);
  			for (; cfg->nid; cfg++)
  				snd_hda_codec_set_pincfg(codec, cfg->nid,
  							 cfg->val);
  			break;
  		case ALC_FIXUP_VERBS:
  			if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs)
  				break;
  			snd_printdd(KERN_INFO "hda_codec: %s: "
  				    "Apply fix-verbs for %s
  ",
  				    codec->chip_name, modelname);
  			add_verb(codec->spec, fix->v.verbs);
  			break;
  		case ALC_FIXUP_FUNC:
  			if (!fix->v.func)
  				break;
  			snd_printdd(KERN_INFO "hda_codec: %s: "
  				    "Apply fix-func for %s
  ",
  				    codec->chip_name, modelname);
  			fix->v.func(codec, fix, action);
  			break;
  		default:
  			snd_printk(KERN_ERR "hda_codec: %s: "
  				   "Invalid fixup type %d
  ",
  				   codec->chip_name, fix->type);
  			break;
  		}
24af2b1cc   Takashi Iwai   ALSA: hda - Fix R...
1439
  		if (!fix->chained)
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1440
1441
1442
  			break;
  		if (++depth > 10)
  			break;
24af2b1cc   Takashi Iwai   ALSA: hda - Fix R...
1443
  		id = fix->chain_id;
9d57883f0   Takashi Iwai   ALSA: hda - Add a...
1444
  	}
f95474ec0   Takashi Iwai   [ALSA] hda-codec ...
1445
  }
e1eb5f100   Todd Broch   ALSA: hda: Add mo...
1446
  static void alc_pick_fixup(struct hda_codec *codec,
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1447
1448
1449
  			   const struct alc_model_fixup *models,
  			   const struct snd_pci_quirk *quirk,
  			   const struct alc_fixup *fixlist)
e1eb5f100   Todd Broch   ALSA: hda: Add mo...
1450
  {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1451
  	struct alc_spec *spec = codec->spec;
596830ee1   Takashi Iwai   ALSA: hda/realtek...
1452
  	const struct snd_pci_quirk *q;
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1453
1454
  	int id = -1;
  	const char *name = NULL;
e1eb5f100   Todd Broch   ALSA: hda: Add mo...
1455

e1eb5f100   Todd Broch   ALSA: hda: Add mo...
1456
1457
1458
  	if (codec->modelname && models) {
  		while (models->name) {
  			if (!strcmp(codec->modelname, models->name)) {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1459
1460
  				id = models->id;
  				name = models->name;
e1eb5f100   Todd Broch   ALSA: hda: Add mo...
1461
1462
1463
1464
  				break;
  			}
  			models++;
  		}
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1465
1466
  	}
  	if (id < 0) {
596830ee1   Takashi Iwai   ALSA: hda/realtek...
1467
1468
1469
  		q = snd_pci_quirk_lookup(codec->bus->pci, quirk);
  		if (q) {
  			id = q->value;
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1470
  #ifdef CONFIG_SND_DEBUG_VERBOSE
596830ee1   Takashi Iwai   ALSA: hda/realtek...
1471
  			name = q->name;
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1472
1473
1474
  #endif
  		}
  	}
596830ee1   Takashi Iwai   ALSA: hda/realtek...
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
  	if (id < 0) {
  		for (q = quirk; q->subvendor; q++) {
  			unsigned int vendorid =
  				q->subdevice | (q->subvendor << 16);
  			if (vendorid == codec->subsystem_id) {
  				id = q->value;
  #ifdef CONFIG_SND_DEBUG_VERBOSE
  				name = q->name;
  #endif
  				break;
  			}
  		}
  	}
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
1488
1489
1490
1491
1492
  
  	spec->fixup_id = id;
  	if (id >= 0) {
  		spec->fixup_list = fixlist;
  		spec->fixup_name = name;
e1eb5f100   Todd Broch   ALSA: hda: Add mo...
1493
  	}
f95474ec0   Takashi Iwai   [ALSA] hda-codec ...
1494
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
1495
1496
1497
  /*
   * COEF access helper functions
   */
274693f37   Kailang Yang   ALSA: hda - Add A...
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
  static int alc_read_coef_idx(struct hda_codec *codec,
  			unsigned int coef_idx)
  {
  	unsigned int val;
  	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
  		    		coef_idx);
  	val = snd_hda_codec_read(codec, 0x20, 0,
  			 	AC_VERB_GET_PROC_COEF, 0);
  	return val;
  }
977ddd6b2   Kailang Yang   ALSA: hda - Set u...
1508
1509
1510
1511
1512
1513
1514
1515
  static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx,
  							unsigned int coef_val)
  {
  	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX,
  			    coef_idx);
  	snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF,
  			    coef_val);
  }
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
1516
1517
1518
1519
1520
1521
1522
1523
  /* a special bypass for COEF 0; read the cached value at the second time */
  static unsigned int alc_get_coef0(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	if (!spec->coef0)
  		spec->coef0 = alc_read_coef_idx(codec, 0);
  	return spec->coef0;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
1524
1525
1526
  /*
   * Digital I/O handling
   */
757899ace   Takashi Iwai   ALSA: hda - Share...
1527
1528
1529
1530
1531
  /* set right pin controls for digital I/O */
  static void alc_auto_init_digital(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	int i;
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
1532
  	hda_nid_t pin, dac;
757899ace   Takashi Iwai   ALSA: hda - Share...
1533
1534
1535
  
  	for (i = 0; i < spec->autocfg.dig_outs; i++) {
  		pin = spec->autocfg.dig_out_pins[i];
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
  		if (!pin)
  			continue;
  		snd_hda_codec_write(codec, pin, 0,
  				    AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
  		if (!i)
  			dac = spec->multiout.dig_out_nid;
  		else
  			dac = spec->slave_dig_outs[i - 1];
  		if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
  			continue;
  		snd_hda_codec_write(codec, dac, 0,
  				    AC_VERB_SET_AMP_GAIN_MUTE,
  				    AMP_OUT_UNMUTE);
757899ace   Takashi Iwai   ALSA: hda - Share...
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
  	}
  	pin = spec->autocfg.dig_in_pin;
  	if (pin)
  		snd_hda_codec_write(codec, pin, 0,
  				    AC_VERB_SET_PIN_WIDGET_CONTROL,
  				    PIN_IN);
  }
  
  /* parse digital I/Os and set up NIDs in BIOS auto-parse mode */
  static void alc_auto_parse_digital(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
51e4152a9   Takashi Iwai   ALSA: hda/realtek...
1561
  	int i, err, nums;
757899ace   Takashi Iwai   ALSA: hda - Share...
1562
1563
1564
  	hda_nid_t dig_nid;
  
  	/* support multiple SPDIFs; the secondary is set up as a slave */
51e4152a9   Takashi Iwai   ALSA: hda/realtek...
1565
  	nums = 0;
757899ace   Takashi Iwai   ALSA: hda - Share...
1566
  	for (i = 0; i < spec->autocfg.dig_outs; i++) {
a926757f0   Takashi Iwai   ALSA: hda - Fix w...
1567
  		hda_nid_t conn[4];
757899ace   Takashi Iwai   ALSA: hda - Share...
1568
1569
  		err = snd_hda_get_connections(codec,
  					      spec->autocfg.dig_out_pins[i],
a926757f0   Takashi Iwai   ALSA: hda - Fix w...
1570
  					      conn, ARRAY_SIZE(conn));
51e4152a9   Takashi Iwai   ALSA: hda/realtek...
1571
  		if (err <= 0)
757899ace   Takashi Iwai   ALSA: hda - Share...
1572
  			continue;
a926757f0   Takashi Iwai   ALSA: hda - Fix w...
1573
  		dig_nid = conn[0]; /* assume the first element is audio-out */
51e4152a9   Takashi Iwai   ALSA: hda/realtek...
1574
  		if (!nums) {
757899ace   Takashi Iwai   ALSA: hda - Share...
1575
1576
1577
1578
  			spec->multiout.dig_out_nid = dig_nid;
  			spec->dig_out_type = spec->autocfg.dig_out_type[0];
  		} else {
  			spec->multiout.slave_dig_outs = spec->slave_dig_outs;
51e4152a9   Takashi Iwai   ALSA: hda/realtek...
1579
  			if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1)
757899ace   Takashi Iwai   ALSA: hda - Share...
1580
  				break;
51e4152a9   Takashi Iwai   ALSA: hda/realtek...
1581
  			spec->slave_dig_outs[nums - 1] = dig_nid;
757899ace   Takashi Iwai   ALSA: hda - Share...
1582
  		}
51e4152a9   Takashi Iwai   ALSA: hda/realtek...
1583
  		nums++;
757899ace   Takashi Iwai   ALSA: hda - Share...
1584
1585
1586
  	}
  
  	if (spec->autocfg.dig_in_pin) {
01fdf1801   Takashi Iwai   ALSA: hda - Fix a...
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
  		dig_nid = codec->start_nid;
  		for (i = 0; i < codec->num_nodes; i++, dig_nid++) {
  			unsigned int wcaps = get_wcaps(codec, dig_nid);
  			if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
  				continue;
  			if (!(wcaps & AC_WCAP_DIGITAL))
  				continue;
  			if (!(wcaps & AC_WCAP_CONN_LIST))
  				continue;
  			err = get_connection_index(codec, dig_nid,
  						   spec->autocfg.dig_in_pin);
  			if (err >= 0) {
  				spec->dig_in_nid = dig_nid;
  				break;
  			}
  		}
757899ace   Takashi Iwai   ALSA: hda - Share...
1603
1604
  	}
  }
f95474ec0   Takashi Iwai   [ALSA] hda-codec ...
1605
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
1606
   * capture mixer elements
ef8ef5fb1   Vincent Petry   ALSA: hda: Added ...
1607
   */
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1608
1609
1610
1611
1612
  static int alc_cap_vol_info(struct snd_kcontrol *kcontrol,
  			    struct snd_ctl_elem_info *uinfo)
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
1613
  	unsigned long val;
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1614
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1615

5a9e02e94   Wu Fengguang   ALSA: hda - creat...
1616
  	mutex_lock(&codec->control_mutex);
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
1617
1618
1619
1620
1621
  	if (spec->vol_in_capsrc)
  		val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
  	else
  		val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
  	kcontrol->private_value = val;
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1622
  	err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
5a9e02e94   Wu Fengguang   ALSA: hda - creat...
1623
  	mutex_unlock(&codec->control_mutex);
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1624
1625
1626
1627
1628
1629
1630
1631
  	return err;
  }
  
  static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
  			   unsigned int size, unsigned int __user *tlv)
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
1632
  	unsigned long val;
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1633
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1634

5a9e02e94   Wu Fengguang   ALSA: hda - creat...
1635
  	mutex_lock(&codec->control_mutex);
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
1636
1637
1638
1639
1640
  	if (spec->vol_in_capsrc)
  		val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT);
  	else
  		val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT);
  	kcontrol->private_value = val;
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1641
  	err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
5a9e02e94   Wu Fengguang   ALSA: hda - creat...
1642
  	mutex_unlock(&codec->control_mutex);
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1643
1644
1645
1646
1647
1648
1649
1650
  	return err;
  }
  
  typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol,
  			     struct snd_ctl_elem_value *ucontrol);
  
  static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_value *ucontrol,
9c7a083d9   Takashi Iwai   ALSA: hda - Chang...
1651
  				 getput_call_t func, bool check_adc_switch)
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1652
1653
1654
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
21268961d   Takashi Iwai   ALSA: hda - More ...
1655
  	int i, err = 0;
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1656

5a9e02e94   Wu Fengguang   ALSA: hda - creat...
1657
  	mutex_lock(&codec->control_mutex);
21268961d   Takashi Iwai   ALSA: hda - More ...
1658
  	if (check_adc_switch && spec->dyn_adc_switch) {
9c7a083d9   Takashi Iwai   ALSA: hda - Chang...
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
  		for (i = 0; i < spec->num_adc_nids; i++) {
  			kcontrol->private_value =
  				HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
  						    3, 0, HDA_INPUT);
  			err = func(kcontrol, ucontrol);
  			if (err < 0)
  				goto error;
  		}
  	} else {
  		i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
1669
1670
1671
1672
1673
1674
  		if (spec->vol_in_capsrc)
  			kcontrol->private_value =
  				HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i],
  						    3, 0, HDA_OUTPUT);
  		else
  			kcontrol->private_value =
21268961d   Takashi Iwai   ALSA: hda - More ...
1675
1676
  				HDA_COMPOSE_AMP_VAL(spec->adc_nids[i],
  						    3, 0, HDA_INPUT);
9c7a083d9   Takashi Iwai   ALSA: hda - Chang...
1677
1678
1679
  		err = func(kcontrol, ucontrol);
  	}
   error:
5a9e02e94   Wu Fengguang   ALSA: hda - creat...
1680
  	mutex_unlock(&codec->control_mutex);
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1681
1682
1683
1684
1685
1686
1687
  	return err;
  }
  
  static int alc_cap_vol_get(struct snd_kcontrol *kcontrol,
  			   struct snd_ctl_elem_value *ucontrol)
  {
  	return alc_cap_getput_caller(kcontrol, ucontrol,
9c7a083d9   Takashi Iwai   ALSA: hda - Chang...
1688
  				     snd_hda_mixer_amp_volume_get, false);
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1689
1690
1691
1692
1693
1694
  }
  
  static int alc_cap_vol_put(struct snd_kcontrol *kcontrol,
  			   struct snd_ctl_elem_value *ucontrol)
  {
  	return alc_cap_getput_caller(kcontrol, ucontrol,
9c7a083d9   Takashi Iwai   ALSA: hda - Chang...
1695
  				     snd_hda_mixer_amp_volume_put, true);
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1696
1697
1698
1699
1700
1701
1702
1703
1704
  }
  
  /* capture mixer elements */
  #define alc_cap_sw_info		snd_ctl_boolean_stereo_info
  
  static int alc_cap_sw_get(struct snd_kcontrol *kcontrol,
  			  struct snd_ctl_elem_value *ucontrol)
  {
  	return alc_cap_getput_caller(kcontrol, ucontrol,
9c7a083d9   Takashi Iwai   ALSA: hda - Chang...
1705
  				     snd_hda_mixer_amp_switch_get, false);
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1706
1707
1708
1709
1710
1711
  }
  
  static int alc_cap_sw_put(struct snd_kcontrol *kcontrol,
  			  struct snd_ctl_elem_value *ucontrol)
  {
  	return alc_cap_getput_caller(kcontrol, ucontrol,
9c7a083d9   Takashi Iwai   ALSA: hda - Chang...
1712
  				     snd_hda_mixer_amp_switch_put, true);
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1713
  }
a23b688f4   Takashi Iwai   ALSA: hda - Don't...
1714
  #define _DEFINE_CAPMIX(num) \
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
  	{ \
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
  		.name = "Capture Switch", \
  		.access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
  		.count = num, \
  		.info = alc_cap_sw_info, \
  		.get = alc_cap_sw_get, \
  		.put = alc_cap_sw_put, \
  	}, \
  	{ \
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
  		.name = "Capture Volume", \
  		.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \
  			   SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
  			   SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \
  		.count = num, \
  		.info = alc_cap_vol_info, \
  		.get = alc_cap_vol_get, \
  		.put = alc_cap_vol_put, \
  		.tlv = { .c = alc_cap_vol_tlv }, \
a23b688f4   Takashi Iwai   ALSA: hda - Don't...
1735
1736
1737
  	}
  
  #define _DEFINE_CAPSRC(num) \
3c3e9892a   Takashi Iwai   ALSA: hda - Re-ad...
1738
1739
1740
1741
1742
1743
1744
1745
  	{ \
  		.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
  		/* .name = "Capture Source", */ \
  		.name = "Input Source", \
  		.count = num, \
  		.info = alc_mux_enum_info, \
  		.get = alc_mux_enum_get, \
  		.put = alc_mux_enum_put, \
a23b688f4   Takashi Iwai   ALSA: hda - Don't...
1746
1747
1748
  	}
  
  #define DEFINE_CAPMIX(num) \
a9111321f   Takashi Iwai   ALSA: hda - Const...
1749
  static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \
a23b688f4   Takashi Iwai   ALSA: hda - Don't...
1750
1751
1752
1753
1754
1755
  	_DEFINE_CAPMIX(num),				      \
  	_DEFINE_CAPSRC(num),				      \
  	{ } /* end */					      \
  }
  
  #define DEFINE_CAPMIX_NOSRC(num) \
a9111321f   Takashi Iwai   ALSA: hda - Const...
1756
  static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \
a23b688f4   Takashi Iwai   ALSA: hda - Don't...
1757
1758
  	_DEFINE_CAPMIX(num),					    \
  	{ } /* end */						    \
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1759
1760
1761
1762
1763
1764
  }
  
  /* up to three ADCs */
  DEFINE_CAPMIX(1);
  DEFINE_CAPMIX(2);
  DEFINE_CAPMIX(3);
a23b688f4   Takashi Iwai   ALSA: hda - Don't...
1765
1766
1767
  DEFINE_CAPMIX_NOSRC(1);
  DEFINE_CAPMIX_NOSRC(2);
  DEFINE_CAPMIX_NOSRC(3);
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1768
1769
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
1770
   * virtual master controls
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1771
   */
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1772
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
1773
   * slave controls for virtual master
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1774
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
  static const char * const alc_slave_vols[] = {
  	"Front Playback Volume",
  	"Surround Playback Volume",
  	"Center Playback Volume",
  	"LFE Playback Volume",
  	"Side Playback Volume",
  	"Headphone Playback Volume",
  	"Speaker Playback Volume",
  	"Mono Playback Volume",
  	"Line-Out Playback Volume",
3fe45aeaf   Takashi Iwai   ALSA: hda - Add "...
1785
  	"PCM Playback Volume",
1d045db96   Takashi Iwai   ALSA: hda - Split...
1786
  	NULL,
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1787
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
  static const char * const alc_slave_sws[] = {
  	"Front Playback Switch",
  	"Surround Playback Switch",
  	"Center Playback Switch",
  	"LFE Playback Switch",
  	"Side Playback Switch",
  	"Headphone Playback Switch",
  	"Speaker Playback Switch",
  	"Mono Playback Switch",
  	"IEC958 Playback Switch",
  	"Line-Out Playback Switch",
3fe45aeaf   Takashi Iwai   ALSA: hda - Add "...
1799
  	"PCM Playback Switch",
1d045db96   Takashi Iwai   ALSA: hda - Split...
1800
  	NULL,
16ded5253   Takashi Iwai   [ALSA] hda-codec ...
1801
  };
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1802
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
1803
   * build control elements
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1804
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
1805
  #define NID_MAPPING		(-1)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1806

1d045db96   Takashi Iwai   ALSA: hda - Split...
1807
1808
1809
1810
1811
1812
  #define SUBDEV_SPEAKER_		(0 << 6)
  #define SUBDEV_HP_		(1 << 6)
  #define SUBDEV_LINE_		(2 << 6)
  #define SUBDEV_SPEAKER(x)	(SUBDEV_SPEAKER_ | ((x) & 0x3f))
  #define SUBDEV_HP(x)		(SUBDEV_HP_ | ((x) & 0x3f))
  #define SUBDEV_LINE(x)		(SUBDEV_LINE_ | ((x) & 0x3f))
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1813

1d045db96   Takashi Iwai   ALSA: hda - Split...
1814
  static void alc_free_kctls(struct hda_codec *codec);
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1815

1d045db96   Takashi Iwai   ALSA: hda - Split...
1816
1817
1818
1819
1820
  #ifdef CONFIG_SND_HDA_INPUT_BEEP
  /* additional beep mixers; the actual parameters are overwritten at build */
  static const struct snd_kcontrol_new alc_beep_mixer[] = {
  	HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
  	HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
16ded5253   Takashi Iwai   [ALSA] hda-codec ...
1821
1822
  	{ } /* end */
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
1823
  #endif
16ded5253   Takashi Iwai   [ALSA] hda-codec ...
1824

1d045db96   Takashi Iwai   ALSA: hda - Split...
1825
1826
1827
1828
1829
1830
1831
1832
  static int alc_build_controls(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	struct snd_kcontrol *kctl = NULL;
  	const struct snd_kcontrol_new *knew;
  	int i, j, err;
  	unsigned int u;
  	hda_nid_t nid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1833
1834
1835
1836
1837
1838
  
  	for (i = 0; i < spec->num_mixers; i++) {
  		err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
  		if (err < 0)
  			return err;
  	}
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
1839
1840
1841
1842
1843
  	if (spec->cap_mixer) {
  		err = snd_hda_add_new_ctls(codec, spec->cap_mixer);
  		if (err < 0)
  			return err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1844
  	if (spec->multiout.dig_out_nid) {
9c7f852e8   Takashi Iwai   [ALSA] Fix/add su...
1845
  		err = snd_hda_create_spdif_out_ctls(codec,
74b654c95   Stephen Warren   ALSA: hda: Virtua...
1846
  						    spec->multiout.dig_out_nid,
9c7f852e8   Takashi Iwai   [ALSA] Fix/add su...
1847
  						    spec->multiout.dig_out_nid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1848
1849
  		if (err < 0)
  			return err;
e64f14f4e   Takashi Iwai   ALSA: hda - Allow...
1850
1851
1852
1853
1854
1855
1856
  		if (!spec->no_analog) {
  			err = snd_hda_create_spdif_share_sw(codec,
  							    &spec->multiout);
  			if (err < 0)
  				return err;
  			spec->multiout.share_spdif = 1;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1857
1858
1859
1860
1861
1862
  	}
  	if (spec->dig_in_nid) {
  		err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
  		if (err < 0)
  			return err;
  	}
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
1863

67d634c07   Takashi Iwai   ALSA: hda - Fix b...
1864
  #ifdef CONFIG_SND_HDA_INPUT_BEEP
45bdd1c1b   Takashi Iwai   ALSA: hda - Creat...
1865
1866
  	/* create beep controls if needed */
  	if (spec->beep_amp) {
a9111321f   Takashi Iwai   ALSA: hda - Const...
1867
  		const struct snd_kcontrol_new *knew;
45bdd1c1b   Takashi Iwai   ALSA: hda - Creat...
1868
1869
1870
1871
1872
1873
  		for (knew = alc_beep_mixer; knew->name; knew++) {
  			struct snd_kcontrol *kctl;
  			kctl = snd_ctl_new1(knew, codec);
  			if (!kctl)
  				return -ENOMEM;
  			kctl->private_value = spec->beep_amp;
5e26dfd06   Jaroslav Kysela   ALSA: hda - simpl...
1874
  			err = snd_hda_ctl_add(codec, 0, kctl);
45bdd1c1b   Takashi Iwai   ALSA: hda - Creat...
1875
1876
1877
1878
  			if (err < 0)
  				return err;
  		}
  	}
67d634c07   Takashi Iwai   ALSA: hda - Fix b...
1879
  #endif
45bdd1c1b   Takashi Iwai   ALSA: hda - Creat...
1880

2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
1881
  	/* if we have no master control, let's create it */
e64f14f4e   Takashi Iwai   ALSA: hda - Allow...
1882
1883
  	if (!spec->no_analog &&
  	    !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
1c82ed1bc   Takashi Iwai   [ALSA] Keep priva...
1884
  		unsigned int vmaster_tlv[4];
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
1885
  		snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
1c82ed1bc   Takashi Iwai   [ALSA] Keep priva...
1886
  					HDA_OUTPUT, vmaster_tlv);
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
1887
  		err = snd_hda_add_vmaster(codec, "Master Playback Volume",
1c82ed1bc   Takashi Iwai   [ALSA] Keep priva...
1888
  					  vmaster_tlv, alc_slave_vols);
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
1889
1890
1891
  		if (err < 0)
  			return err;
  	}
e64f14f4e   Takashi Iwai   ALSA: hda - Allow...
1892
1893
  	if (!spec->no_analog &&
  	    !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
1894
1895
1896
1897
1898
  		err = snd_hda_add_vmaster(codec, "Master Playback Switch",
  					  NULL, alc_slave_sws);
  		if (err < 0)
  			return err;
  	}
5b0cb1d85   Jaroslav Kysela   ALSA: hda - add m...
1899
  	/* assign Capture Source enums to NID */
fbe618f21   Takashi Iwai   ALSA: hda - Don't...
1900
1901
1902
1903
1904
  	if (spec->capsrc_nids || spec->adc_nids) {
  		kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
  		if (!kctl)
  			kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
  		for (i = 0; kctl && i < kctl->count; i++) {
61071594f   Takashi Iwai   ALSA: hda/realtek...
1905
1906
  			err = snd_hda_add_nid(codec, kctl, i,
  					      get_capsrc(spec, i));
fbe618f21   Takashi Iwai   ALSA: hda - Don't...
1907
1908
1909
  			if (err < 0)
  				return err;
  		}
5b0cb1d85   Jaroslav Kysela   ALSA: hda - add m...
1910
  	}
60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
1911
  	if (spec->cap_mixer && spec->adc_nids) {
5b0cb1d85   Jaroslav Kysela   ALSA: hda - add m...
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
  		const char *kname = kctl ? kctl->id.name : NULL;
  		for (knew = spec->cap_mixer; knew->name; knew++) {
  			if (kname && strcmp(knew->name, kname) == 0)
  				continue;
  			kctl = snd_hda_find_mixer_ctl(codec, knew->name);
  			for (i = 0; kctl && i < kctl->count; i++) {
  				err = snd_hda_add_nid(codec, kctl, i,
  						      spec->adc_nids[i]);
  				if (err < 0)
  					return err;
  			}
  		}
  	}
  
  	/* other nid->control mapping */
  	for (i = 0; i < spec->num_mixers; i++) {
  		for (knew = spec->mixers[i]; knew->name; knew++) {
  			if (knew->iface != NID_MAPPING)
  				continue;
  			kctl = snd_hda_find_mixer_ctl(codec, knew->name);
  			if (kctl == NULL)
  				continue;
  			u = knew->subdevice;
  			for (j = 0; j < 4; j++, u >>= 8) {
  				nid = u & 0x3f;
  				if (nid == 0)
  					continue;
  				switch (u & 0xc0) {
  				case SUBDEV_SPEAKER_:
  					nid = spec->autocfg.speaker_pins[nid];
  					break;
  				case SUBDEV_LINE_:
  					nid = spec->autocfg.line_out_pins[nid];
  					break;
  				case SUBDEV_HP_:
  					nid = spec->autocfg.hp_pins[nid];
  					break;
  				default:
  					continue;
  				}
  				err = snd_hda_add_nid(codec, kctl, 0, nid);
  				if (err < 0)
  					return err;
  			}
  			u = knew->private_value;
  			for (j = 0; j < 4; j++, u >>= 8) {
  				nid = u & 0xff;
  				if (nid == 0)
  					continue;
  				err = snd_hda_add_nid(codec, kctl, 0, nid);
  				if (err < 0)
  					return err;
  			}
  		}
  	}
bae84e70d   Takashi Iwai   ALSA: hda - Fix a...
1967
1968
  
  	alc_free_kctls(codec); /* no longer needed */
01a61e12b   Takashi Iwai   ALSA: hda - Creat...
1969
1970
1971
  	err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1972
1973
  	return 0;
  }
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1974

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1975
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
1976
   * Common callbacks
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
1977
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1978

1d045db96   Takashi Iwai   ALSA: hda - Split...
1979
  static void alc_init_special_input_src(struct hda_codec *codec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1980

1d045db96   Takashi Iwai   ALSA: hda - Split...
1981
1982
1983
1984
  static int alc_init(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	unsigned int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1985

1d045db96   Takashi Iwai   ALSA: hda - Split...
1986
1987
  	alc_fix_pll(codec);
  	alc_auto_init_amp(codec, spec->init_amp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1988

1d045db96   Takashi Iwai   ALSA: hda - Split...
1989
1990
1991
  	for (i = 0; i < spec->num_init_verbs; i++)
  		snd_hda_sequence_write(codec, spec->init_verbs[i]);
  	alc_init_special_input_src(codec);
dfc0ff62a   Takashi Iwai   [ALSA] Add ASUS Z...
1992

1d045db96   Takashi Iwai   ALSA: hda - Split...
1993
1994
  	if (spec->init_hook)
  		spec->init_hook(codec);
16ded5253   Takashi Iwai   [ALSA] hda-codec ...
1995

1d045db96   Takashi Iwai   ALSA: hda - Split...
1996
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT);
16ded5253   Takashi Iwai   [ALSA] hda-codec ...
1997

01a61e12b   Takashi Iwai   ALSA: hda - Creat...
1998
  	snd_hda_jack_report_sync(codec);
1d045db96   Takashi Iwai   ALSA: hda - Split...
1999
2000
2001
  	hda_call_check_power_status(codec, 0x01);
  	return 0;
  }
ea1fb29ac   Kailang Yang   ALSA: hda - fix s...
2002

1d045db96   Takashi Iwai   ALSA: hda - Split...
2003
2004
2005
  static void alc_unsol_event(struct hda_codec *codec, unsigned int res)
  {
  	struct alc_spec *spec = codec->spec;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2006

1d045db96   Takashi Iwai   ALSA: hda - Split...
2007
2008
2009
  	if (spec->unsol_event)
  		spec->unsol_event(codec, res);
  }
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2010

1d045db96   Takashi Iwai   ALSA: hda - Split...
2011
2012
2013
2014
2015
2016
2017
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid)
  {
  	struct alc_spec *spec = codec->spec;
  	return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
  }
  #endif
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2018
2019
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
2020
   * Analog playback callbacks
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2021
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
2022
2023
2024
  static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo,
  				    struct hda_codec *codec,
  				    struct snd_pcm_substream *substream)
458a4fabf   Takashi Iwai   [ALSA] hda-codec ...
2025
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2026
2027
2028
  	struct alc_spec *spec = codec->spec;
  	return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
  					     hinfo);
458a4fabf   Takashi Iwai   [ALSA] hda-codec ...
2029
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2030
2031
2032
2033
2034
  static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
  				       struct hda_codec *codec,
  				       unsigned int stream_tag,
  				       unsigned int format,
  				       struct snd_pcm_substream *substream)
458a4fabf   Takashi Iwai   [ALSA] hda-codec ...
2035
  {
a9fd4f3fc   Takashi Iwai   ALSA: hda - Clean...
2036
  	struct alc_spec *spec = codec->spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2037
2038
  	return snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
  						stream_tag, format, substream);
4f5d17062   Takashi Iwai   ALSA: hda - Clean...
2039
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2040
2041
2042
  static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
  				       struct hda_codec *codec,
  				       struct snd_pcm_substream *substream)
4f5d17062   Takashi Iwai   ALSA: hda - Clean...
2043
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2044
2045
  	struct alc_spec *spec = codec->spec;
  	return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2046
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2047
2048
2049
2050
2051
2052
  /*
   * Digital out
   */
  static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
  					struct hda_codec *codec,
  					struct snd_pcm_substream *substream)
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2053
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2054
2055
  	struct alc_spec *spec = codec->spec;
  	return snd_hda_multi_out_dig_open(codec, &spec->multiout);
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2056
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2057
2058
2059
2060
2061
  static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
  					   struct hda_codec *codec,
  					   unsigned int stream_tag,
  					   unsigned int format,
  					   struct snd_pcm_substream *substream)
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2062
  {
a9fd4f3fc   Takashi Iwai   ALSA: hda - Clean...
2063
  	struct alc_spec *spec = codec->spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2064
2065
  	return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
  					     stream_tag, format, substream);
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2066
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2067
2068
2069
  static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
  					   struct hda_codec *codec,
  					   struct snd_pcm_substream *substream)
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2070
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2071
2072
  	struct alc_spec *spec = codec->spec;
  	return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2073
  }
47fd830ac   Takashi Iwai   [ALSA] hda-codec ...
2074

1d045db96   Takashi Iwai   ALSA: hda - Split...
2075
2076
2077
  static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
  					 struct hda_codec *codec,
  					 struct snd_pcm_substream *substream)
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2078
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2079
2080
  	struct alc_spec *spec = codec->spec;
  	return snd_hda_multi_out_dig_close(codec, &spec->multiout);
ccc656ce5   Kailang Yang   [ALSA] hda-codec ...
2081
  }
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2082
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
2083
   * Analog capture
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2084
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
2085
2086
2087
2088
2089
2090
2091
  static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
  				      struct hda_codec *codec,
  				      unsigned int stream_tag,
  				      unsigned int format,
  				      struct snd_pcm_substream *substream)
  {
  	struct alc_spec *spec = codec->spec;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2092

6330079fc   Takashi Iwai   [ALSA] hda-codec ...
2093
  	snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2094
2095
2096
  				   stream_tag, 0, format);
  	return 0;
  }
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2097
  static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2098
  				      struct hda_codec *codec,
c8b6bf9b5   Takashi Iwai   [ALSA] Remove xxx...
2099
  				      struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2100
2101
  {
  	struct alc_spec *spec = codec->spec;
888afa154   Takashi Iwai   [ALSA] hda-codec ...
2102
2103
  	snd_hda_codec_cleanup_stream(codec,
  				     spec->adc_nids[substream->number + 1]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2104
2105
  	return 0;
  }
840b64c08   Takashi Iwai   ALSA: hda - Add s...
2106
  /* analog capture with dynamic dual-adc changes */
21268961d   Takashi Iwai   ALSA: hda - More ...
2107
  static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
840b64c08   Takashi Iwai   ALSA: hda - Add s...
2108
2109
2110
2111
2112
2113
  				       struct hda_codec *codec,
  				       unsigned int stream_tag,
  				       unsigned int format,
  				       struct snd_pcm_substream *substream)
  {
  	struct alc_spec *spec = codec->spec;
21268961d   Takashi Iwai   ALSA: hda - More ...
2114
  	spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
840b64c08   Takashi Iwai   ALSA: hda - Add s...
2115
2116
2117
2118
2119
  	spec->cur_adc_stream_tag = stream_tag;
  	spec->cur_adc_format = format;
  	snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
  	return 0;
  }
21268961d   Takashi Iwai   ALSA: hda - More ...
2120
  static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
840b64c08   Takashi Iwai   ALSA: hda - Add s...
2121
2122
2123
2124
2125
2126
2127
2128
  				       struct hda_codec *codec,
  				       struct snd_pcm_substream *substream)
  {
  	struct alc_spec *spec = codec->spec;
  	snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
  	spec->cur_adc = 0;
  	return 0;
  }
21268961d   Takashi Iwai   ALSA: hda - More ...
2129
  static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
840b64c08   Takashi Iwai   ALSA: hda - Add s...
2130
2131
2132
2133
2134
  	.substreams = 1,
  	.channels_min = 2,
  	.channels_max = 2,
  	.nid = 0, /* fill later */
  	.ops = {
21268961d   Takashi Iwai   ALSA: hda - More ...
2135
2136
  		.prepare = dyn_adc_capture_pcm_prepare,
  		.cleanup = dyn_adc_capture_pcm_cleanup
840b64c08   Takashi Iwai   ALSA: hda - Add s...
2137
2138
  	},
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2139
2140
2141
  
  /*
   */
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2142
  static const struct hda_pcm_stream alc_pcm_analog_playback = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2143
2144
2145
  	.substreams = 1,
  	.channels_min = 2,
  	.channels_max = 8,
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2146
  	/* NID is set in alc_build_pcms */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2147
  	.ops = {
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2148
2149
2150
  		.open = alc_playback_pcm_open,
  		.prepare = alc_playback_pcm_prepare,
  		.cleanup = alc_playback_pcm_cleanup
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2151
2152
  	},
  };
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2153
  static const struct hda_pcm_stream alc_pcm_analog_capture = {
6330079fc   Takashi Iwai   [ALSA] hda-codec ...
2154
2155
2156
2157
2158
  	.substreams = 1,
  	.channels_min = 2,
  	.channels_max = 2,
  	/* NID is set in alc_build_pcms */
  };
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2159
  static const struct hda_pcm_stream alc_pcm_analog_alt_playback = {
6330079fc   Takashi Iwai   [ALSA] hda-codec ...
2160
2161
2162
2163
2164
  	.substreams = 1,
  	.channels_min = 2,
  	.channels_max = 2,
  	/* NID is set in alc_build_pcms */
  };
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2165
  static const struct hda_pcm_stream alc_pcm_analog_alt_capture = {
6330079fc   Takashi Iwai   [ALSA] hda-codec ...
2166
  	.substreams = 2, /* can be overridden */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2167
2168
  	.channels_min = 2,
  	.channels_max = 2,
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2169
  	/* NID is set in alc_build_pcms */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2170
  	.ops = {
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2171
2172
  		.prepare = alc_alt_capture_pcm_prepare,
  		.cleanup = alc_alt_capture_pcm_cleanup
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2173
2174
  	},
  };
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2175
  static const struct hda_pcm_stream alc_pcm_digital_playback = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2176
2177
2178
2179
2180
  	.substreams = 1,
  	.channels_min = 2,
  	.channels_max = 2,
  	/* NID is set in alc_build_pcms */
  	.ops = {
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2181
2182
2183
2184
  		.open = alc_dig_playback_pcm_open,
  		.close = alc_dig_playback_pcm_close,
  		.prepare = alc_dig_playback_pcm_prepare,
  		.cleanup = alc_dig_playback_pcm_cleanup
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2185
2186
  	},
  };
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2187
  static const struct hda_pcm_stream alc_pcm_digital_capture = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2188
2189
2190
2191
2192
  	.substreams = 1,
  	.channels_min = 2,
  	.channels_max = 2,
  	/* NID is set in alc_build_pcms */
  };
4c5186ed6   Jonathan Woithe   [ALSA] hda: add P...
2193
  /* Used by alc_build_pcms to flag that a PCM has no playback stream */
a9111321f   Takashi Iwai   ALSA: hda - Const...
2194
  static const struct hda_pcm_stream alc_pcm_null_stream = {
4c5186ed6   Jonathan Woithe   [ALSA] hda: add P...
2195
2196
2197
2198
  	.substreams = 0,
  	.channels_min = 0,
  	.channels_max = 0,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2199
2200
2201
2202
  static int alc_build_pcms(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	struct hda_pcm *info = spec->pcm_rec;
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2203
  	const struct hda_pcm_stream *p;
1fa175736   Takashi Iwai   ALSA: hda/realtek...
2204
  	bool have_multi_adcs;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2205
2206
2207
2208
  	int i;
  
  	codec->num_pcms = 1;
  	codec->pcm_info = info;
e64f14f4e   Takashi Iwai   ALSA: hda - Allow...
2209
2210
  	if (spec->no_analog)
  		goto skip_analog;
812a2cca2   Takashi Iwai   ALSA: hda - Split...
2211
2212
  	snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog),
  		 "%s Analog", codec->chip_name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2213
  	info->name = spec->stream_name_analog;
274693f37   Kailang Yang   ALSA: hda - Add A...
2214

c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2215
2216
2217
2218
2219
  	if (spec->multiout.dac_nids > 0) {
  		p = spec->stream_analog_playback;
  		if (!p)
  			p = &alc_pcm_analog_playback;
  		info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
4a471b7dd   Takashi Iwai   [ALSA] hda-codec ...
2220
2221
  		info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
  	}
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2222
2223
  	if (spec->adc_nids) {
  		p = spec->stream_analog_capture;
21268961d   Takashi Iwai   ALSA: hda - More ...
2224
2225
2226
2227
2228
2229
  		if (!p) {
  			if (spec->dyn_adc_switch)
  				p = &dyn_adc_pcm_analog_capture;
  			else
  				p = &alc_pcm_analog_capture;
  		}
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2230
  		info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
4a471b7dd   Takashi Iwai   [ALSA] hda-codec ...
2231
2232
2233
2234
2235
2236
2237
2238
2239
  		info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
  	}
  
  	if (spec->channel_mode) {
  		info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0;
  		for (i = 0; i < spec->num_channel_mode; i++) {
  			if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) {
  				info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2240
2241
  		}
  	}
e64f14f4e   Takashi Iwai   ALSA: hda - Allow...
2242
   skip_analog:
e08a007d1   Takashi Iwai   [ALSA] hda-codec ...
2243
  	/* SPDIF for stream index #1 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2244
  	if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
812a2cca2   Takashi Iwai   ALSA: hda - Split...
2245
2246
2247
  		snprintf(spec->stream_name_digital,
  			 sizeof(spec->stream_name_digital),
  			 "%s Digital", codec->chip_name);
e08a007d1   Takashi Iwai   [ALSA] hda-codec ...
2248
  		codec->num_pcms = 2;
b25c9da19   Wu Fengguang   ALSA: enable conc...
2249
  	        codec->slave_dig_outs = spec->multiout.slave_dig_outs;
c06134d73   Takashi Iwai   [ALSA] hda-codec ...
2250
  		info = spec->pcm_rec + 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2251
  		info->name = spec->stream_name_digital;
8c441982f   Takashi Iwai   ALSA: hda - Assig...
2252
2253
2254
2255
  		if (spec->dig_out_type)
  			info->pcm_type = spec->dig_out_type;
  		else
  			info->pcm_type = HDA_PCM_TYPE_SPDIF;
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2256
2257
2258
2259
2260
  		if (spec->multiout.dig_out_nid) {
  			p = spec->stream_digital_playback;
  			if (!p)
  				p = &alc_pcm_digital_playback;
  			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2261
2262
  			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
  		}
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2263
2264
2265
2266
2267
  		if (spec->dig_in_nid) {
  			p = spec->stream_digital_capture;
  			if (!p)
  				p = &alc_pcm_digital_capture;
  			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2268
2269
  			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
  		}
963f803fb   Takashi Iwai   ALSA: hda - Don't...
2270
2271
  		/* FIXME: do we need this for all Realtek codec models? */
  		codec->spdif_status_reset = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2272
  	}
e64f14f4e   Takashi Iwai   ALSA: hda - Allow...
2273
2274
  	if (spec->no_analog)
  		return 0;
e08a007d1   Takashi Iwai   [ALSA] hda-codec ...
2275
2276
2277
  	/* If the use of more than one ADC is requested for the current
  	 * model, configure a second analog capture-only PCM.
  	 */
1fa175736   Takashi Iwai   ALSA: hda/realtek...
2278
2279
2280
  	have_multi_adcs = (spec->num_adc_nids > 1) &&
  		!spec->dyn_adc_switch && !spec->auto_mic &&
  		(!spec->input_mux || spec->input_mux->num_items > 1);
e08a007d1   Takashi Iwai   [ALSA] hda-codec ...
2281
  	/* Additional Analaog capture for index #2 */
1fa175736   Takashi Iwai   ALSA: hda/realtek...
2282
  	if (spec->alt_dac_nid || have_multi_adcs) {
e08a007d1   Takashi Iwai   [ALSA] hda-codec ...
2283
  		codec->num_pcms = 3;
c06134d73   Takashi Iwai   [ALSA] hda-codec ...
2284
  		info = spec->pcm_rec + 2;
e08a007d1   Takashi Iwai   [ALSA] hda-codec ...
2285
  		info->name = spec->stream_name_analog;
6330079fc   Takashi Iwai   [ALSA] hda-codec ...
2286
  		if (spec->alt_dac_nid) {
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2287
2288
2289
2290
  			p = spec->stream_analog_alt_playback;
  			if (!p)
  				p = &alc_pcm_analog_alt_playback;
  			info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p;
6330079fc   Takashi Iwai   [ALSA] hda-codec ...
2291
2292
2293
2294
2295
2296
2297
  			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
  				spec->alt_dac_nid;
  		} else {
  			info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
  				alc_pcm_null_stream;
  			info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0;
  		}
1fa175736   Takashi Iwai   ALSA: hda/realtek...
2298
  		if (have_multi_adcs) {
c2d986b0d   Takashi Iwai   ALSA: hda - Clean...
2299
2300
2301
2302
  			p = spec->stream_analog_alt_capture;
  			if (!p)
  				p = &alc_pcm_analog_alt_capture;
  			info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p;
6330079fc   Takashi Iwai   [ALSA] hda-codec ...
2303
2304
2305
2306
2307
2308
2309
2310
  			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid =
  				spec->adc_nids[1];
  			info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
  				spec->num_adc_nids - 1;
  		} else {
  			info->stream[SNDRV_PCM_STREAM_CAPTURE] =
  				alc_pcm_null_stream;
  			info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0;
e08a007d1   Takashi Iwai   [ALSA] hda-codec ...
2311
2312
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2313
2314
  	return 0;
  }
a4e09aa3c   Takashi Iwai   ALSA: hda - Fix c...
2315
2316
  static inline void alc_shutup(struct hda_codec *codec)
  {
1c716153a   Takashi Iwai   ALSA: hda - Intro...
2317
2318
2319
2320
  	struct alc_spec *spec = codec->spec;
  
  	if (spec && spec->shutup)
  		spec->shutup(codec);
a4e09aa3c   Takashi Iwai   ALSA: hda - Fix c...
2321
2322
  	snd_hda_shutup_pins(codec);
  }
603c40199   Takashi Iwai   ALSA: hda - Use g...
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
  static void alc_free_kctls(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  
  	if (spec->kctls.list) {
  		struct snd_kcontrol_new *kctl = spec->kctls.list;
  		int i;
  		for (i = 0; i < spec->kctls.used; i++)
  			kfree(kctl[i].name);
  	}
  	snd_array_free(&spec->kctls);
  }
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
  static void alc_free_bind_ctls(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	if (spec->bind_ctls.list) {
  		struct hda_bind_ctls **ctl = spec->bind_ctls.list;
  		int i;
  		for (i = 0; i < spec->bind_ctls.used; i++)
  			kfree(ctl[i]);
  	}
  	snd_array_free(&spec->bind_ctls);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2346
2347
  static void alc_free(struct hda_codec *codec)
  {
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2348
  	struct alc_spec *spec = codec->spec;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2349

f12ab1e07   Takashi Iwai   [ALSA] hda-codec ...
2350
  	if (!spec)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2351
  		return;
a4e09aa3c   Takashi Iwai   ALSA: hda - Fix c...
2352
  	alc_shutup(codec);
603c40199   Takashi Iwai   ALSA: hda - Use g...
2353
  	alc_free_kctls(codec);
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2354
  	alc_free_bind_ctls(codec);
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2355
  	kfree(spec);
680cd5365   Kusanagi Kouichi   ALSA: hda: Add di...
2356
  	snd_hda_detach_beep_device(codec);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2357
  }
f5de24b06   Hector Martin   ALSA: HDA: add po...
2358
  #ifdef CONFIG_SND_HDA_POWER_SAVE
c97259df3   Daniel T Chen   ALSA: hda: Refact...
2359
2360
  static void alc_power_eapd(struct hda_codec *codec)
  {
691f1fccf   Takashi Iwai   ALSA: hda - Refac...
2361
  	alc_auto_setup_eapd(codec, false);
c97259df3   Daniel T Chen   ALSA: hda: Refact...
2362
  }
f5de24b06   Hector Martin   ALSA: HDA: add po...
2363
2364
2365
  static int alc_suspend(struct hda_codec *codec, pm_message_t state)
  {
  	struct alc_spec *spec = codec->spec;
a4e09aa3c   Takashi Iwai   ALSA: hda - Fix c...
2366
  	alc_shutup(codec);
f5de24b06   Hector Martin   ALSA: HDA: add po...
2367
  	if (spec && spec->power_hook)
c97259df3   Daniel T Chen   ALSA: hda: Refact...
2368
  		spec->power_hook(codec);
f5de24b06   Hector Martin   ALSA: HDA: add po...
2369
2370
2371
  	return 0;
  }
  #endif
2a43952a9   Takashi Iwai   ALSA: hda - Make ...
2372
  #ifdef CONFIG_PM
e044c39ae   Takashi Iwai   ALSA: hda - Resto...
2373
2374
  static int alc_resume(struct hda_codec *codec)
  {
1c716153a   Takashi Iwai   ALSA: hda - Intro...
2375
  	msleep(150); /* to avoid pop noise */
e044c39ae   Takashi Iwai   ALSA: hda - Resto...
2376
2377
2378
  	codec->patch_ops.init(codec);
  	snd_hda_codec_resume_amp(codec);
  	snd_hda_codec_resume_cache(codec);
9e5341b92   Takashi Iwai   ALSA: hda - Intro...
2379
  	hda_call_check_power_status(codec, 0x01);
e044c39ae   Takashi Iwai   ALSA: hda - Resto...
2380
2381
  	return 0;
  }
e044c39ae   Takashi Iwai   ALSA: hda - Resto...
2382
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2383
2384
  /*
   */
a9111321f   Takashi Iwai   ALSA: hda - Const...
2385
  static const struct hda_codec_ops alc_patch_ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2386
2387
2388
2389
  	.build_controls = alc_build_controls,
  	.build_pcms = alc_build_pcms,
  	.init = alc_init,
  	.free = alc_free,
ae6b813a4   Takashi Iwai   [ALSA] hda-codec ...
2390
  	.unsol_event = alc_unsol_event,
2a43952a9   Takashi Iwai   ALSA: hda - Make ...
2391
  #ifdef CONFIG_PM
e044c39ae   Takashi Iwai   ALSA: hda - Resto...
2392
2393
  	.resume = alc_resume,
  #endif
cb53c626e   Takashi Iwai   [ALSA] hda-intel ...
2394
  #ifdef CONFIG_SND_HDA_POWER_SAVE
f5de24b06   Hector Martin   ALSA: HDA: add po...
2395
  	.suspend = alc_suspend,
cb53c626e   Takashi Iwai   [ALSA] hda-intel ...
2396
2397
  	.check_power_status = alc_check_power_status,
  #endif
c97259df3   Daniel T Chen   ALSA: hda: Refact...
2398
  	.reboot_notify = alc_shutup,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2399
  };
c027ddcd0   Kailang Yang   ALSA: hda - Add a...
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
  /* replace the codec chip_name with the given string */
  static int alc_codec_rename(struct hda_codec *codec, const char *name)
  {
  	kfree(codec->chip_name);
  	codec->chip_name = kstrdup(name, GFP_KERNEL);
  	if (!codec->chip_name) {
  		alc_free(codec);
  		return -ENOMEM;
  	}
  	return 0;
  }
2fa522bed   Takashi Iwai   [ALSA] Add test m...
2411
  /*
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
   * Rename codecs appropriately from COEF value
   */
  struct alc_codec_rename_table {
  	unsigned int vendor_id;
  	unsigned short coef_mask;
  	unsigned short coef_bits;
  	const char *name;
  };
  
  static struct alc_codec_rename_table rename_tbl[] = {
  	{ 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
  	{ 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
  	{ 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
  	{ 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
  	{ 0x10ec0269, 0xffff, 0xa023, "ALC259" },
  	{ 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
  	{ 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
  	{ 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
  	{ 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
  	{ 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
  	{ 0x10ec0899, 0x2000, 0x2000, "ALC899" },
  	{ 0x10ec0892, 0xffff, 0x8020, "ALC661" },
  	{ 0x10ec0892, 0xffff, 0x8011, "ALC661" },
  	{ 0x10ec0892, 0xffff, 0x4011, "ALC656" },
  	{ } /* terminator */
  };
  
  static int alc_codec_rename_from_preset(struct hda_codec *codec)
  {
  	const struct alc_codec_rename_table *p;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
2442
2443
2444
2445
  
  	for (p = rename_tbl; p->vendor_id; p++) {
  		if (p->vendor_id != codec->vendor_id)
  			continue;
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
2446
  		if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
2447
2448
2449
2450
2451
2452
  			return alc_codec_rename(codec, p->name);
  	}
  	return 0;
  }
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
2453
   * Automatic parse of I/O pins from the BIOS configuration
2fa522bed   Takashi Iwai   [ALSA] Add test m...
2454
   */
2fa522bed   Takashi Iwai   [ALSA] Add test m...
2455

1d045db96   Takashi Iwai   ALSA: hda - Split...
2456
2457
2458
2459
  enum {
  	ALC_CTL_WIDGET_VOL,
  	ALC_CTL_WIDGET_MUTE,
  	ALC_CTL_BIND_MUTE,
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2460
2461
  	ALC_CTL_BIND_VOL,
  	ALC_CTL_BIND_SW,
2fa522bed   Takashi Iwai   [ALSA] Add test m...
2462
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
2463
2464
2465
2466
  static const struct snd_kcontrol_new alc_control_templates[] = {
  	HDA_CODEC_VOLUME(NULL, 0, 0, 0),
  	HDA_CODEC_MUTE(NULL, 0, 0, 0),
  	HDA_BIND_MUTE(NULL, 0, 0, 0),
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2467
2468
  	HDA_BIND_VOL(NULL, 0),
  	HDA_BIND_SW(NULL, 0),
2fa522bed   Takashi Iwai   [ALSA] Add test m...
2469
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
2470
2471
2472
  /* add dynamic controls */
  static int add_control(struct alc_spec *spec, int type, const char *name,
  		       int cidx, unsigned long val)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2473
  {
c8b6bf9b5   Takashi Iwai   [ALSA] Remove xxx...
2474
  	struct snd_kcontrol_new *knew;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2475

ce764ab22   Takashi Iwai   ALSA: hda - Add c...
2476
  	knew = alc_kcontrol_new(spec);
603c40199   Takashi Iwai   ALSA: hda - Use g...
2477
2478
  	if (!knew)
  		return -ENOMEM;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2479
  	*knew = alc_control_templates[type];
543537bd9   Paulo Marques   [PATCH] create a ...
2480
  	knew->name = kstrdup(name, GFP_KERNEL);
f12ab1e07   Takashi Iwai   [ALSA] hda-codec ...
2481
  	if (!knew->name)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2482
  		return -ENOMEM;
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2483
  	knew->index = cidx;
4d02d1b63   Jaroslav Kysela   ALSA: hda - proc ...
2484
  	if (get_amp_nid_(val))
5e26dfd06   Jaroslav Kysela   ALSA: hda - simpl...
2485
  		knew->subdevice = HDA_SUBDEV_AMP_FLAG;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2486
  	knew->private_value = val;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2487
2488
  	return 0;
  }
0afe5f891   Takashi Iwai   ALSA: hda - Clean...
2489
2490
  static int add_control_with_pfx(struct alc_spec *spec, int type,
  				const char *pfx, const char *dir,
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2491
  				const char *sfx, int cidx, unsigned long val)
0afe5f891   Takashi Iwai   ALSA: hda - Clean...
2492
2493
2494
  {
  	char name[32];
  	snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2495
  	return add_control(spec, type, name, cidx, val);
0afe5f891   Takashi Iwai   ALSA: hda - Clean...
2496
  }
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2497
2498
2499
2500
2501
2502
2503
2504
  #define add_pb_vol_ctrl(spec, type, pfx, val)			\
  	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
  #define add_pb_sw_ctrl(spec, type, pfx, val)			\
  	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
  #define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)			\
  	add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
  #define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)			\
  	add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
0afe5f891   Takashi Iwai   ALSA: hda - Clean...
2505

23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2506
2507
2508
  static const char * const channel_name[4] = {
  	"Front", "Surround", "CLFE", "Side"
  };
6843ca16f   Takashi Iwai   ALSA: hda - Clean...
2509
2510
  static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch,
  					bool can_be_master, int *index)
bcb2f0f51   Takashi Iwai   ALSA: hda - Add s...
2511
  {
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
2512
  	struct auto_pin_cfg *cfg = &spec->autocfg;
6843ca16f   Takashi Iwai   ALSA: hda - Clean...
2513
  	*index = 0;
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
2514
2515
  	if (cfg->line_outs == 1 && !spec->multi_ios &&
  	    !cfg->hp_outs && !cfg->speaker_outs && can_be_master)
bcb2f0f51   Takashi Iwai   ALSA: hda - Add s...
2516
2517
2518
2519
  		return "Master";
  
  	switch (cfg->line_out_type) {
  	case AUTO_PIN_SPEAKER_OUT:
ebbeb3d6a   David Henningsson   ALSA: HDA: Fix vo...
2520
2521
  		if (cfg->line_outs == 1)
  			return "Speaker";
fbabc2461   Takashi Iwai   ALSA: hda/realtek...
2522
2523
  		if (cfg->line_outs == 2)
  			return ch ? "Bass Speaker" : "Speaker";
ebbeb3d6a   David Henningsson   ALSA: HDA: Fix vo...
2524
  		break;
bcb2f0f51   Takashi Iwai   ALSA: hda - Add s...
2525
  	case AUTO_PIN_HP_OUT:
6843ca16f   Takashi Iwai   ALSA: hda - Clean...
2526
2527
2528
2529
  		/* for multi-io case, only the primary out */
  		if (ch && spec->multi_ios)
  			break;
  		*index = ch;
bcb2f0f51   Takashi Iwai   ALSA: hda - Add s...
2530
2531
  		return "Headphone";
  	default:
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
2532
  		if (cfg->line_outs == 1 && !spec->multi_ios)
bcb2f0f51   Takashi Iwai   ALSA: hda - Add s...
2533
2534
2535
  			return "PCM";
  		break;
  	}
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2536
2537
2538
2539
  	if (snd_BUG_ON(ch >= ARRAY_SIZE(channel_name)))
  		return "PCM";
  
  	return channel_name[ch];
bcb2f0f51   Takashi Iwai   ALSA: hda - Add s...
2540
  }
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2541
  /* create input playback/capture controls for the given pin */
f12ab1e07   Takashi Iwai   [ALSA] hda-codec ...
2542
  static int new_analog_input(struct alc_spec *spec, hda_nid_t pin,
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2543
  			    const char *ctlname, int ctlidx,
df694daa3   Kailang Yang   [ALSA] hda-codec ...
2544
  			    int idx, hda_nid_t mix_nid)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2545
  {
df694daa3   Kailang Yang   [ALSA] hda-codec ...
2546
  	int err;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2547

66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2548
  	err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx,
f12ab1e07   Takashi Iwai   [ALSA] hda-codec ...
2549
2550
  			  HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
  	if (err < 0)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2551
  		return err;
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2552
  	err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx,
f12ab1e07   Takashi Iwai   [ALSA] hda-codec ...
2553
2554
  			  HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT));
  	if (err < 0)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2555
2556
2557
  		return err;
  	return 0;
  }
05f5f4770   Takashi Iwai   ALSA: hda - Gener...
2558
2559
2560
2561
2562
  static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid)
  {
  	unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
  	return (pincap & AC_PINCAP_IN) != 0;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2563
  /* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
2564
  static int alc_auto_fill_adc_caps(struct hda_codec *codec)
b78217096   Takashi Iwai   ALSA: hda - Parse...
2565
  {
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
2566
  	struct alc_spec *spec = codec->spec;
b78217096   Takashi Iwai   ALSA: hda - Parse...
2567
  	hda_nid_t nid;
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
2568
2569
2570
  	hda_nid_t *adc_nids = spec->private_adc_nids;
  	hda_nid_t *cap_nids = spec->private_capsrc_nids;
  	int max_nums = ARRAY_SIZE(spec->private_adc_nids);
b78217096   Takashi Iwai   ALSA: hda - Parse...
2571
  	int i, nums = 0;
24de183ed   Takashi Iwai   ALSA: hda/realtek...
2572
2573
  	if (spec->shared_mic_hp)
  		max_nums = 1; /* no multi streams with the shared HP/mic */
b78217096   Takashi Iwai   ALSA: hda - Parse...
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
  	nid = codec->start_nid;
  	for (i = 0; i < codec->num_nodes; i++, nid++) {
  		hda_nid_t src;
  		const hda_nid_t *list;
  		unsigned int caps = get_wcaps(codec, nid);
  		int type = get_wcaps_type(caps);
  
  		if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
  			continue;
  		adc_nids[nums] = nid;
  		cap_nids[nums] = nid;
  		src = nid;
  		for (;;) {
  			int n;
  			type = get_wcaps_type(get_wcaps(codec, src));
  			if (type == AC_WID_PIN)
  				break;
  			if (type == AC_WID_AUD_SEL) {
  				cap_nids[nums] = src;
  				break;
  			}
  			n = snd_hda_get_conn_list(codec, src, &list);
  			if (n > 1) {
  				cap_nids[nums] = src;
  				break;
  			} else if (n != 1)
  				break;
  			src = *list;
  		}
  		if (++nums >= max_nums)
  			break;
  	}
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
2606
  	spec->adc_nids = spec->private_adc_nids;
21268961d   Takashi Iwai   ALSA: hda - More ...
2607
  	spec->capsrc_nids = spec->private_capsrc_nids;
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
2608
  	spec->num_adc_nids = nums;
b78217096   Takashi Iwai   ALSA: hda - Parse...
2609
2610
  	return nums;
  }
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2611
  /* create playback/capture controls for input pins */
b78217096   Takashi Iwai   ALSA: hda - Parse...
2612
  static int alc_auto_create_input_ctls(struct hda_codec *codec)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2613
  {
05f5f4770   Takashi Iwai   ALSA: hda - Gener...
2614
  	struct alc_spec *spec = codec->spec;
b78217096   Takashi Iwai   ALSA: hda - Parse...
2615
2616
  	const struct auto_pin_cfg *cfg = &spec->autocfg;
  	hda_nid_t mixer = spec->mixer_nid;
61b9b9b10   Herton Ronaldo Krzesinski   ALSA: hda - Consi...
2617
  	struct hda_input_mux *imux = &spec->private_imux[0];
b78217096   Takashi Iwai   ALSA: hda - Parse...
2618
  	int num_adcs;
b78217096   Takashi Iwai   ALSA: hda - Parse...
2619
  	int i, c, err, idx, type_idx = 0;
5322bf279   David Henningsson   ALSA: HDA: Fix vo...
2620
  	const char *prev_label = NULL;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2621

d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
2622
  	num_adcs = alc_auto_fill_adc_caps(codec);
b78217096   Takashi Iwai   ALSA: hda - Parse...
2623
2624
  	if (num_adcs < 0)
  		return 0;
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2625
  	for (i = 0; i < cfg->num_inputs; i++) {
05f5f4770   Takashi Iwai   ALSA: hda - Gener...
2626
  		hda_nid_t pin;
10a20af7c   Takashi Iwai   ALSA: hda - Impro...
2627
  		const char *label;
05f5f4770   Takashi Iwai   ALSA: hda - Gener...
2628

66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2629
  		pin = cfg->inputs[i].pin;
05f5f4770   Takashi Iwai   ALSA: hda - Gener...
2630
2631
  		if (!alc_is_input_pin(codec, pin))
  			continue;
5322bf279   David Henningsson   ALSA: HDA: Fix vo...
2632
  		label = hda_get_autocfg_input_label(codec, cfg, i);
24de183ed   Takashi Iwai   ALSA: hda/realtek...
2633
2634
  		if (spec->shared_mic_hp && !strcmp(label, "Misc"))
  			label = "Headphone Mic";
5322bf279   David Henningsson   ALSA: HDA: Fix vo...
2635
  		if (prev_label && !strcmp(label, prev_label))
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2636
2637
2638
  			type_idx++;
  		else
  			type_idx = 0;
5322bf279   David Henningsson   ALSA: HDA: Fix vo...
2639
  		prev_label = label;
05f5f4770   Takashi Iwai   ALSA: hda - Gener...
2640
2641
2642
2643
  		if (mixer) {
  			idx = get_connection_index(codec, mixer, pin);
  			if (idx >= 0) {
  				err = new_analog_input(spec, pin,
10a20af7c   Takashi Iwai   ALSA: hda - Impro...
2644
2645
  						       label, type_idx,
  						       idx, mixer);
05f5f4770   Takashi Iwai   ALSA: hda - Gener...
2646
2647
2648
2649
  				if (err < 0)
  					return err;
  			}
  		}
b78217096   Takashi Iwai   ALSA: hda - Parse...
2650
  		for (c = 0; c < num_adcs; c++) {
61071594f   Takashi Iwai   ALSA: hda/realtek...
2651
  			hda_nid_t cap = get_capsrc(spec, c);
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
2652
  			idx = get_connection_index(codec, cap, pin);
b78217096   Takashi Iwai   ALSA: hda - Parse...
2653
  			if (idx >= 0) {
21268961d   Takashi Iwai   ALSA: hda - More ...
2654
  				spec->imux_pins[imux->num_items] = pin;
b78217096   Takashi Iwai   ALSA: hda - Parse...
2655
2656
2657
2658
  				snd_hda_add_imux_item(imux, label, idx, NULL);
  				break;
  			}
  		}
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2659
  	}
21268961d   Takashi Iwai   ALSA: hda - More ...
2660
2661
2662
  
  	spec->num_mux_defs = 1;
  	spec->input_mux = imux;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2663
2664
  	return 0;
  }
24de183ed   Takashi Iwai   ALSA: hda/realtek...
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
  /* create a shared input with the headphone out */
  static int alc_auto_create_shared_input(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	struct auto_pin_cfg *cfg = &spec->autocfg;
  	unsigned int defcfg;
  	hda_nid_t nid;
  
  	/* only one internal input pin? */
  	if (cfg->num_inputs != 1)
  		return 0;
  	defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
  	if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
  		return 0;
  
  	if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
  		nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */
  	else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT)
  		nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */
  	else
  		return 0; /* both not available */
  
  	if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
  		return 0; /* no input */
  
  	cfg->inputs[1].pin = nid;
  	cfg->inputs[1].type = AUTO_PIN_MIC;
  	cfg->num_inputs = 2;
  	spec->shared_mic_hp = 1;
  	snd_printdd("realtek: Enable shared I/O jack on NID 0x%x
  ", nid);
  	return 0;
  }
f6c7e5461   Takashi Iwai   [ALSA] hda-codec ...
2698
2699
2700
2701
2702
2703
  static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid,
  			       unsigned int pin_type)
  {
  	snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
  			    pin_type);
  	/* unmute pin */
44c024005   Takashi Iwai   ALSA: hda - Fix a...
2704
2705
  	if (nid_has_mute(codec, nid, HDA_OUTPUT))
  		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
d260cdf65   Takashi Iwai   [ALSA] hda-codec ...
2706
  			    AMP_OUT_UNMUTE);
f6c7e5461   Takashi Iwai   [ALSA] hda-codec ...
2707
  }
baba8ee9d   Takashi Iwai   [ALSA] hda-codec ...
2708
2709
2710
2711
2712
2713
2714
  static int get_pin_type(int line_out_type)
  {
  	if (line_out_type == AUTO_PIN_HP_OUT)
  		return PIN_HP;
  	else
  		return PIN_OUT;
  }
0a7f53209   Takashi Iwai   ALSA: hda - Unify...
2715
  static void alc_auto_init_analog_input(struct hda_codec *codec)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2716
2717
  {
  	struct alc_spec *spec = codec->spec;
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2718
  	struct auto_pin_cfg *cfg = &spec->autocfg;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2719
  	int i;
66ceeb6bc   Takashi Iwai   ALSA: hda - Use n...
2720
2721
  	for (i = 0; i < cfg->num_inputs; i++) {
  		hda_nid_t nid = cfg->inputs[i].pin;
05f5f4770   Takashi Iwai   ALSA: hda - Gener...
2722
  		if (alc_is_input_pin(codec, nid)) {
30ea098fc   Takashi Iwai   ALSA: hda - Fix i...
2723
  			alc_set_input_pin(codec, nid, cfg->inputs[i].type);
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
2724
  			if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
f12ab1e07   Takashi Iwai   [ALSA] hda-codec ...
2725
2726
  				snd_hda_codec_write(codec, nid, 0,
  						    AC_VERB_SET_AMP_GAIN_MUTE,
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2727
2728
2729
  						    AMP_OUT_MUTE);
  		}
  	}
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
2730
2731
2732
2733
2734
2735
2736
2737
2738
  
  	/* mute all loopback inputs */
  	if (spec->mixer_nid) {
  		int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL);
  		for (i = 0; i < nums; i++)
  			snd_hda_codec_write(codec, spec->mixer_nid, 0,
  					    AC_VERB_SET_AMP_GAIN_MUTE,
  					    AMP_IN_MUTE(i));
  	}
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2739
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2740
2741
  /* convert from MIX nid to DAC */
  static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2742
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2743
2744
  	hda_nid_t list[5];
  	int i, num;
4a79ba34c   Takashi Iwai   ALSA: hda - Add a...
2745

afcd55150   Takashi Iwai   ALSA: hda - Merge...
2746
2747
  	if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT)
  		return nid;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2748
2749
2750
2751
2752
2753
  	num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list));
  	for (i = 0; i < num; i++) {
  		if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT)
  			return list[i];
  	}
  	return 0;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2754
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2755
2756
  /* go down to the selector widget before the mixer */
  static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin)
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2757
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2758
2759
2760
2761
2762
2763
2764
  	hda_nid_t srcs[5];
  	int num = snd_hda_get_connections(codec, pin, srcs,
  					  ARRAY_SIZE(srcs));
  	if (num != 1 ||
  	    get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL)
  		return pin;
  	return srcs[0];
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
2765
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2766
2767
2768
  /* get MIX nid connected to the given pin targeted to DAC */
  static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin,
  				   hda_nid_t dac)
748cce431   Takashi Iwai   ALSA: hda - Fix i...
2769
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2770
2771
2772
2773
2774
2775
2776
2777
  	hda_nid_t mix[5];
  	int i, num;
  
  	pin = alc_go_down_to_selector(codec, pin);
  	num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
  	for (i = 0; i < num; i++) {
  		if (alc_auto_mix_to_dac(codec, mix[i]) == dac)
  			return mix[i];
748cce431   Takashi Iwai   ALSA: hda - Fix i...
2778
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
2779
  	return 0;
748cce431   Takashi Iwai   ALSA: hda - Fix i...
2780
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2781
2782
2783
  /* select the connection from pin to DAC if needed */
  static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin,
  			       hda_nid_t dac)
eaa9b3a74   Takashi Iwai   ALSA: hda - Fix c...
2784
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2785
2786
  	hda_nid_t mix[5];
  	int i, num;
eaa9b3a74   Takashi Iwai   ALSA: hda - Fix c...
2787

1d045db96   Takashi Iwai   ALSA: hda - Split...
2788
2789
2790
  	pin = alc_go_down_to_selector(codec, pin);
  	num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix));
  	if (num < 2)
8ed99d976   Takashi Iwai   ALSA: hda - Add d...
2791
  		return 0;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2792
2793
2794
2795
2796
2797
  	for (i = 0; i < num; i++) {
  		if (alc_auto_mix_to_dac(codec, mix[i]) == dac) {
  			snd_hda_codec_update_cache(codec, pin, 0,
  						   AC_VERB_SET_CONNECT_SEL, i);
  			return 0;
  		}
840b64c08   Takashi Iwai   ALSA: hda - Add s...
2798
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
2799
  	return 0;
840b64c08   Takashi Iwai   ALSA: hda - Add s...
2800
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2801
2802
  /* look for an empty DAC slot */
  static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin)
584c0c4c3   Takashi Iwai   ALSA: hda - Initi...
2803
2804
  {
  	struct alc_spec *spec = codec->spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2805
2806
  	hda_nid_t srcs[5];
  	int i, num;
21268961d   Takashi Iwai   ALSA: hda - More ...
2807

1d045db96   Takashi Iwai   ALSA: hda - Split...
2808
2809
2810
2811
2812
2813
2814
  	pin = alc_go_down_to_selector(codec, pin);
  	num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
  	for (i = 0; i < num; i++) {
  		hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
  		if (!nid)
  			continue;
  		if (found_in_nid_list(nid, spec->multiout.dac_nids,
0a34b42b6   Takashi Iwai   ALSA: hda/realtek...
2815
  				      ARRAY_SIZE(spec->private_dac_nids)))
1d045db96   Takashi Iwai   ALSA: hda - Split...
2816
  			continue;
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
2817
2818
2819
  		if (found_in_nid_list(nid, spec->multiout.hp_out_nid,
  				      ARRAY_SIZE(spec->multiout.hp_out_nid)))
  		    continue;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2820
2821
2822
2823
2824
2825
  		if (found_in_nid_list(nid, spec->multiout.extra_out_nid,
  				      ARRAY_SIZE(spec->multiout.extra_out_nid)))
  		    continue;
  		return nid;
  	}
  	return 0;
584c0c4c3   Takashi Iwai   ALSA: hda - Initi...
2826
  }
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
  /* check whether the DAC is reachable from the pin */
  static bool alc_auto_is_dac_reachable(struct hda_codec *codec,
  				      hda_nid_t pin, hda_nid_t dac)
  {
  	hda_nid_t srcs[5];
  	int i, num;
  
  	pin = alc_go_down_to_selector(codec, pin);
  	num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs));
  	for (i = 0; i < num; i++) {
  		hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]);
  		if (nid == dac)
  			return true;
  	}
  	return false;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
2843
  static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
2844
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2845
2846
2847
2848
  	hda_nid_t sel = alc_go_down_to_selector(codec, pin);
  	if (snd_hda_get_conn_list(codec, sel, NULL) == 1)
  		return alc_auto_look_for_dac(codec, pin);
  	return 0;
f9e336f65   Takashi Iwai   ALSA: hda - Unify...
2849
  }
0a34b42b6   Takashi Iwai   ALSA: hda/realtek...
2850
  /* return 0 if no possible DAC is found, 1 if one or more found */
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
  static int alc_auto_fill_extra_dacs(struct hda_codec *codec, int num_outs,
  				    const hda_nid_t *pins, hda_nid_t *dacs)
  {
  	int i;
  
  	if (num_outs && !dacs[0]) {
  		dacs[0] = alc_auto_look_for_dac(codec, pins[0]);
  		if (!dacs[0])
  			return 0;
  	}
  
  	for (i = 1; i < num_outs; i++)
  		dacs[i] = get_dac_if_single(codec, pins[i]);
  	for (i = 1; i < num_outs; i++) {
  		if (!dacs[i])
  			dacs[i] = alc_auto_look_for_dac(codec, pins[i]);
  	}
0a34b42b6   Takashi Iwai   ALSA: hda/realtek...
2868
  	return 1;
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
2869
2870
2871
  }
  
  static int alc_auto_fill_multi_ios(struct hda_codec *codec,
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
2872
  				   unsigned int location, int offset);
fde48a1f8   David Henningsson   ALSA: HDA: Realte...
2873
2874
  static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
  					  hda_nid_t pin, hda_nid_t dac);
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
2875

1d045db96   Takashi Iwai   ALSA: hda - Split...
2876
2877
  /* fill in the dac_nids table from the parsed pin configuration */
  static int alc_auto_fill_dac_nids(struct hda_codec *codec)
21268961d   Takashi Iwai   ALSA: hda - More ...
2878
2879
  {
  	struct alc_spec *spec = codec->spec;
0a34b42b6   Takashi Iwai   ALSA: hda/realtek...
2880
  	struct auto_pin_cfg *cfg = &spec->autocfg;
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
2881
2882
  	unsigned int location, defcfg;
  	int num_pins;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2883
2884
  	bool redone = false;
  	int i;
21268961d   Takashi Iwai   ALSA: hda - More ...
2885

1d045db96   Takashi Iwai   ALSA: hda - Split...
2886
   again:
8f398ae72   Takashi Iwai   ALSA: hda - Fix D...
2887
2888
  	/* set num_dacs once to full for alc_auto_look_for_dac() */
  	spec->multiout.num_dacs = cfg->line_outs;
e23832ac1   Takashi Iwai   ALSA: hda - Suppo...
2889
  	spec->multiout.hp_out_nid[0] = 0;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2890
2891
2892
  	spec->multiout.extra_out_nid[0] = 0;
  	memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
  	spec->multiout.dac_nids = spec->private_dac_nids;
0a34b42b6   Takashi Iwai   ALSA: hda/realtek...
2893
  	spec->multi_ios = 0;
21268961d   Takashi Iwai   ALSA: hda - More ...
2894

1d045db96   Takashi Iwai   ALSA: hda - Split...
2895
2896
2897
2898
2899
2900
  	/* fill hard-wired DACs first */
  	if (!redone) {
  		for (i = 0; i < cfg->line_outs; i++)
  			spec->private_dac_nids[i] =
  				get_dac_if_single(codec, cfg->line_out_pins[i]);
  		if (cfg->hp_outs)
e23832ac1   Takashi Iwai   ALSA: hda - Suppo...
2901
  			spec->multiout.hp_out_nid[0] =
1d045db96   Takashi Iwai   ALSA: hda - Split...
2902
2903
2904
2905
  				get_dac_if_single(codec, cfg->hp_pins[0]);
  		if (cfg->speaker_outs)
  			spec->multiout.extra_out_nid[0] =
  				get_dac_if_single(codec, cfg->speaker_pins[0]);
21268961d   Takashi Iwai   ALSA: hda - More ...
2906
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
  	for (i = 0; i < cfg->line_outs; i++) {
  		hda_nid_t pin = cfg->line_out_pins[i];
  		if (spec->private_dac_nids[i])
  			continue;
  		spec->private_dac_nids[i] = alc_auto_look_for_dac(codec, pin);
  		if (!spec->private_dac_nids[i] && !redone) {
  			/* if we can't find primary DACs, re-probe without
  			 * checking the hard-wired DACs
  			 */
  			redone = true;
  			goto again;
21268961d   Takashi Iwai   ALSA: hda - More ...
2918
2919
  		}
  	}
8f398ae72   Takashi Iwai   ALSA: hda - Fix D...
2920
2921
  	/* re-count num_dacs and squash invalid entries */
  	spec->multiout.num_dacs = 0;
1d045db96   Takashi Iwai   ALSA: hda - Split...
2922
2923
2924
  	for (i = 0; i < cfg->line_outs; i++) {
  		if (spec->private_dac_nids[i])
  			spec->multiout.num_dacs++;
0a34b42b6   Takashi Iwai   ALSA: hda/realtek...
2925
  		else {
1d045db96   Takashi Iwai   ALSA: hda - Split...
2926
2927
2928
  			memmove(spec->private_dac_nids + i,
  				spec->private_dac_nids + i + 1,
  				sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
0a34b42b6   Takashi Iwai   ALSA: hda/realtek...
2929
2930
  			spec->private_dac_nids[cfg->line_outs - 1] = 0;
  		}
1d045db96   Takashi Iwai   ALSA: hda - Split...
2931
  	}
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
2932
2933
  	if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
  		/* try to fill multi-io first */
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
2934
2935
  		defcfg = snd_hda_codec_get_pincfg(codec, cfg->line_out_pins[0]);
  		location = get_defcfg_location(defcfg);
21268961d   Takashi Iwai   ALSA: hda - More ...
2936

07b18f69a   Takashi Iwai   ALSA: hda/realtek...
2937
  		num_pins = alc_auto_fill_multi_ios(codec, location, 0);
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
2938
2939
2940
2941
2942
2943
  		if (num_pins > 0) {
  			spec->multi_ios = num_pins;
  			spec->ext_channel_count = 2;
  			spec->multiout.num_dacs = num_pins + 1;
  		}
  	}
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2944

716eef032   Takashi Iwai   ALSA: hda/realtek...
2945
2946
  	if (cfg->line_out_type != AUTO_PIN_HP_OUT)
  		alc_auto_fill_extra_dacs(codec, cfg->hp_outs, cfg->hp_pins,
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
2947
  				 spec->multiout.hp_out_nid);
0a34b42b6   Takashi Iwai   ALSA: hda/realtek...
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
  	if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
  		int err = alc_auto_fill_extra_dacs(codec, cfg->speaker_outs,
  					cfg->speaker_pins,
  					spec->multiout.extra_out_nid);
  		/* if no speaker volume is assigned, try again as the primary
  		 * output
  		 */
  		if (!err && cfg->speaker_outs > 0 &&
  		    cfg->line_out_type == AUTO_PIN_HP_OUT) {
  			cfg->hp_outs = cfg->line_outs;
  			memcpy(cfg->hp_pins, cfg->line_out_pins,
  			       sizeof(cfg->hp_pins));
  			cfg->line_outs = cfg->speaker_outs;
  			memcpy(cfg->line_out_pins, cfg->speaker_pins,
  			       sizeof(cfg->speaker_pins));
  			cfg->speaker_outs = 0;
  			memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
  			cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
  			redone = false;
  			goto again;
  		}
  	}
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2970

07b18f69a   Takashi Iwai   ALSA: hda/realtek...
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
  	if (!spec->multi_ios &&
  	    cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
  	    cfg->hp_outs) {
  		/* try multi-ios with HP + inputs */
  		defcfg = snd_hda_codec_get_pincfg(codec, cfg->hp_pins[0]);
  		location = get_defcfg_location(defcfg);
  
  		num_pins = alc_auto_fill_multi_ios(codec, location, 1);
  		if (num_pins > 0) {
  			spec->multi_ios = num_pins;
  			spec->ext_channel_count = 2;
  			spec->multiout.num_dacs = num_pins + 1;
  		}
  	}
fde48a1f8   David Henningsson   ALSA: HDA: Realte...
2985
2986
2987
2988
  	if (cfg->line_out_pins[0])
  		spec->vmaster_nid =
  			alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0],
  						 spec->multiout.dac_nids[0]);
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
2989
2990
  	return 0;
  }
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
  static inline unsigned int get_ctl_pos(unsigned int data)
  {
  	hda_nid_t nid = get_amp_nid_(data);
  	unsigned int dir = get_amp_direction_(data);
  	return (nid << 1) | dir;
  }
  
  #define is_ctl_used(bits, data) \
  	test_bit(get_ctl_pos(data), bits)
  #define mark_ctl_usage(bits, data) \
  	set_bit(get_ctl_pos(data), bits)
1d045db96   Takashi Iwai   ALSA: hda - Split...
3002
3003
3004
  static int alc_auto_add_vol_ctl(struct hda_codec *codec,
  			      const char *pfx, int cidx,
  			      hda_nid_t nid, unsigned int chs)
6694635d3   Takashi Iwai   ALSA: hda - Fix A...
3005
  {
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3006
3007
  	struct alc_spec *spec = codec->spec;
  	unsigned int val;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3008
3009
  	if (!nid)
  		return 0;
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3010
3011
3012
3013
  	val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
  	if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */
  		return 0;
  	mark_ctl_usage(spec->vol_ctls, val);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3014
  	return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx,
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3015
  				 val);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3016
  }
6694635d3   Takashi Iwai   ALSA: hda - Fix A...
3017

e29d37781   Takashi Iwai   ALSA: hda/realtek...
3018
3019
3020
3021
3022
3023
3024
3025
3026
  static int alc_auto_add_stereo_vol(struct hda_codec *codec,
  				   const char *pfx, int cidx,
  				   hda_nid_t nid)
  {
  	int chs = 1;
  	if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
  		chs = 3;
  	return alc_auto_add_vol_ctl(codec, pfx, cidx, nid, chs);
  }
21268961d   Takashi Iwai   ALSA: hda - More ...
3027

1d045db96   Takashi Iwai   ALSA: hda - Split...
3028
3029
3030
3031
3032
3033
3034
  /* create a mute-switch for the given mixer widget;
   * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
   */
  static int alc_auto_add_sw_ctl(struct hda_codec *codec,
  			     const char *pfx, int cidx,
  			     hda_nid_t nid, unsigned int chs)
  {
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3035
  	struct alc_spec *spec = codec->spec;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3036
  	int wid_type;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3037
3038
  	int type;
  	unsigned long val;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3039
3040
3041
3042
3043
3044
3045
  	if (!nid)
  		return 0;
  	wid_type = get_wcaps_type(get_wcaps(codec, nid));
  	if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) {
  		type = ALC_CTL_WIDGET_MUTE;
  		val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT);
  	} else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3046
3047
3048
3049
3050
  		type = ALC_CTL_WIDGET_MUTE;
  		val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT);
  	} else {
  		type = ALC_CTL_BIND_MUTE;
  		val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT);
6694635d3   Takashi Iwai   ALSA: hda - Fix A...
3051
  	}
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3052
3053
3054
  	if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */
  		return 0;
  	mark_ctl_usage(spec->sw_ctls, val);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3055
  	return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
6694635d3   Takashi Iwai   ALSA: hda - Fix A...
3056
  }
e29d37781   Takashi Iwai   ALSA: hda/realtek...
3057
3058
3059
3060
3061
3062
3063
3064
  static int alc_auto_add_stereo_sw(struct hda_codec *codec, const char *pfx,
  				  int cidx, hda_nid_t nid)
  {
  	int chs = 1;
  	if (get_wcaps(codec, nid) & AC_WCAP_STEREO)
  		chs = 3;
  	return alc_auto_add_sw_ctl(codec, pfx, cidx, nid, chs);
  }
dc1eae256   Takashi Iwai   ALSA: hda - Add a...
3065

afcd55150   Takashi Iwai   ALSA: hda - Merge...
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
  static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec,
  					   hda_nid_t pin, hda_nid_t dac)
  {
  	hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
  	if (nid_has_mute(codec, pin, HDA_OUTPUT))
  		return pin;
  	else if (mix && nid_has_mute(codec, mix, HDA_INPUT))
  		return mix;
  	else if (nid_has_mute(codec, dac, HDA_OUTPUT))
  		return dac;
  	return 0;
  }
  
  static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec,
  					  hda_nid_t pin, hda_nid_t dac)
  {
  	hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac);
  	if (nid_has_volume(codec, dac, HDA_OUTPUT))
  		return dac;
  	else if (nid_has_volume(codec, mix, HDA_OUTPUT))
  		return mix;
  	else if (nid_has_volume(codec, pin, HDA_OUTPUT))
  		return pin;
  	return 0;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3091
3092
3093
  /* add playback controls from the parsed DAC table */
  static int alc_auto_create_multi_out_ctls(struct hda_codec *codec,
  					     const struct auto_pin_cfg *cfg)
dc1eae256   Takashi Iwai   ALSA: hda - Add a...
3094
3095
  {
  	struct alc_spec *spec = codec->spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3096
  	int i, err, noutputs;
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
3097

1d045db96   Takashi Iwai   ALSA: hda - Split...
3098
3099
3100
  	noutputs = cfg->line_outs;
  	if (spec->multi_ios > 0)
  		noutputs += spec->multi_ios;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3101

1d045db96   Takashi Iwai   ALSA: hda - Split...
3102
3103
3104
  	for (i = 0; i < noutputs; i++) {
  		const char *name;
  		int index;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3105
3106
3107
3108
3109
  		hda_nid_t dac, pin;
  		hda_nid_t sw, vol;
  
  		dac = spec->multiout.dac_nids[i];
  		if (!dac)
1d045db96   Takashi Iwai   ALSA: hda - Split...
3110
3111
3112
3113
3114
  			continue;
  		if (i >= cfg->line_outs)
  			pin = spec->multi_io[i - 1].pin;
  		else
  			pin = cfg->line_out_pins[i];
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3115
3116
3117
  
  		sw = alc_look_for_out_mute_nid(codec, pin, dac);
  		vol = alc_look_for_out_vol_nid(codec, pin, dac);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3118
  		name = alc_get_line_out_pfx(spec, i, true, &index);
9c4e84d3b   Takashi Iwai   ALSA: hda - Fix C...
3119
  		if (!name || !strcmp(name, "CLFE")) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3120
  			/* Center/LFE */
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3121
  			err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3122
3123
  			if (err < 0)
  				return err;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3124
  			err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3125
3126
  			if (err < 0)
  				return err;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3127
  			err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3128
3129
  			if (err < 0)
  				return err;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3130
  			err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3131
3132
3133
  			if (err < 0)
  				return err;
  		} else {
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3134
  			err = alc_auto_add_stereo_vol(codec, name, index, vol);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3135
3136
  			if (err < 0)
  				return err;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3137
  			err = alc_auto_add_stereo_sw(codec, name, index, sw);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3138
3139
  			if (err < 0)
  				return err;
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
3140
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3141
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3142
3143
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3144

1d045db96   Takashi Iwai   ALSA: hda - Split...
3145
  static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
766ddee68   Takashi Iwai   ALSA: hda/realtek...
3146
3147
  				     hda_nid_t dac, const char *pfx,
  				     int cidx)
1d045db96   Takashi Iwai   ALSA: hda - Split...
3148
3149
  {
  	struct alc_spec *spec = codec->spec;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3150
  	hda_nid_t sw, vol;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3151
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3152

1d045db96   Takashi Iwai   ALSA: hda - Split...
3153
  	if (!dac) {
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3154
  		unsigned int val;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3155
3156
3157
3158
  		/* the corresponding DAC is already occupied */
  		if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP))
  			return 0; /* no way */
  		/* create a switch only */
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3159
3160
3161
3162
  		val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT);
  		if (is_ctl_used(spec->sw_ctls, val))
  			return 0; /* already created */
  		mark_ctl_usage(spec->sw_ctls, val);
766ddee68   Takashi Iwai   ALSA: hda/realtek...
3163
  		return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, cidx, val);
e9edcee06   Takashi Iwai   [ALSA] hda-codec ...
3164
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3165

afcd55150   Takashi Iwai   ALSA: hda - Merge...
3166
3167
  	sw = alc_look_for_out_mute_nid(codec, pin, dac);
  	vol = alc_look_for_out_vol_nid(codec, pin, dac);
766ddee68   Takashi Iwai   ALSA: hda/realtek...
3168
  	err = alc_auto_add_stereo_vol(codec, pfx, cidx, vol);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3169
3170
  	if (err < 0)
  		return err;
766ddee68   Takashi Iwai   ALSA: hda/realtek...
3171
  	err = alc_auto_add_stereo_sw(codec, pfx, cidx, sw);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3172
3173
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3174
3175
  	return 0;
  }
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
  static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec,
  					  unsigned int nums,
  					  struct hda_ctl_ops *ops)
  {
  	struct alc_spec *spec = codec->spec;
  	struct hda_bind_ctls **ctlp, *ctl;
  	snd_array_init(&spec->bind_ctls, sizeof(ctl), 8);
  	ctlp = snd_array_new(&spec->bind_ctls);
  	if (!ctlp)
  		return NULL;
  	ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL);
  	*ctlp = ctl;
  	if (ctl)
  		ctl->ops = ops;
  	return ctl;
  }
  
  /* add playback controls for speaker and HP outputs */
  static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins,
  				      const hda_nid_t *pins,
  				      const hda_nid_t *dacs,
  				      const char *pfx)
  {
  	struct alc_spec *spec = codec->spec;
  	struct hda_bind_ctls *ctl;
  	char name[32];
  	int i, n, err;
  
  	if (!num_pins || !pins[0])
  		return 0;
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3206
3207
3208
3209
  	if (num_pins == 1) {
  		hda_nid_t dac = *dacs;
  		if (!dac)
  			dac = spec->multiout.dac_nids[0];
766ddee68   Takashi Iwai   ALSA: hda/realtek...
3210
  		return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0);
527e4d73a   Takashi Iwai   ALSA: hda/realtek...
3211
  	}
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3212
3213
3214
3215
  
  	if (dacs[num_pins - 1]) {
  		/* OK, we have a multi-output system with individual volumes */
  		for (i = 0; i < num_pins; i++) {
766ddee68   Takashi Iwai   ALSA: hda/realtek...
3216
3217
3218
3219
3220
3221
3222
3223
3224
  			if (num_pins >= 3) {
  				snprintf(name, sizeof(name), "%s %s",
  					 pfx, channel_name[i]);
  				err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
  								name, 0);
  			} else {
  				err = alc_auto_create_extra_out(codec, pins[i], dacs[i],
  								pfx, i);
  			}
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
  			if (err < 0)
  				return err;
  		}
  		return 0;
  	}
  
  	/* Let's create a bind-controls */
  	ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_sw);
  	if (!ctl)
  		return -ENOMEM;
  	n = 0;
  	for (i = 0; i < num_pins; i++) {
  		if (get_wcaps(codec, pins[i]) & AC_WCAP_OUT_AMP)
  			ctl->values[n++] =
  				HDA_COMPOSE_AMP_VAL(pins[i], 3, 0, HDA_OUTPUT);
  	}
  	if (n) {
  		snprintf(name, sizeof(name), "%s Playback Switch", pfx);
  		err = add_control(spec, ALC_CTL_BIND_SW, name, 0, (long)ctl);
  		if (err < 0)
  			return err;
  	}
  
  	ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol);
  	if (!ctl)
  		return -ENOMEM;
  	n = 0;
  	for (i = 0; i < num_pins; i++) {
  		hda_nid_t vol;
  		if (!pins[i] || !dacs[i])
  			continue;
  		vol = alc_look_for_out_vol_nid(codec, pins[i], dacs[i]);
  		if (vol)
  			ctl->values[n++] =
  				HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT);
  	}
  	if (n) {
  		snprintf(name, sizeof(name), "%s Playback Volume", pfx);
  		err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl);
  		if (err < 0)
  			return err;
  	}
  	return 0;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3269
  static int alc_auto_create_hp_out(struct hda_codec *codec)
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3270
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3271
  	struct alc_spec *spec = codec->spec;
e23832ac1   Takashi Iwai   ALSA: hda - Suppo...
3272
3273
3274
3275
  	return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs,
  					  spec->autocfg.hp_pins,
  					  spec->multiout.hp_out_nid,
  					  "Headphone");
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3276
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3277
  static int alc_auto_create_speaker_out(struct hda_codec *codec)
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3278
  {
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3279
  	struct alc_spec *spec = codec->spec;
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3280
3281
3282
3283
  	return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs,
  					  spec->autocfg.speaker_pins,
  					  spec->multiout.extra_out_nid,
  					  "Speaker");
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3284
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3285
  static void alc_auto_set_output_and_unmute(struct hda_codec *codec,
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3286
  					      hda_nid_t pin, int pin_type,
1d045db96   Takashi Iwai   ALSA: hda - Split...
3287
  					      hda_nid_t dac)
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3288
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3289
  	int i, num;
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3290
  	hda_nid_t nid, mix = 0;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3291
  	hda_nid_t srcs[HDA_MAX_CONNECTIONS];
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3292

afcd55150   Takashi Iwai   ALSA: hda - Merge...
3293
3294
  	alc_set_pin_output(codec, pin, pin_type);
  	nid = alc_go_down_to_selector(codec, pin);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3295
3296
3297
3298
3299
3300
3301
3302
3303
  	num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs));
  	for (i = 0; i < num; i++) {
  		if (alc_auto_mix_to_dac(codec, srcs[i]) != dac)
  			continue;
  		mix = srcs[i];
  		break;
  	}
  	if (!mix)
  		return;
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3304

1d045db96   Takashi Iwai   ALSA: hda - Split...
3305
3306
3307
3308
  	/* need the manual connection? */
  	if (num > 1)
  		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i);
  	/* unmute mixer widget inputs */
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3309
3310
  	if (nid_has_mute(codec, mix, HDA_INPUT)) {
  		snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1d045db96   Takashi Iwai   ALSA: hda - Split...
3311
  			    AMP_IN_UNMUTE(0));
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3312
  		snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE,
1d045db96   Takashi Iwai   ALSA: hda - Split...
3313
  			    AMP_IN_UNMUTE(1));
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3314
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3315
  	/* initialize volume */
afcd55150   Takashi Iwai   ALSA: hda - Merge...
3316
3317
3318
3319
  	nid = alc_look_for_out_vol_nid(codec, pin, dac);
  	if (nid)
  		snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
  				    AMP_OUT_ZERO);
43dea228a   Takashi Iwai   ALSA: hda - Fix s...
3320
3321
3322
3323
3324
3325
  
  	/* unmute DAC if it's not assigned to a mixer */
  	nid = alc_look_for_out_mute_nid(codec, pin, dac);
  	if (nid == mix && nid_has_mute(codec, dac, HDA_OUTPUT))
  		snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE,
  				    AMP_OUT_ZERO);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3326
  }
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3327

1d045db96   Takashi Iwai   ALSA: hda - Split...
3328
  static void alc_auto_init_multi_out(struct hda_codec *codec)
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3329
3330
  {
  	struct alc_spec *spec = codec->spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3331
3332
  	int pin_type = get_pin_type(spec->autocfg.line_out_type);
  	int i;
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3333

1d045db96   Takashi Iwai   ALSA: hda - Split...
3334
3335
3336
3337
3338
3339
  	for (i = 0; i <= HDA_SIDE; i++) {
  		hda_nid_t nid = spec->autocfg.line_out_pins[i];
  		if (nid)
  			alc_auto_set_output_and_unmute(codec, nid, pin_type,
  					spec->multiout.dac_nids[i]);
  	}
bec15c3a5   Takashi Iwai   [ALSA] hda-codec ...
3340
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3341
  static void alc_auto_init_extra_out(struct hda_codec *codec)
e9427969f   Takashi Iwai   ALSA: hda - Conso...
3342
3343
  {
  	struct alc_spec *spec = codec->spec;
8cd0775da   Takashi Iwai   ALSA: hda - Fix i...
3344
  	int i;
675c1aa3c   Takashi Iwai   ALSA: hda - Fix o...
3345
  	hda_nid_t pin, dac;
e9427969f   Takashi Iwai   ALSA: hda - Conso...
3346

636030e90   David Henningsson   ALSA: HDA: Fixup ...
3347
  	for (i = 0; i < spec->autocfg.hp_outs; i++) {
716eef032   Takashi Iwai   ALSA: hda/realtek...
3348
3349
  		if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
  			break;
e23832ac1   Takashi Iwai   ALSA: hda - Suppo...
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
  		pin = spec->autocfg.hp_pins[i];
  		if (!pin)
  			break;
  		dac = spec->multiout.hp_out_nid[i];
  		if (!dac) {
  			if (i > 0 && spec->multiout.hp_out_nid[0])
  				dac = spec->multiout.hp_out_nid[0];
  			else
  				dac = spec->multiout.dac_nids[0];
  		}
675c1aa3c   Takashi Iwai   ALSA: hda - Fix o...
3360
3361
  		alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac);
  	}
8cd0775da   Takashi Iwai   ALSA: hda - Fix i...
3362
  	for (i = 0; i < spec->autocfg.speaker_outs; i++) {
716eef032   Takashi Iwai   ALSA: hda/realtek...
3363
3364
  		if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
  			break;
8cd0775da   Takashi Iwai   ALSA: hda - Fix i...
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
  		pin = spec->autocfg.speaker_pins[i];
  		if (!pin)
  			break;
  		dac = spec->multiout.extra_out_nid[i];
  		if (!dac) {
  			if (i > 0 && spec->multiout.extra_out_nid[0])
  				dac = spec->multiout.extra_out_nid[0];
  			else
  				dac = spec->multiout.dac_nids[0];
  		}
675c1aa3c   Takashi Iwai   ALSA: hda - Fix o...
3375
3376
  		alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac);
  	}
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
3377
  }
df694daa3   Kailang Yang   [ALSA] hda-codec ...
3378
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
3379
   * multi-io helper
df694daa3   Kailang Yang   [ALSA] hda-codec ...
3380
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
3381
  static int alc_auto_fill_multi_ios(struct hda_codec *codec,
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
3382
3383
  				   unsigned int location,
  				   int offset)
df694daa3   Kailang Yang   [ALSA] hda-codec ...
3384
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3385
3386
  	struct alc_spec *spec = codec->spec;
  	struct auto_pin_cfg *cfg = &spec->autocfg;
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
3387
  	hda_nid_t prime_dac = spec->private_dac_nids[0];
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
3388
  	int type, i, dacs, num_pins = 0;
ea1fb29ac   Kailang Yang   ALSA: hda - fix s...
3389

07b18f69a   Takashi Iwai   ALSA: hda/realtek...
3390
  	dacs = spec->multiout.num_dacs;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3391
3392
3393
  	for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
  		for (i = 0; i < cfg->num_inputs; i++) {
  			hda_nid_t nid = cfg->inputs[i].pin;
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
3394
  			hda_nid_t dac = 0;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
  			unsigned int defcfg, caps;
  			if (cfg->inputs[i].type != type)
  				continue;
  			defcfg = snd_hda_codec_get_pincfg(codec, nid);
  			if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
  				continue;
  			if (location && get_defcfg_location(defcfg) != location)
  				continue;
  			caps = snd_hda_query_pin_caps(codec, nid);
  			if (!(caps & AC_PINCAP_OUT))
  				continue;
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
3406
3407
3408
3409
3410
3411
3412
  			if (offset && offset + num_pins < dacs) {
  				dac = spec->private_dac_nids[offset + num_pins];
  				if (!alc_auto_is_dac_reachable(codec, nid, dac))
  					dac = 0;
  			}
  			if (!dac)
  				dac = alc_auto_look_for_dac(codec, nid);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3413
3414
3415
3416
3417
3418
3419
  			if (!dac)
  				continue;
  			spec->multi_io[num_pins].pin = nid;
  			spec->multi_io[num_pins].dac = dac;
  			num_pins++;
  			spec->private_dac_nids[spec->multiout.num_dacs++] = dac;
  		}
863b45180   Takashi Iwai   ALSA: hda - Fix c...
3420
  	}
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
3421
  	spec->multiout.num_dacs = dacs;
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
3422
3423
  	if (num_pins < 2) {
  		/* clear up again */
07b18f69a   Takashi Iwai   ALSA: hda/realtek...
3424
3425
  		memset(spec->private_dac_nids + dacs, 0,
  		       sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - dacs));
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
3426
  		spec->private_dac_nids[0] = prime_dac;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3427
  		return 0;
c267468e9   Takashi Iwai   ALSA: hda - Prefe...
3428
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3429
  	return num_pins;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3430
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3431
3432
  static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_info *uinfo)
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3433
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3434
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3435
  	struct alc_spec *spec = codec->spec;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3436

1d045db96   Takashi Iwai   ALSA: hda - Split...
3437
3438
3439
3440
3441
3442
3443
3444
3445
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
  	uinfo->count = 1;
  	uinfo->value.enumerated.items = spec->multi_ios + 1;
  	if (uinfo->value.enumerated.item > spec->multi_ios)
  		uinfo->value.enumerated.item = spec->multi_ios;
  	sprintf(uinfo->value.enumerated.name, "%dch",
  		(uinfo->value.enumerated.item + 1) * 2);
  	return 0;
  }
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3446

1d045db96   Takashi Iwai   ALSA: hda - Split...
3447
3448
3449
3450
3451
3452
3453
3454
  static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
  {
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
  	struct alc_spec *spec = codec->spec;
  	ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2;
  	return 0;
  }
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3455

1d045db96   Takashi Iwai   ALSA: hda - Split...
3456
3457
3458
3459
  static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output)
  {
  	struct alc_spec *spec = codec->spec;
  	hda_nid_t nid = spec->multi_io[idx].pin;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3460

1d045db96   Takashi Iwai   ALSA: hda - Split...
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
  	if (!spec->multi_io[idx].ctl_in)
  		spec->multi_io[idx].ctl_in =
  			snd_hda_codec_read(codec, nid, 0,
  					   AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
  	if (output) {
  		snd_hda_codec_update_cache(codec, nid, 0,
  					   AC_VERB_SET_PIN_WIDGET_CONTROL,
  					   PIN_OUT);
  		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
  			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
  						 HDA_AMP_MUTE, 0);
  		alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac);
  	} else {
  		if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)
  			snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0,
  						 HDA_AMP_MUTE, HDA_AMP_MUTE);
  		snd_hda_codec_update_cache(codec, nid, 0,
  					   AC_VERB_SET_PIN_WIDGET_CONTROL,
  					   spec->multi_io[idx].ctl_in);
4f574b7b1   Takashi Iwai   ALSA: hda - More ...
3480
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3481
  	return 0;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3482
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3483
3484
  static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3485
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3486
  	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
f6c7e5461   Takashi Iwai   [ALSA] hda-codec ...
3487
  	struct alc_spec *spec = codec->spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3488
  	int i, ch;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3489

1d045db96   Takashi Iwai   ALSA: hda - Split...
3490
3491
3492
3493
3494
3495
3496
3497
3498
  	ch = ucontrol->value.enumerated.item[0];
  	if (ch < 0 || ch > spec->multi_ios)
  		return -EINVAL;
  	if (ch == (spec->ext_channel_count - 1) / 2)
  		return 0;
  	spec->ext_channel_count = (ch + 1) * 2;
  	for (i = 0; i < spec->multi_ios; i++)
  		alc_set_multi_io(codec, i, i < ch);
  	spec->multiout.max_channels = spec->ext_channel_count;
7b1655f5f   Takashi Iwai   ALSA: hda - Re-ad...
3499
3500
  	if (spec->need_dac_fix && !spec->const_channel_count)
  		spec->multiout.num_dacs = spec->multiout.max_channels / 2;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3501
3502
  	return 1;
  }
3abf2f363   Takashi Iwai   ALSA: hda - Fix p...
3503

1d045db96   Takashi Iwai   ALSA: hda - Split...
3504
3505
3506
3507
3508
3509
  static const struct snd_kcontrol_new alc_auto_channel_mode_enum = {
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "Channel Mode",
  	.info = alc_auto_ch_mode_info,
  	.get = alc_auto_ch_mode_get,
  	.put = alc_auto_ch_mode_put,
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3510
  };
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3511
  static int alc_auto_add_multi_channel_mode(struct hda_codec *codec)
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3512
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3513
  	struct alc_spec *spec = codec->spec;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3514

c267468e9   Takashi Iwai   ALSA: hda - Prefe...
3515
  	if (spec->multi_ios > 0) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3516
  		struct snd_kcontrol_new *knew;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3517

1d045db96   Takashi Iwai   ALSA: hda - Split...
3518
3519
3520
3521
3522
3523
3524
  		knew = alc_kcontrol_new(spec);
  		if (!knew)
  			return -ENOMEM;
  		*knew = alc_auto_channel_mode_enum;
  		knew->name = kstrdup("Channel Mode", GFP_KERNEL);
  		if (!knew->name)
  			return -ENOMEM;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3525
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3526
3527
  	return 0;
  }
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3528

1d045db96   Takashi Iwai   ALSA: hda - Split...
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
  /* filter out invalid adc_nids (and capsrc_nids) that don't give all
   * active input pins
   */
  static void alc_remove_invalid_adc_nids(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	const struct hda_input_mux *imux;
  	hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)];
  	hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)];
  	int i, n, nums;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3539

1d045db96   Takashi Iwai   ALSA: hda - Split...
3540
3541
3542
3543
3544
  	imux = spec->input_mux;
  	if (!imux)
  		return;
  	if (spec->dyn_adc_switch)
  		return;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3545

1d045db96   Takashi Iwai   ALSA: hda - Split...
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
  	nums = 0;
  	for (n = 0; n < spec->num_adc_nids; n++) {
  		hda_nid_t cap = spec->private_capsrc_nids[n];
  		int num_conns = snd_hda_get_conn_list(codec, cap, NULL);
  		for (i = 0; i < imux->num_items; i++) {
  			hda_nid_t pin = spec->imux_pins[i];
  			if (pin) {
  				if (get_connection_index(codec, cap, pin) < 0)
  					break;
  			} else if (num_conns <= imux->items[i].index)
  				break;
  		}
  		if (i >= imux->num_items) {
  			adc_nids[nums] = spec->private_adc_nids[n];
  			capsrc_nids[nums++] = cap;
22971e3a7   Takashi Iwai   ALSA: hda - add d...
3561
3562
  		}
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
  	if (!nums) {
  		/* check whether ADC-switch is possible */
  		if (!alc_check_dyn_adc_switch(codec)) {
  			printk(KERN_WARNING "hda_codec: %s: no valid ADC found;"
  			       " using fallback 0x%x
  ",
  			       codec->chip_name, spec->private_adc_nids[0]);
  			spec->num_adc_nids = 1;
  			spec->auto_mic = 0;
  			return;
22971e3a7   Takashi Iwai   ALSA: hda - add d...
3573
  		}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3574
3575
3576
3577
3578
3579
  	} else if (nums != spec->num_adc_nids) {
  		memcpy(spec->private_adc_nids, adc_nids,
  		       nums * sizeof(hda_nid_t));
  		memcpy(spec->private_capsrc_nids, capsrc_nids,
  		       nums * sizeof(hda_nid_t));
  		spec->num_adc_nids = nums;
22971e3a7   Takashi Iwai   ALSA: hda - add d...
3580
  	}
aef9d318b   Takashi Iwai   [ALSA] hda-codec ...
3581

1d045db96   Takashi Iwai   ALSA: hda - Split...
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
  	if (spec->auto_mic)
  		alc_auto_mic_check_imux(codec); /* check auto-mic setups */
  	else if (spec->input_mux->num_items == 1)
  		spec->num_adc_nids = 1; /* reduce to a single ADC */
  }
  
  /*
   * initialize ADC paths
   */
  static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx)
  {
  	struct alc_spec *spec = codec->spec;
  	hda_nid_t nid;
  
  	nid = spec->adc_nids[adc_idx];
  	/* mute ADC */
44c024005   Takashi Iwai   ALSA: hda - Fix a...
3598
  	if (nid_has_mute(codec, nid, HDA_INPUT)) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3599
3600
3601
3602
  		snd_hda_codec_write(codec, nid, 0,
  				    AC_VERB_SET_AMP_GAIN_MUTE,
  				    AMP_IN_MUTE(0));
  		return;
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3603
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3604
3605
3606
  	if (!spec->capsrc_nids)
  		return;
  	nid = spec->capsrc_nids[adc_idx];
44c024005   Takashi Iwai   ALSA: hda - Fix a...
3607
  	if (nid_has_mute(codec, nid, HDA_OUTPUT))
1d045db96   Takashi Iwai   ALSA: hda - Split...
3608
3609
3610
3611
  		snd_hda_codec_write(codec, nid, 0,
  				    AC_VERB_SET_AMP_GAIN_MUTE,
  				    AMP_OUT_MUTE);
  }
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
3612

1d045db96   Takashi Iwai   ALSA: hda - Split...
3613
3614
3615
3616
  static void alc_auto_init_input_src(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	int c, nums;
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
3617

1d045db96   Takashi Iwai   ALSA: hda - Split...
3618
3619
3620
3621
3622
3623
3624
3625
3626
  	for (c = 0; c < spec->num_adc_nids; c++)
  		alc_auto_init_adc(codec, c);
  	if (spec->dyn_adc_switch)
  		nums = 1;
  	else
  		nums = spec->num_adc_nids;
  	for (c = 0; c < nums; c++)
  		alc_mux_select(codec, 0, spec->cur_mux[c], true);
  }
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
3627

1d045db96   Takashi Iwai   ALSA: hda - Split...
3628
3629
3630
3631
3632
3633
3634
3635
3636
  /* add mic boosts if needed */
  static int alc_auto_add_mic_boost(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	struct auto_pin_cfg *cfg = &spec->autocfg;
  	int i, err;
  	int type_idx = 0;
  	hda_nid_t nid;
  	const char *prev_label = NULL;
ea1fb29ac   Kailang Yang   ALSA: hda - fix s...
3637

1d045db96   Takashi Iwai   ALSA: hda - Split...
3638
3639
3640
3641
3642
3643
3644
3645
3646
  	for (i = 0; i < cfg->num_inputs; i++) {
  		if (cfg->inputs[i].type > AUTO_PIN_MIC)
  			break;
  		nid = cfg->inputs[i].pin;
  		if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) {
  			const char *label;
  			char boost_label[32];
  
  			label = hda_get_autocfg_input_label(codec, cfg, i);
24de183ed   Takashi Iwai   ALSA: hda/realtek...
3647
3648
  			if (spec->shared_mic_hp && !strcmp(label, "Misc"))
  				label = "Headphone Mic";
1d045db96   Takashi Iwai   ALSA: hda - Split...
3649
3650
3651
3652
3653
  			if (prev_label && !strcmp(label, prev_label))
  				type_idx++;
  			else
  				type_idx = 0;
  			prev_label = label;
bf1b02258   Kailang Yang   ALSA: hda - Add a...
3654

1d045db96   Takashi Iwai   ALSA: hda - Split...
3655
3656
3657
3658
3659
3660
3661
3662
3663
  			snprintf(boost_label, sizeof(boost_label),
  				 "%s Boost Volume", label);
  			err = add_control(spec, ALC_CTL_WIDGET_VOL,
  					  boost_label, type_idx,
  				  HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT));
  			if (err < 0)
  				return err;
  		}
  	}
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
3664
3665
  	return 0;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
  /* select or unmute the given capsrc route */
  static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap,
  				    int idx)
  {
  	if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) {
  		snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx,
  					 HDA_AMP_MUTE, 0);
  	} else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) {
  		snd_hda_codec_write_cache(codec, cap, 0,
  					  AC_VERB_SET_CONNECT_SEL, idx);
  	}
  }
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3678

1d045db96   Takashi Iwai   ALSA: hda - Split...
3679
3680
3681
3682
3683
  /* set the default connection to that pin */
  static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin)
  {
  	struct alc_spec *spec = codec->spec;
  	int i;
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3684

1d045db96   Takashi Iwai   ALSA: hda - Split...
3685
3686
3687
  	if (!pin)
  		return 0;
  	for (i = 0; i < spec->num_adc_nids; i++) {
61071594f   Takashi Iwai   ALSA: hda/realtek...
3688
  		hda_nid_t cap = get_capsrc(spec, i);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3689
  		int idx;
f53281e62   Kailang Yang   ALSA: hda - Add s...
3690

1d045db96   Takashi Iwai   ALSA: hda - Split...
3691
3692
3693
3694
3695
3696
3697
3698
  		idx = get_connection_index(codec, cap, pin);
  		if (idx < 0)
  			continue;
  		select_or_unmute_capsrc(codec, cap, idx);
  		return i; /* return the found index */
  	}
  	return -1; /* not found */
  }
e01bf5091   Takashi Iwai   ALSA: hda - Fix A...
3699

1d045db96   Takashi Iwai   ALSA: hda - Split...
3700
3701
3702
3703
3704
  /* initialize some special cases for input sources */
  static void alc_init_special_input_src(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	int i;
84898e87c   Kailang Yang   ALSA: hda - Add A...
3705

1d045db96   Takashi Iwai   ALSA: hda - Split...
3706
3707
3708
  	for (i = 0; i < spec->autocfg.num_inputs; i++)
  		init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin);
  }
84898e87c   Kailang Yang   ALSA: hda - Add A...
3709

1d045db96   Takashi Iwai   ALSA: hda - Split...
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
  /* assign appropriate capture mixers */
  static void set_capture_mixer(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	static const struct snd_kcontrol_new *caps[2][3] = {
  		{ alc_capture_mixer_nosrc1,
  		  alc_capture_mixer_nosrc2,
  		  alc_capture_mixer_nosrc3 },
  		{ alc_capture_mixer1,
  		  alc_capture_mixer2,
  		  alc_capture_mixer3 },
  	};
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3722

1d045db96   Takashi Iwai   ALSA: hda - Split...
3723
  	/* check whether either of ADC or MUX has a volume control */
44c024005   Takashi Iwai   ALSA: hda - Fix a...
3724
  	if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3725
3726
  		if (!spec->capsrc_nids)
  			return; /* no volume */
44c024005   Takashi Iwai   ALSA: hda - Fix a...
3727
  		if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT))
1d045db96   Takashi Iwai   ALSA: hda - Split...
3728
3729
3730
  			return; /* no volume in capsrc, too */
  		spec->vol_in_capsrc = 1;
  	}
60db6b53f   Kailang Yang   ALSA: hda - Add s...
3731

1d045db96   Takashi Iwai   ALSA: hda - Split...
3732
3733
3734
  	if (spec->num_adc_nids > 0) {
  		int mux = 0;
  		int num_adcs = 0;
64154835c   Tony Vroon   ALSA: hda - Add l...
3735

1d045db96   Takashi Iwai   ALSA: hda - Split...
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
  		if (spec->input_mux && spec->input_mux->num_items > 1)
  			mux = 1;
  		if (spec->auto_mic) {
  			num_adcs = 1;
  			mux = 0;
  		} else if (spec->dyn_adc_switch)
  			num_adcs = 1;
  		if (!num_adcs) {
  			if (spec->num_adc_nids > 3)
  				spec->num_adc_nids = 3;
  			else if (!spec->num_adc_nids)
  				return;
  			num_adcs = spec->num_adc_nids;
  		}
  		spec->cap_mixer = caps[mux][num_adcs - 1];
  	}
  }
f53281e62   Kailang Yang   ALSA: hda - Add s...
3753

1d045db96   Takashi Iwai   ALSA: hda - Split...
3754
  /*
e47706295   Takashi Iwai   ALSA: hda - Provi...
3755
3756
3757
3758
3759
   * standard auto-parser initializations
   */
  static void alc_auto_init_std(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
3a93897ea   Takashi Iwai   ALSA: hda - Manag...
3760
  	spec->use_jack_tbl = 1;
e47706295   Takashi Iwai   ALSA: hda - Provi...
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
  	alc_auto_init_multi_out(codec);
  	alc_auto_init_extra_out(codec);
  	alc_auto_init_analog_input(codec);
  	alc_auto_init_input_src(codec);
  	alc_auto_init_digital(codec);
  	if (spec->unsol_event)
  		alc_inithook(codec);
  }
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
3771
3772
3773
3774
3775
   * Digital-beep handlers
   */
  #ifdef CONFIG_SND_HDA_INPUT_BEEP
  #define set_beep_amp(spec, nid, idx, dir) \
  	((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir))
84898e87c   Kailang Yang   ALSA: hda - Add A...
3776

1d045db96   Takashi Iwai   ALSA: hda - Split...
3777
3778
3779
3780
3781
3782
3783
  static const struct snd_pci_quirk beep_white_list[] = {
  	SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
  	SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
  	SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
  	SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
  	SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
  	{}
fe3eb0a73   Kailang Yang   ALSA: hda - Add s...
3784
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
  static inline int has_cdefine_beep(struct hda_codec *codec)
  {
  	struct alc_spec *spec = codec->spec;
  	const struct snd_pci_quirk *q;
  	q = snd_pci_quirk_lookup(codec->bus->pci, beep_white_list);
  	if (q)
  		return q->value;
  	return spec->cdefine.enable_pcbeep;
  }
  #else
  #define set_beep_amp(spec, nid, idx, dir) /* NOP */
  #define has_cdefine_beep(codec)		0
  #endif
84898e87c   Kailang Yang   ALSA: hda - Add A...
3798

1d045db96   Takashi Iwai   ALSA: hda - Split...
3799
3800
3801
3802
  /* parse the BIOS configuration and set up the alc_spec */
  /* return 1 if successful, 0 if the proper config is not found,
   * or a negative error code
   */
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
3803
3804
3805
  static int alc_parse_auto_config(struct hda_codec *codec,
  				 const hda_nid_t *ignore_nids,
  				 const hda_nid_t *ssid_nids)
1d045db96   Takashi Iwai   ALSA: hda - Split...
3806
3807
  {
  	struct alc_spec *spec = codec->spec;
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3808
  	struct auto_pin_cfg *cfg = &spec->autocfg;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3809
  	int err;
26f5df265   Takashi Iwai   ALSA: hda - Add A...
3810

53c334add   Takashi Iwai   ALSA: hda - Rewri...
3811
3812
  	err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
  				       spec->parse_flags);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3813
3814
  	if (err < 0)
  		return err;
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3815
3816
  	if (!cfg->line_outs) {
  		if (cfg->dig_outs || cfg->dig_in_pin) {
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
3817
3818
3819
3820
  			spec->multiout.max_channels = 2;
  			spec->no_analog = 1;
  			goto dig_only;
  		}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3821
  		return 0; /* can't find valid BIOS pin config */
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
3822
  	}
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3823

06503670a   Takashi Iwai   ALSA: hda/realtek...
3824
3825
  	if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
  	    cfg->line_outs <= cfg->hp_outs) {
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3826
3827
3828
3829
3830
3831
3832
3833
3834
3835
  		/* use HP as primary out */
  		cfg->speaker_outs = cfg->line_outs;
  		memcpy(cfg->speaker_pins, cfg->line_out_pins,
  		       sizeof(cfg->speaker_pins));
  		cfg->line_outs = cfg->hp_outs;
  		memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
  		cfg->hp_outs = 0;
  		memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
  		cfg->line_out_type = AUTO_PIN_HP_OUT;
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
3836
3837
3838
  	err = alc_auto_fill_dac_nids(codec);
  	if (err < 0)
  		return err;
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3839
3840
3841
  	err = alc_auto_add_multi_channel_mode(codec);
  	if (err < 0)
  		return err;
23c09b009   Takashi Iwai   ALSA: hda - Suppo...
3842
  	err = alc_auto_create_multi_out_ctls(codec, cfg);
1d045db96   Takashi Iwai   ALSA: hda - Split...
3843
3844
3845
3846
3847
3848
3849
3850
  	if (err < 0)
  		return err;
  	err = alc_auto_create_hp_out(codec);
  	if (err < 0)
  		return err;
  	err = alc_auto_create_speaker_out(codec);
  	if (err < 0)
  		return err;
24de183ed   Takashi Iwai   ALSA: hda/realtek...
3851
3852
3853
  	err = alc_auto_create_shared_input(codec);
  	if (err < 0)
  		return err;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3854
3855
3856
  	err = alc_auto_create_input_ctls(codec);
  	if (err < 0)
  		return err;
84898e87c   Kailang Yang   ALSA: hda - Add A...
3857

1d045db96   Takashi Iwai   ALSA: hda - Split...
3858
  	spec->multiout.max_channels = spec->multiout.num_dacs * 2;
f53281e62   Kailang Yang   ALSA: hda - Add s...
3859

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
3860
   dig_only:
1d045db96   Takashi Iwai   ALSA: hda - Split...
3861
  	alc_auto_parse_digital(codec);
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3862

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
3863
3864
3865
3866
3867
  	if (!spec->no_analog)
  		alc_remove_invalid_adc_nids(codec);
  
  	if (ssid_nids)
  		alc_ssid_check(codec, ssid_nids);
64154835c   Tony Vroon   ALSA: hda - Add l...
3868

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
3869
3870
3871
3872
3873
3874
  	if (!spec->no_analog) {
  		alc_auto_check_switches(codec);
  		err = alc_auto_add_mic_boost(codec);
  		if (err < 0)
  			return err;
  	}
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3875

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
3876
3877
  	if (spec->kctls.list)
  		add_mixer(spec, spec->kctls.list);
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3878

1d045db96   Takashi Iwai   ALSA: hda - Split...
3879
  	return 1;
60db6b53f   Kailang Yang   ALSA: hda - Add s...
3880
  }
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3881

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
3882
3883
3884
3885
3886
3887
  static int alc880_parse_auto_config(struct hda_codec *codec)
  {
  	static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
  	static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 }; 
  	return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  static const struct hda_amp_list alc880_loopbacks[] = {
  	{ 0x0b, HDA_INPUT, 0 },
  	{ 0x0b, HDA_INPUT, 1 },
  	{ 0x0b, HDA_INPUT, 2 },
  	{ 0x0b, HDA_INPUT, 3 },
  	{ 0x0b, HDA_INPUT, 4 },
  	{ } /* end */
  };
  #endif
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3898

1d045db96   Takashi Iwai   ALSA: hda - Split...
3899
  /*
ee3b29693   Takashi Iwai   ALSA: hda/realtek...
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
3912
3913
3914
3915
3916
3917
3918
3919
3920
3921
3922
3923
3924
3925
3926
3927
3928
3929
3930
   * ALC880 fix-ups
   */
  enum {
  	ALC880_FIXUP_GPIO2,
  	ALC880_FIXUP_MEDION_RIM,
  };
  
  static const struct alc_fixup alc880_fixups[] = {
  	[ALC880_FIXUP_GPIO2] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = alc_gpio2_init_verbs,
  	},
  	[ALC880_FIXUP_MEDION_RIM] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
  			{ 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC880_FIXUP_GPIO2,
  	},
  };
  
  static const struct snd_pci_quirk alc880_fixup_tbl[] = {
  	SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
  	{}
  };
  
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
3931
3932
3933
3934
3935
3936
3937
3938
3939
3940
3941
3942
3943
   * board setups
   */
  #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
  #define alc_board_config \
  	snd_hda_check_board_config
  #define alc_board_codec_sid_config \
  	snd_hda_check_board_codec_sid_config
  #include "alc_quirks.c"
  #else
  #define alc_board_config(codec, nums, models, tbl)	-1
  #define alc_board_codec_sid_config(codec, nums, models, tbl)	-1
  #define setup_preset(codec, x)	/* NOP */
  #endif
64154835c   Tony Vroon   ALSA: hda - Add l...
3944

1d045db96   Takashi Iwai   ALSA: hda - Split...
3945
3946
3947
3948
3949
3950
  /*
   * OK, here we have finally the patch for ALC880
   */
  #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
  #include "alc880_quirks.c"
  #endif
4f5d17062   Takashi Iwai   ALSA: hda - Clean...
3951

1d045db96   Takashi Iwai   ALSA: hda - Split...
3952
  static int patch_alc880(struct hda_codec *codec)
60db6b53f   Kailang Yang   ALSA: hda - Add s...
3953
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3954
3955
3956
  	struct alc_spec *spec;
  	int board_config;
  	int err;
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
3957

1d045db96   Takashi Iwai   ALSA: hda - Split...
3958
3959
3960
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (spec == NULL)
  		return -ENOMEM;
3b8510ce9   Takashi Iwai   ALSA: hda - Add c...
3961

1d045db96   Takashi Iwai   ALSA: hda - Split...
3962
  	codec->spec = spec;
64154835c   Tony Vroon   ALSA: hda - Add l...
3963

1d045db96   Takashi Iwai   ALSA: hda - Split...
3964
  	spec->mixer_nid = 0x0b;
7b1655f5f   Takashi Iwai   ALSA: hda - Re-ad...
3965
  	spec->need_dac_fix = 1;
f53281e62   Kailang Yang   ALSA: hda - Add s...
3966

1d045db96   Takashi Iwai   ALSA: hda - Split...
3967
3968
3969
3970
3971
3972
3973
3974
  	board_config = alc_board_config(codec, ALC880_MODEL_LAST,
  					alc880_models, alc880_cfg_tbl);
  	if (board_config < 0) {
  		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.
  ",
  		       codec->chip_name);
  		board_config = ALC_MODEL_AUTO;
  	}
f53281e62   Kailang Yang   ALSA: hda - Add s...
3975

1d045db96   Takashi Iwai   ALSA: hda - Split...
3976
  	if (board_config == ALC_MODEL_AUTO) {
ee3b29693   Takashi Iwai   ALSA: hda/realtek...
3977
3978
3979
3980
3981
  		alc_pick_fixup(codec, NULL, alc880_fixup_tbl, alc880_fixups);
  		alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
  	}
  
  	if (board_config == ALC_MODEL_AUTO) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
3982
3983
  		/* automatic parse from the BIOS config */
  		err = alc880_parse_auto_config(codec);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
3984
3985
  		if (err < 0)
  			goto error;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3986
3987
3988
3989
3990
3991
3992
3993
3994
3995
  #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
  		else if (!err) {
  			printk(KERN_INFO
  			       "hda_codec: Cannot set up configuration "
  			       "from BIOS.  Using 3-stack mode...
  ");
  			board_config = ALC880_3ST;
  		}
  #endif
  	}
84898e87c   Kailang Yang   ALSA: hda - Add A...
3996

fde48a1f8   David Henningsson   ALSA: HDA: Realte...
3997
3998
  	if (board_config != ALC_MODEL_AUTO) {
  		spec->vmaster_nid = 0x0c;
1d045db96   Takashi Iwai   ALSA: hda - Split...
3999
  		setup_preset(codec, &alc880_presets[board_config]);
fde48a1f8   David Henningsson   ALSA: HDA: Realte...
4000
  	}
fe3eb0a73   Kailang Yang   ALSA: hda - Add s...
4001

60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
4002
  	if (!spec->no_analog && !spec->adc_nids) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4003
4004
4005
4006
  		alc_auto_fill_adc_caps(codec);
  		alc_rebuild_imux_for_auto_mic(codec);
  		alc_remove_invalid_adc_nids(codec);
  	}
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4007
4008
4009
4010
4011
4012
  
  	if (!spec->no_analog && !spec->cap_mixer)
  		set_capture_mixer(codec);
  
  	if (!spec->no_analog) {
  		err = snd_hda_attach_beep_device(codec, 0x1);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4013
4014
  		if (err < 0)
  			goto error;
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4015
4016
  		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
  	}
f53281e62   Kailang Yang   ALSA: hda - Add s...
4017

ee3b29693   Takashi Iwai   ALSA: hda/realtek...
4018
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
1d045db96   Takashi Iwai   ALSA: hda - Split...
4019
4020
  	codec->patch_ops = alc_patch_ops;
  	if (board_config == ALC_MODEL_AUTO)
e47706295   Takashi Iwai   ALSA: hda - Provi...
4021
  		spec->init_hook = alc_auto_init_std;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4022
4023
4024
4025
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  	if (!spec->loopback.amplist)
  		spec->loopback.amplist = alc880_loopbacks;
  #endif
f53281e62   Kailang Yang   ALSA: hda - Add s...
4026

1d045db96   Takashi Iwai   ALSA: hda - Split...
4027
  	return 0;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4028
4029
4030
4031
  
   error:
  	alc_free(codec);
  	return err;
226b1ec8c   Kailang Yang   ALSA: hda - Fix s...
4032
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
4033

60db6b53f   Kailang Yang   ALSA: hda - Add s...
4034
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
4035
   * ALC260 support
60db6b53f   Kailang Yang   ALSA: hda - Add s...
4036
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4037
  static int alc260_parse_auto_config(struct hda_codec *codec)
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4038
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4039
  	static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4040
4041
  	static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
  	return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4042
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
4043
4044
4045
4046
4047
4048
4049
4050
4051
4052
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  static const struct hda_amp_list alc260_loopbacks[] = {
  	{ 0x07, HDA_INPUT, 0 },
  	{ 0x07, HDA_INPUT, 1 },
  	{ 0x07, HDA_INPUT, 2 },
  	{ 0x07, HDA_INPUT, 3 },
  	{ 0x07, HDA_INPUT, 4 },
  	{ } /* end */
  };
  #endif
0ec33d1f9   Takashi Iwai   ALSA: hda - Refac...
4053

1d045db96   Takashi Iwai   ALSA: hda - Split...
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
  /*
   * Pin config fixes
   */
  enum {
  	PINFIX_HP_DC5750,
  };
  
  static const struct alc_fixup alc260_fixups[] = {
  	[PINFIX_HP_DC5750] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x11, 0x90130110 }, /* speaker */
  			{ }
  		}
  	},
  };
  
  static const struct snd_pci_quirk alc260_fixup_tbl[] = {
  	SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", PINFIX_HP_DC5750),
  	{}
  };
  
  /*
   */
  #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
  #include "alc260_quirks.c"
  #endif
  
  static int patch_alc260(struct hda_codec *codec)
977ddd6b2   Kailang Yang   ALSA: hda - Set u...
4083
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
  	struct alc_spec *spec;
  	int err, board_config;
  
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (spec == NULL)
  		return -ENOMEM;
  
  	codec->spec = spec;
  
  	spec->mixer_nid = 0x07;
  
  	board_config = alc_board_config(codec, ALC260_MODEL_LAST,
  					alc260_models, alc260_cfg_tbl);
  	if (board_config < 0) {
  		snd_printd(KERN_INFO "hda_codec: %s: BIOS auto-probing.
  ",
  			   codec->chip_name);
  		board_config = ALC_MODEL_AUTO;
977ddd6b2   Kailang Yang   ALSA: hda - Set u...
4102
  	}
0ec33d1f9   Takashi Iwai   ALSA: hda - Refac...
4103

1d045db96   Takashi Iwai   ALSA: hda - Split...
4104
4105
4106
  	if (board_config == ALC_MODEL_AUTO) {
  		alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups);
  		alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
977ddd6b2   Kailang Yang   ALSA: hda - Set u...
4107
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
4108
4109
4110
  	if (board_config == ALC_MODEL_AUTO) {
  		/* automatic parse from the BIOS config */
  		err = alc260_parse_auto_config(codec);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4111
4112
  		if (err < 0)
  			goto error;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4113
4114
4115
4116
4117
4118
4119
4120
4121
4122
  #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
  		else if (!err) {
  			printk(KERN_INFO
  			       "hda_codec: Cannot set up configuration "
  			       "from BIOS.  Using base mode...
  ");
  			board_config = ALC260_BASIC;
  		}
  #endif
  	}
977ddd6b2   Kailang Yang   ALSA: hda - Set u...
4123

fde48a1f8   David Henningsson   ALSA: HDA: Realte...
4124
  	if (board_config != ALC_MODEL_AUTO) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4125
  		setup_preset(codec, &alc260_presets[board_config]);
fde48a1f8   David Henningsson   ALSA: HDA: Realte...
4126
4127
  		spec->vmaster_nid = 0x08;
  	}
977ddd6b2   Kailang Yang   ALSA: hda - Set u...
4128

60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
4129
  	if (!spec->no_analog && !spec->adc_nids) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4130
4131
4132
4133
  		alc_auto_fill_adc_caps(codec);
  		alc_rebuild_imux_for_auto_mic(codec);
  		alc_remove_invalid_adc_nids(codec);
  	}
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4134
4135
4136
4137
4138
4139
  
  	if (!spec->no_analog && !spec->cap_mixer)
  		set_capture_mixer(codec);
  
  	if (!spec->no_analog) {
  		err = snd_hda_attach_beep_device(codec, 0x1);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4140
4141
  		if (err < 0)
  			goto error;
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4142
4143
  		set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
  	}
977ddd6b2   Kailang Yang   ALSA: hda - Set u...
4144

1d045db96   Takashi Iwai   ALSA: hda - Split...
4145
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
1a99d4a46   Kailang Yang   ALSA: hda - Fix A...
4146

1d045db96   Takashi Iwai   ALSA: hda - Split...
4147
4148
  	codec->patch_ops = alc_patch_ops;
  	if (board_config == ALC_MODEL_AUTO)
8452a982f   Takashi Iwai   ALSA: hda - Merge...
4149
  		spec->init_hook = alc_auto_init_std;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4150
4151
4152
4153
4154
  	spec->shutup = alc_eapd_shutup;
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  	if (!spec->loopback.amplist)
  		spec->loopback.amplist = alc260_loopbacks;
  #endif
6981d1843   Takashi Iwai   ALSA: hda - Add a...
4155

1d045db96   Takashi Iwai   ALSA: hda - Split...
4156
  	return 0;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4157
4158
4159
4160
  
   error:
  	alc_free(codec);
  	return err;
6981d1843   Takashi Iwai   ALSA: hda - Add a...
4161
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
4162
4163
4164
4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175
4176
4177
4178
4179
4180
  
  /*
   * ALC882/883/885/888/889 support
   *
   * ALC882 is almost identical with ALC880 but has cleaner and more flexible
   * configuration.  Each pin widget can choose any input DACs and a mixer.
   * Each ADC is connected from a mixer of all inputs.  This makes possible
   * 6-channel independent captures.
   *
   * In addition, an independent DAC for the multi-playback (not used in this
   * driver yet).
   */
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  #define alc882_loopbacks	alc880_loopbacks
  #endif
  
  /*
   * Pin config fixes
   */
ff818c24c   Takashi Iwai   ALSA: hda - Add f...
4181
  enum {
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4182
4183
4184
4185
4186
4187
  	ALC882_FIXUP_ABIT_AW9D_MAX,
  	ALC882_FIXUP_LENOVO_Y530,
  	ALC882_FIXUP_PB_M5210,
  	ALC882_FIXUP_ACER_ASPIRE_7736,
  	ALC882_FIXUP_ASUS_W90V,
  	ALC889_FIXUP_VAIO_TT,
0e7cc2e74   Takashi Iwai   ALSA: hda/realtek...
4188
  	ALC888_FIXUP_EEE1601,
177943a39   Takashi Iwai   ALSA: hda/realtek...
4189
  	ALC882_FIXUP_EAPD,
7a6069bf6   Takashi Iwai   ALSA: hda/realtek...
4190
  	ALC883_FIXUP_EAPD,
8812c4f96   Takashi Iwai   ALSA: hda/realtek...
4191
  	ALC883_FIXUP_ACER_EAPD,
eb844d51c   Takashi Iwai   ALSA: hda/realtek...
4192
  	ALC882_FIXUP_GPIO3,
68ef0561e   Takashi Iwai   ALSA: hda/realtek...
4193
4194
  	ALC889_FIXUP_COEF,
  	ALC882_FIXUP_ASUS_W2JC,
c3e837bbc   Takashi Iwai   ALSA: hda/realtek...
4195
4196
4197
  	ALC882_FIXUP_ACER_ASPIRE_4930G,
  	ALC882_FIXUP_ACER_ASPIRE_8930G,
  	ALC882_FIXUP_ASPIRE_8930G_VERBS,
5671087ff   Takashi Iwai   ALSA: hda/realtek...
4198
  	ALC885_FIXUP_MACPRO_GPIO,
ff818c24c   Takashi Iwai   ALSA: hda - Add f...
4199
  };
68ef0561e   Takashi Iwai   ALSA: hda/realtek...
4200
4201
4202
4203
4204
4205
4206
  static void alc889_fixup_coef(struct hda_codec *codec,
  			      const struct alc_fixup *fix, int action)
  {
  	if (action != ALC_FIXUP_ACT_INIT)
  		return;
  	alc889_coef_init(codec);
  }
5671087ff   Takashi Iwai   ALSA: hda/realtek...
4207
4208
4209
4210
4211
4212
4213
4214
4215
4216
4217
4218
4219
4220
4221
4222
4223
4224
4225
4226
4227
4228
4229
4230
4231
4232
4233
4234
4235
4236
4237
4238
4239
4240
4241
4242
4243
4244
4245
4246
4247
4248
  /* toggle speaker-output according to the hp-jack state */
  static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted)
  {
  	unsigned int gpiostate, gpiomask, gpiodir;
  
  	gpiostate = snd_hda_codec_read(codec, codec->afg, 0,
  				       AC_VERB_GET_GPIO_DATA, 0);
  
  	if (!muted)
  		gpiostate |= (1 << pin);
  	else
  		gpiostate &= ~(1 << pin);
  
  	gpiomask = snd_hda_codec_read(codec, codec->afg, 0,
  				      AC_VERB_GET_GPIO_MASK, 0);
  	gpiomask |= (1 << pin);
  
  	gpiodir = snd_hda_codec_read(codec, codec->afg, 0,
  				     AC_VERB_GET_GPIO_DIRECTION, 0);
  	gpiodir |= (1 << pin);
  
  
  	snd_hda_codec_write(codec, codec->afg, 0,
  			    AC_VERB_SET_GPIO_MASK, gpiomask);
  	snd_hda_codec_write(codec, codec->afg, 0,
  			    AC_VERB_SET_GPIO_DIRECTION, gpiodir);
  
  	msleep(1);
  
  	snd_hda_codec_write(codec, codec->afg, 0,
  			    AC_VERB_SET_GPIO_DATA, gpiostate);
  }
  
  /* set up GPIO at initialization */
  static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
  				     const struct alc_fixup *fix, int action)
  {
  	if (action != ALC_FIXUP_ACT_INIT)
  		return;
  	alc882_gpio_mute(codec, 0, 0);
  	alc882_gpio_mute(codec, 1, 0);
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
4249
  static const struct alc_fixup alc882_fixups[] = {
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4250
  	[ALC882_FIXUP_ABIT_AW9D_MAX] = {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4251
4252
4253
4254
4255
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x15, 0x01080104 }, /* side */
  			{ 0x16, 0x01011012 }, /* rear */
  			{ 0x17, 0x01016011 }, /* clfe */
2785591a9   Kailang Yang   ALSA: hda - Add f...
4256
  			{ }
145a902bf   David Henningsson   ALSA: HDA: Enable...
4257
4258
  		}
  	},
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4259
  	[ALC882_FIXUP_LENOVO_Y530] = {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
4260
4261
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4262
4263
  			{ 0x15, 0x99130112 }, /* rear int speakers */
  			{ 0x16, 0x99130111 }, /* subwoofer */
ac6124079   David Henningsson   ALSA: HDA: Enable...
4264
4265
4266
  			{ }
  		}
  	},
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4267
  	[ALC882_FIXUP_PB_M5210] = {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
4268
4269
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4270
  			{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
357f915ec   Kailang Yang   ALSA: hda - Fix E...
4271
4272
4273
  			{}
  		}
  	},
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4274
  	[ALC882_FIXUP_ACER_ASPIRE_7736] = {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4275
4276
  		.type = ALC_FIXUP_SKU,
  		.v.sku = ALC_FIXUP_SKU_IGNORE,
6981d1843   Takashi Iwai   ALSA: hda - Add a...
4277
  	},
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4278
  	[ALC882_FIXUP_ASUS_W90V] = {
5cdf745eb   Takashi Iwai   ALSA: hda - Fix p...
4279
4280
4281
4282
4283
4284
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x16, 0x99130110 }, /* fix sequence for CLFE */
  			{ }
  		}
  	},
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4285
4286
4287
4288
4289
4290
4291
  	[ALC889_FIXUP_VAIO_TT] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x17, 0x90170111 }, /* hidden surround speaker */
  			{ }
  		}
  	},
0e7cc2e74   Takashi Iwai   ALSA: hda/realtek...
4292
4293
4294
4295
4296
4297
4298
  	[ALC888_FIXUP_EEE1601] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
  			{ 0x20, AC_VERB_SET_PROC_COEF,  0x0838 },
  			{ }
  		}
177943a39   Takashi Iwai   ALSA: hda/realtek...
4299
4300
4301
4302
4303
4304
4305
4306
4307
4308
  	},
  	[ALC882_FIXUP_EAPD] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			/* change to EAPD mode */
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
  			{ }
  		}
  	},
7a6069bf6   Takashi Iwai   ALSA: hda/realtek...
4309
4310
4311
4312
4313
4314
4315
4316
4317
  	[ALC883_FIXUP_EAPD] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			/* change to EAPD mode */
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
  			{ }
  		}
  	},
8812c4f96   Takashi Iwai   ALSA: hda/realtek...
4318
4319
4320
4321
4322
4323
4324
4325
4326
  	[ALC883_FIXUP_ACER_EAPD] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			/* eanable EAPD on Acer laptops */
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
  			{ }
  		}
  	},
eb844d51c   Takashi Iwai   ALSA: hda/realtek...
4327
4328
4329
4330
  	[ALC882_FIXUP_GPIO3] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = alc_gpio3_init_verbs,
  	},
68ef0561e   Takashi Iwai   ALSA: hda/realtek...
4331
4332
4333
4334
4335
4336
4337
4338
4339
4340
  	[ALC882_FIXUP_ASUS_W2JC] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = alc_gpio1_init_verbs,
  		.chained = true,
  		.chain_id = ALC882_FIXUP_EAPD,
  	},
  	[ALC889_FIXUP_COEF] = {
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc889_fixup_coef,
  	},
c3e837bbc   Takashi Iwai   ALSA: hda/realtek...
4341
4342
4343
4344
4345
4346
4347
4348
4349
4350
4351
4352
4353
4354
4355
4356
4357
4358
4359
4360
4361
4362
4363
4364
4365
4366
4367
4368
4369
4370
4371
4372
4373
4374
4375
4376
4377
4378
4379
4380
4381
4382
4383
4384
4385
4386
4387
4388
4389
4390
4391
  	[ALC882_FIXUP_ACER_ASPIRE_4930G] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x16, 0x99130111 }, /* CLFE speaker */
  			{ 0x17, 0x99130112 }, /* surround speaker */
  			{ }
  		}
  	},
  	[ALC882_FIXUP_ACER_ASPIRE_8930G] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x16, 0x99130111 }, /* CLFE speaker */
  			{ 0x1b, 0x99130112 }, /* surround speaker */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
  	},
  	[ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
  		/* additional init verbs for Acer Aspire 8930G */
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			/* Enable all DACs */
  			/* DAC DISABLE/MUTE 1? */
  			/*  setting bits 1-5 disables DAC nids 0x02-0x06
  			 *  apparently. Init=0x38 */
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
  			/* DAC DISABLE/MUTE 2? */
  			/*  some bit here disables the other DACs.
  			 *  Init=0x4900 */
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
  			/* DMIC fix
  			 * This laptop has a stereo digital microphone.
  			 * The mics are only 1cm apart which makes the stereo
  			 * useless. However, either the mic or the ALC889
  			 * makes the signal become a difference/sum signal
  			 * instead of standard stereo, which is annoying.
  			 * So instead we flip this bit which makes the
  			 * codec replicate the sum signal to both channels,
  			 * turning it into a normal mono mic.
  			 */
  			/* DMIC_CONTROL? Init value = 0x0001 */
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
  			{ }
  		}
  	},
5671087ff   Takashi Iwai   ALSA: hda/realtek...
4392
4393
4394
4395
  	[ALC885_FIXUP_MACPRO_GPIO] = {
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc885_fixup_macpro_gpio,
  	},
ff818c24c   Takashi Iwai   ALSA: hda - Add f...
4396
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
4397
  static const struct snd_pci_quirk alc882_fixup_tbl[] = {
8812c4f96   Takashi Iwai   ALSA: hda/realtek...
4398
4399
4400
4401
4402
4403
  	SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
  	SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
  	SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
  	SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
  	SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
  	SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
c3e837bbc   Takashi Iwai   ALSA: hda/realtek...
4404
4405
4406
4407
4408
4409
4410
4411
4412
4413
4414
4415
4416
4417
  	SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
  		      ALC882_FIXUP_ACER_ASPIRE_4930G),
  	SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
  		      ALC882_FIXUP_ACER_ASPIRE_4930G),
  	SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
  		      ALC882_FIXUP_ACER_ASPIRE_8930G),
  	SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
  		      ALC882_FIXUP_ACER_ASPIRE_8930G),
  	SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
  		      ALC882_FIXUP_ACER_ASPIRE_4930G),
  	SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
  		      ALC882_FIXUP_ACER_ASPIRE_4930G),
  	SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
  		      ALC882_FIXUP_ACER_ASPIRE_4930G),
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4418
  	SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
ac9b1cddf   Takashi Iwai   ALSA: hda/realtek...
4419
  	SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
177943a39   Takashi Iwai   ALSA: hda/realtek...
4420
  	SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4421
  	SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
68ef0561e   Takashi Iwai   ALSA: hda/realtek...
4422
  	SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
0e7cc2e74   Takashi Iwai   ALSA: hda/realtek...
4423
  	SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
ac9b1cddf   Takashi Iwai   ALSA: hda/realtek...
4424
  	SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
5671087ff   Takashi Iwai   ALSA: hda/realtek...
4425
4426
4427
4428
4429
4430
4431
  
  	/* All Apple entries are in codec SSIDs */
  	SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO),
  	SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
  	SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
  	SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
  	SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
7a6069bf6   Takashi Iwai   ALSA: hda/realtek...
4432
  	SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
eb844d51c   Takashi Iwai   ALSA: hda/realtek...
4433
  	SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
5c0ebfbe5   Takashi Iwai   ALSA: hda/realtek...
4434
  	SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
7a6069bf6   Takashi Iwai   ALSA: hda/realtek...
4435
4436
  	SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
  	SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
ac9b1cddf   Takashi Iwai   ALSA: hda/realtek...
4437
  	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
68ef0561e   Takashi Iwai   ALSA: hda/realtek...
4438
  	SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
ff818c24c   Takashi Iwai   ALSA: hda - Add f...
4439
4440
  	{}
  };
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4441
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
4442
   * BIOS auto configuration
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4443
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4444
4445
4446
  /* almost identical with ALC880 parser... */
  static int alc882_parse_auto_config(struct hda_codec *codec)
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4447
  	static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4448
4449
  	static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
  	return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
1d045db96   Takashi Iwai   ALSA: hda - Split...
4450
  }
b896b4ebf   Kailang Yang   ALSA: hda - Fix n...
4451

1d045db96   Takashi Iwai   ALSA: hda - Split...
4452
4453
4454
4455
4456
4457
4458
  /*
   */
  #ifdef CONFIG_SND_HDA_ENABLE_REALTEK_QUIRKS
  #include "alc882_quirks.c"
  #endif
  
  static int patch_alc882(struct hda_codec *codec)
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4459
4460
  {
  	struct alc_spec *spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4461
  	int err, board_config;
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4462
4463
4464
4465
4466
4467
  
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (spec == NULL)
  		return -ENOMEM;
  
  	codec->spec = spec;
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
4468
  	spec->mixer_nid = 0x0b;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4469
4470
4471
4472
4473
4474
4475
4476
  	switch (codec->vendor_id) {
  	case 0x10ec0882:
  	case 0x10ec0885:
  		break;
  	default:
  		/* ALC883 and variants */
  		alc_fix_pll_init(codec, 0x20, 0x0a, 10);
  		break;
c793bec55   Kailang Yang   ALSA: hda - Don't...
4477
  	}
977ddd6b2   Kailang Yang   ALSA: hda - Set u...
4478

e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4479
4480
4481
  	err = alc_codec_rename_from_preset(codec);
  	if (err < 0)
  		goto error;
b25396994   Takashi Iwai   ALSA: hda/realtek...
4482
4483
4484
4485
  	board_config = alc_board_config(codec, ALC882_MODEL_LAST,
  					alc882_models, NULL);
  	if (board_config < 0)
  		board_config = alc_board_codec_sid_config(codec,
1d045db96   Takashi Iwai   ALSA: hda - Split...
4486
  			ALC882_MODEL_LAST, alc882_models, alc882_ssid_cfg_tbl);
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4487
4488
  
  	if (board_config < 0) {
9a11f1aa8   Takashi Iwai   ALSA: hda - Rewor...
4489
4490
4491
  		printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.
  ",
  		       codec->chip_name);
1d045db96   Takashi Iwai   ALSA: hda - Split...
4492
  		board_config = ALC_MODEL_AUTO;
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4493
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
4494
4495
  	if (board_config == ALC_MODEL_AUTO) {
  		alc_pick_fixup(codec, NULL, alc882_fixup_tbl, alc882_fixups);
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
4496
4497
  		alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
  	}
ff818c24c   Takashi Iwai   ALSA: hda - Add f...
4498

1d045db96   Takashi Iwai   ALSA: hda - Split...
4499
4500
4501
  	alc_auto_parse_customize_define(codec);
  
  	if (board_config == ALC_MODEL_AUTO) {
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4502
  		/* automatic parse from the BIOS config */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4503
  		err = alc882_parse_auto_config(codec);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4504
4505
  		if (err < 0)
  			goto error;
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4506
  	}
fde48a1f8   David Henningsson   ALSA: HDA: Realte...
4507
  	if (board_config != ALC_MODEL_AUTO) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4508
  		setup_preset(codec, &alc882_presets[board_config]);
fde48a1f8   David Henningsson   ALSA: HDA: Realte...
4509
4510
  		spec->vmaster_nid = 0x0c;
  	}
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4511

60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
4512
  	if (!spec->no_analog && !spec->adc_nids) {
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
4513
  		alc_auto_fill_adc_caps(codec);
21268961d   Takashi Iwai   ALSA: hda - More ...
4514
  		alc_rebuild_imux_for_auto_mic(codec);
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
4515
  		alc_remove_invalid_adc_nids(codec);
84898e87c   Kailang Yang   ALSA: hda - Add A...
4516
  	}
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4517
4518
  	if (!spec->no_analog && !spec->cap_mixer)
  		set_capture_mixer(codec);
1d045db96   Takashi Iwai   ALSA: hda - Split...
4519

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4520
4521
  	if (!spec->no_analog && has_cdefine_beep(codec)) {
  		err = snd_hda_attach_beep_device(codec, 0x1);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4522
4523
  		if (err < 0)
  			goto error;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4524
  		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4525
  	}
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4526

b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
4527
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
ff818c24c   Takashi Iwai   ALSA: hda - Add f...
4528

f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4529
  	codec->patch_ops = alc_patch_ops;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4530
  	if (board_config == ALC_MODEL_AUTO)
e47706295   Takashi Iwai   ALSA: hda - Provi...
4531
  		spec->init_hook = alc_auto_init_std;
bf1b02258   Kailang Yang   ALSA: hda - Add a...
4532

f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4533
4534
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  	if (!spec->loopback.amplist)
1d045db96   Takashi Iwai   ALSA: hda - Split...
4535
  		spec->loopback.amplist = alc882_loopbacks;
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4536
4537
4538
  #endif
  
  	return 0;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4539
4540
4541
4542
  
   error:
  	alc_free(codec);
  	return err;
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
4543
  }
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4544

df694daa3   Kailang Yang   [ALSA] hda-codec ...
4545
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
4546
   * ALC262 support
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4547
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4548
  static int alc262_parse_auto_config(struct hda_codec *codec)
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4549
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4550
  	static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4551
4552
  	static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
  	return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4553
  }
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4554
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
4555
   * Pin config fixes
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4556
   */
cfc9b06f0   Takashi Iwai   ALSA: hda - Add a...
4557
  enum {
ea4e7af12   Takashi Iwai   ALSA: hda/realtek...
4558
4559
4560
  	ALC262_FIXUP_FSC_H270,
  	ALC262_FIXUP_HP_Z200,
  	ALC262_FIXUP_TYAN,
12837c983   Takashi Iwai   ALSA: hda/realtek...
4561
  	ALC262_FIXUP_TOSHIBA_RX1,
c470150c5   Takashi Iwai   ALSA: hda/realtek...
4562
  	ALC262_FIXUP_LENOVO_3000,
b42590b86   Takashi Iwai   ALSA: hda/realtek...
4563
4564
  	ALC262_FIXUP_BENQ,
  	ALC262_FIXUP_BENQ_T31,
cfc9b06f0   Takashi Iwai   ALSA: hda - Add a...
4565
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
4566
  static const struct alc_fixup alc262_fixups[] = {
ea4e7af12   Takashi Iwai   ALSA: hda/realtek...
4567
  	[ALC262_FIXUP_FSC_H270] = {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
4568
4569
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4570
4571
4572
4573
4574
4575
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x15, 0x0221142f }, /* front HP */
  			{ 0x1b, 0x0121141f }, /* rear HP */
  			{ }
  		}
  	},
ea4e7af12   Takashi Iwai   ALSA: hda/realtek...
4576
  	[ALC262_FIXUP_HP_Z200] = {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4577
4578
4579
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x16, 0x99130120 }, /* internal speaker */
73413b120   Takashi Iwai   ALSA: hda - embed...
4580
4581
  			{ }
  		}
cfc9b06f0   Takashi Iwai   ALSA: hda - Add a...
4582
  	},
ea4e7af12   Takashi Iwai   ALSA: hda/realtek...
4583
4584
4585
4586
4587
4588
4589
  	[ALC262_FIXUP_TYAN] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x1993e1f0 }, /* int AUX */
  			{ }
  		}
  	},
12837c983   Takashi Iwai   ALSA: hda/realtek...
4590
4591
4592
4593
4594
4595
4596
4597
4598
4599
  	[ALC262_FIXUP_TOSHIBA_RX1] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x90170110 }, /* speaker */
  			{ 0x15, 0x0421101f }, /* HP */
  			{ 0x1a, 0x40f000f0 }, /* N/A */
  			{ 0x1b, 0x40f000f0 }, /* N/A */
  			{ 0x1e, 0x40f000f0 }, /* N/A */
  		}
  	},
c470150c5   Takashi Iwai   ALSA: hda/realtek...
4600
4601
4602
4603
  	[ALC262_FIXUP_LENOVO_3000] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			{ 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 },
b42590b86   Takashi Iwai   ALSA: hda/realtek...
4604
4605
4606
4607
4608
4609
4610
4611
  			{}
  		},
  		.chained = true,
  		.chain_id = ALC262_FIXUP_BENQ,
  	},
  	[ALC262_FIXUP_BENQ] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
c470150c5   Takashi Iwai   ALSA: hda/realtek...
4612
4613
4614
4615
4616
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
  			{}
  		}
  	},
b42590b86   Takashi Iwai   ALSA: hda/realtek...
4617
4618
4619
4620
4621
4622
4623
4624
  	[ALC262_FIXUP_BENQ_T31] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			{ 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
  			{ 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
  			{}
  		}
  	},
cfc9b06f0   Takashi Iwai   ALSA: hda - Add a...
4625
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
4626
  static const struct snd_pci_quirk alc262_fixup_tbl[] = {
ea4e7af12   Takashi Iwai   ALSA: hda/realtek...
4627
  	SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
3dcd3be33   Takashi Iwai   ALSA: hda/realtek...
4628
4629
  	SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FIXUP_BENQ),
  	SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
ea4e7af12   Takashi Iwai   ALSA: hda/realtek...
4630
  	SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
12837c983   Takashi Iwai   ALSA: hda/realtek...
4631
4632
  	SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1",
  		      ALC262_FIXUP_TOSHIBA_RX1),
ea4e7af12   Takashi Iwai   ALSA: hda/realtek...
4633
  	SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
c470150c5   Takashi Iwai   ALSA: hda/realtek...
4634
  	SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
b42590b86   Takashi Iwai   ALSA: hda/realtek...
4635
4636
  	SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
  	SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
cfc9b06f0   Takashi Iwai   ALSA: hda - Add a...
4637
4638
  	{}
  };
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4639

1d045db96   Takashi Iwai   ALSA: hda - Split...
4640
4641
4642
4643
  
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  #define alc262_loopbacks	alc880_loopbacks
  #endif
1d045db96   Takashi Iwai   ALSA: hda - Split...
4644
4645
  /*
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4646
  static int patch_alc262(struct hda_codec *codec)
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4647
4648
  {
  	struct alc_spec *spec;
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4649
  	int err;
dc041e0b1   Robert P. J. Day   [ALSA] sound: Cha...
4650
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4651
4652
  	if (spec == NULL)
  		return -ENOMEM;
f12ab1e07   Takashi Iwai   [ALSA] hda-codec ...
4653
  	codec->spec = spec;
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4654

1d045db96   Takashi Iwai   ALSA: hda - Split...
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
  	spec->mixer_nid = 0x0b;
  
  #if 0
  	/* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
  	 * under-run
  	 */
  	{
  	int tmp;
  	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
  	tmp = snd_hda_codec_read(codec, 0x20, 0, AC_VERB_GET_PROC_COEF, 0);
  	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_COEF_INDEX, 7);
  	snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PROC_COEF, tmp | 0x80);
  	}
  #endif
  	alc_auto_parse_customize_define(codec);
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
4670

1d045db96   Takashi Iwai   ALSA: hda - Split...
4671
  	alc_fix_pll_init(codec, 0x20, 0x0a, 10);
42399f7a7   Takashi Iwai   ALSA: hda/realtek...
4672
4673
  	alc_pick_fixup(codec, NULL, alc262_fixup_tbl, alc262_fixups);
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
9c7f852e8   Takashi Iwai   [ALSA] Fix/add su...
4674

42399f7a7   Takashi Iwai   ALSA: hda/realtek...
4675
4676
4677
4678
  	/* automatic parse from the BIOS config */
  	err = alc262_parse_auto_config(codec);
  	if (err < 0)
  		goto error;
df694daa3   Kailang Yang   [ALSA] hda-codec ...
4679

60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
4680
  	if (!spec->no_analog && !spec->adc_nids) {
21268961d   Takashi Iwai   ALSA: hda - More ...
4681
4682
4683
4684
  		alc_auto_fill_adc_caps(codec);
  		alc_rebuild_imux_for_auto_mic(codec);
  		alc_remove_invalid_adc_nids(codec);
  	}
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4685
4686
  
  	if (!spec->no_analog && !spec->cap_mixer)
c7a8eb103   Takashi Iwai   ALSA: hda - Fix m...
4687
  		set_capture_mixer(codec);
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4688
4689
4690
  
  	if (!spec->no_analog && has_cdefine_beep(codec)) {
  		err = snd_hda_attach_beep_device(codec, 0x1);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4691
4692
  		if (err < 0)
  			goto error;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4693
  		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4694
  	}
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
4695

b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
4696
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
7fa90e873   Takashi Iwai   ALSA: hda - Enhan...
4697

df694daa3   Kailang Yang   [ALSA] hda-codec ...
4698
  	codec->patch_ops = alc_patch_ops;
42399f7a7   Takashi Iwai   ALSA: hda/realtek...
4699
  	spec->init_hook = alc_auto_init_std;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4700
  	spec->shutup = alc_eapd_shutup;
c97259df3   Daniel T Chen   ALSA: hda: Refact...
4701
  #ifdef CONFIG_SND_HDA_POWER_SAVE
cb53c626e   Takashi Iwai   [ALSA] hda-intel ...
4702
  	if (!spec->loopback.amplist)
1d045db96   Takashi Iwai   ALSA: hda - Split...
4703
  		spec->loopback.amplist = alc262_loopbacks;
cb53c626e   Takashi Iwai   [ALSA] hda-intel ...
4704
  #endif
ea1fb29ac   Kailang Yang   ALSA: hda - fix s...
4705

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4706
  	return 0;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4707
4708
4709
4710
  
   error:
  	alc_free(codec);
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4711
4712
4713
  }
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
4714
   *  ALC268
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4715
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4716
4717
4718
4719
4720
4721
4722
4723
  /* bind Beep switches of both NID 0x0f and 0x10 */
  static const struct hda_bind_ctls alc268_bind_beep_sw = {
  	.ops = &snd_hda_bind_sw,
  	.values = {
  		HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT),
  		HDA_COMPOSE_AMP_VAL(0x10, 3, 1, HDA_INPUT),
  		0
  	},
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4724
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
4725
4726
4727
4728
  static const struct snd_kcontrol_new alc268_beep_mixer[] = {
  	HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
  	HDA_BIND_SW("Beep Playback Switch", &alc268_bind_beep_sw),
  	{ }
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4729
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
4730
4731
4732
4733
4734
4735
  /* set PCBEEP vol = 0, mute connections */
  static const struct hda_verb alc268_beep_init_verbs[] = {
  	{0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
  	{0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
  	{0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
  	{ }
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4736
4737
4738
4739
4740
  };
  
  /*
   * BIOS auto configuration
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4741
  static int alc268_parse_auto_config(struct hda_codec *codec)
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4742
  {
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4743
  	static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4744
  	struct alc_spec *spec = codec->spec;
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4745
4746
4747
4748
4749
  	int err = alc_parse_auto_config(codec, NULL, alc268_ssids);
  	if (err > 0) {
  		if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) {
  			add_mixer(spec, alc268_beep_mixer);
  			add_verb(spec, alc268_beep_init_verbs);
1d045db96   Takashi Iwai   ALSA: hda - Split...
4750
  		}
1d045db96   Takashi Iwai   ALSA: hda - Split...
4751
  	}
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4752
  	return err;
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4753
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
4754
4755
  /*
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4756
  static int patch_alc268(struct hda_codec *codec)
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4757
4758
  {
  	struct alc_spec *spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4759
  	int i, has_beep, err;
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4760
4761
4762
4763
4764
4765
  
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (spec == NULL)
  		return -ENOMEM;
  
  	codec->spec = spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4766
  	/* ALC268 has no aa-loopback mixer */
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
4767

6ebb80530   Takashi Iwai   ALSA: hda - Remov...
4768
4769
  	/* automatic parse from the BIOS config */
  	err = alc268_parse_auto_config(codec);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4770
4771
  	if (err < 0)
  		goto error;
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4772

1d045db96   Takashi Iwai   ALSA: hda - Split...
4773
4774
4775
4776
4777
4778
4779
  	has_beep = 0;
  	for (i = 0; i < spec->num_mixers; i++) {
  		if (spec->mixers[i] == alc268_beep_mixer) {
  			has_beep = 1;
  			break;
  		}
  	}
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4780

1d045db96   Takashi Iwai   ALSA: hda - Split...
4781
4782
  	if (has_beep) {
  		err = snd_hda_attach_beep_device(codec, 0x1);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4783
4784
  		if (err < 0)
  			goto error;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4785
4786
4787
4788
4789
4790
4791
  		if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
  			/* override the amp caps for beep generator */
  			snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
  					  (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
  					  (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
  					  (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
  					  (0 << AC_AMPCAP_MUTE_SHIFT));
2f8932863   Kailang Yang   [ALSA] hda - show...
4792
  	}
60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
4793
  	if (!spec->no_analog && !spec->adc_nids) {
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
4794
  		alc_auto_fill_adc_caps(codec);
21268961d   Takashi Iwai   ALSA: hda - More ...
4795
  		alc_rebuild_imux_for_auto_mic(codec);
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
4796
  		alc_remove_invalid_adc_nids(codec);
dd704698f   Takashi Iwai   ALSA: hda - Don't...
4797
  	}
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4798

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4799
  	if (!spec->no_analog && !spec->cap_mixer)
1d045db96   Takashi Iwai   ALSA: hda - Split...
4800
  		set_capture_mixer(codec);
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4801
4802
  
  	codec->patch_ops = alc_patch_ops;
6ebb80530   Takashi Iwai   ALSA: hda - Remov...
4803
  	spec->init_hook = alc_auto_init_std;
1c716153a   Takashi Iwai   ALSA: hda - Intro...
4804
  	spec->shutup = alc_eapd_shutup;
1d045db96   Takashi Iwai   ALSA: hda - Split...
4805

f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4806
  	return 0;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
4807
4808
4809
4810
  
   error:
  	alc_free(codec);
  	return err;
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
4811
4812
4813
  }
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
4814
   * ALC269
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
4815
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4816
4817
4818
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  #define alc269_loopbacks	alc880_loopbacks
  #endif
e14063481   Takashi Iwai   [ALSA] hda-codec ...
4819

1d045db96   Takashi Iwai   ALSA: hda - Split...
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
  static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
  	.substreams = 1,
  	.channels_min = 2,
  	.channels_max = 8,
  	.rates = SNDRV_PCM_RATE_44100, /* fixed rate */
  	/* NID is set in alc_build_pcms */
  	.ops = {
  		.open = alc_playback_pcm_open,
  		.prepare = alc_playback_pcm_prepare,
  		.cleanup = alc_playback_pcm_cleanup
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
4830
4831
  	},
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
4832
4833
4834
4835
4836
4837
  static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
  	.substreams = 1,
  	.channels_min = 2,
  	.channels_max = 2,
  	.rates = SNDRV_PCM_RATE_44100, /* fixed rate */
  	/* NID is set in alc_build_pcms */
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
4838
  };
291702f01   Kailang Yang   [ALSA] Support A...
4839

1d045db96   Takashi Iwai   ALSA: hda - Split...
4840
4841
4842
4843
4844
4845
4846
4847
4848
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  static int alc269_mic2_for_mute_led(struct hda_codec *codec)
  {
  	switch (codec->subsystem_id) {
  	case 0x103c1586:
  		return 1;
  	}
  	return 0;
  }
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
4849

1d045db96   Takashi Iwai   ALSA: hda - Split...
4850
4851
4852
4853
4854
4855
4856
4857
4858
4859
4860
4861
4862
4863
4864
4865
4866
4867
  static int alc269_mic2_mute_check_ps(struct hda_codec *codec, hda_nid_t nid)
  {
  	/* update mute-LED according to the speaker mute state */
  	if (nid == 0x01 || nid == 0x14) {
  		int pinval;
  		if (snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0) &
  		    HDA_AMP_MUTE)
  			pinval = 0x24;
  		else
  			pinval = 0x20;
  		/* mic2 vref pin is used for mute LED control */
  		snd_hda_codec_update_cache(codec, 0x19, 0,
  					   AC_VERB_SET_PIN_WIDGET_CONTROL,
  					   pinval);
  	}
  	return alc_check_power_status(codec, nid);
  }
  #endif /* CONFIG_SND_HDA_POWER_SAVE */
9541ba1d6   Chris Pockelé   ALSA: hda - Add s...
4868

1d045db96   Takashi Iwai   ALSA: hda - Split...
4869
4870
4871
4872
4873
  /* different alc269-variants */
  enum {
  	ALC269_TYPE_ALC269VA,
  	ALC269_TYPE_ALC269VB,
  	ALC269_TYPE_ALC269VC,
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
4874
4875
4876
  };
  
  /*
1d045db96   Takashi Iwai   ALSA: hda - Split...
4877
   * BIOS auto configuration
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
4878
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
4879
4880
  static int alc269_parse_auto_config(struct hda_codec *codec)
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4881
  	static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4882
4883
4884
4885
4886
  	static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
  	static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
  	struct alc_spec *spec = codec->spec;
  	const hda_nid_t *ssids = spec->codec_variant == ALC269_TYPE_ALC269VA ?
  		alc269va_ssids : alc269_ssids;
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
4887

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
4888
  	return alc_parse_auto_config(codec, alc269_ignore, ssids);
1d045db96   Takashi Iwai   ALSA: hda - Split...
4889
  }
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
4890

1d045db96   Takashi Iwai   ALSA: hda - Split...
4891
4892
4893
4894
4895
4896
4897
4898
4899
  static void alc269_toggle_power_output(struct hda_codec *codec, int power_up)
  {
  	int val = alc_read_coef_idx(codec, 0x04);
  	if (power_up)
  		val |= 1 << 11;
  	else
  		val &= ~(1 << 11);
  	alc_write_coef_idx(codec, 0x04, val);
  }
291702f01   Kailang Yang   [ALSA] Support A...
4900

1d045db96   Takashi Iwai   ALSA: hda - Split...
4901
4902
  static void alc269_shutup(struct hda_codec *codec)
  {
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
4903
  	if ((alc_get_coef0(codec) & 0x00ff) == 0x017)
1d045db96   Takashi Iwai   ALSA: hda - Split...
4904
  		alc269_toggle_power_output(codec, 0);
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
4905
  	if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4906
4907
4908
4909
  		alc269_toggle_power_output(codec, 0);
  		msleep(150);
  	}
  }
291702f01   Kailang Yang   [ALSA] Support A...
4910

2a43952a9   Takashi Iwai   ALSA: hda - Make ...
4911
  #ifdef CONFIG_PM
1d045db96   Takashi Iwai   ALSA: hda - Split...
4912
4913
  static int alc269_resume(struct hda_codec *codec)
  {
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
4914
  	if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4915
4916
4917
  		alc269_toggle_power_output(codec, 0);
  		msleep(150);
  	}
8c427226e   Kailang Yang   [ALSA] hda-codec ...
4918

1d045db96   Takashi Iwai   ALSA: hda - Split...
4919
  	codec->patch_ops.init(codec);
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
4920

1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
4921
  	if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
4922
4923
4924
  		alc269_toggle_power_output(codec, 1);
  		msleep(200);
  	}
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
4925

1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
4926
  	if ((alc_get_coef0(codec) & 0x00ff) == 0x018)
1d045db96   Takashi Iwai   ALSA: hda - Split...
4927
  		alc269_toggle_power_output(codec, 1);
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
4928

1d045db96   Takashi Iwai   ALSA: hda - Split...
4929
4930
4931
4932
4933
  	snd_hda_codec_resume_amp(codec);
  	snd_hda_codec_resume_cache(codec);
  	hda_call_check_power_status(codec, 0x01);
  	return 0;
  }
2a43952a9   Takashi Iwai   ALSA: hda - Make ...
4934
  #endif /* CONFIG_PM */
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
4935

1d045db96   Takashi Iwai   ALSA: hda - Split...
4936
4937
4938
4939
  static void alc269_fixup_hweq(struct hda_codec *codec,
  			       const struct alc_fixup *fix, int action)
  {
  	int coef;
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
4940

1d045db96   Takashi Iwai   ALSA: hda - Split...
4941
4942
4943
4944
4945
  	if (action != ALC_FIXUP_ACT_INIT)
  		return;
  	coef = alc_read_coef_idx(codec, 0x1e);
  	alc_write_coef_idx(codec, 0x1e, coef | 0x80);
  }
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
4946

1d045db96   Takashi Iwai   ALSA: hda - Split...
4947
4948
4949
4950
4951
4952
4953
4954
4955
  static void alc271_fixup_dmic(struct hda_codec *codec,
  			      const struct alc_fixup *fix, int action)
  {
  	static const struct hda_verb verbs[] = {
  		{0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
  		{0x20, AC_VERB_SET_PROC_COEF, 0x4000},
  		{}
  	};
  	unsigned int cfg;
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
4956

1d045db96   Takashi Iwai   ALSA: hda - Split...
4957
4958
4959
4960
4961
4962
  	if (strcmp(codec->chip_name, "ALC271X"))
  		return;
  	cfg = snd_hda_codec_get_pincfg(codec, 0x12);
  	if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
  		snd_hda_sequence_write(codec, verbs);
  }
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
4963

017f2a104   Takashi Iwai   ALSA: hda - Imple...
4964
4965
4966
4967
4968
4969
4970
4971
4972
4973
4974
4975
4976
4977
  static void alc269_fixup_pcm_44k(struct hda_codec *codec,
  				 const struct alc_fixup *fix, int action)
  {
  	struct alc_spec *spec = codec->spec;
  
  	if (action != ALC_FIXUP_ACT_PROBE)
  		return;
  
  	/* Due to a hardware problem on Lenovo Ideadpad, we need to
  	 * fix the sample rate of analog I/O to 44.1kHz
  	 */
  	spec->stream_analog_playback = &alc269_44k_pcm_analog_playback;
  	spec->stream_analog_capture = &alc269_44k_pcm_analog_capture;
  }
adabb3ec8   Takashi Iwai   ALSA: hda - Fix d...
4978
4979
4980
4981
4982
4983
4984
4985
4986
4987
4988
4989
4990
4991
4992
  static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
  				     const struct alc_fixup *fix, int action)
  {
  	int coef;
  
  	if (action != ALC_FIXUP_ACT_INIT)
  		return;
  	/* The digital-mic unit sends PDM (differential signal) instead of
  	 * the standard PCM, thus you can't record a valid mono stream as is.
  	 * Below is a workaround specific to ALC269 to control the dmic
  	 * signal source as mono.
  	 */
  	coef = alc_read_coef_idx(codec, 0x07);
  	alc_write_coef_idx(codec, 0x07, coef | 0x80);
  }
245199116   Takashi Iwai   ALSA: hda - Repla...
4993
4994
  static void alc269_quanta_automute(struct hda_codec *codec)
  {
42cf0d015   David Henningsson   ALSA: HDA: Refact...
4995
  	update_outputs(codec);
245199116   Takashi Iwai   ALSA: hda - Repla...
4996
4997
4998
4999
5000
5001
5002
5003
5004
5005
5006
5007
5008
5009
5010
5011
5012
5013
5014
5015
  
  	snd_hda_codec_write(codec, 0x20, 0,
  			AC_VERB_SET_COEF_INDEX, 0x0c);
  	snd_hda_codec_write(codec, 0x20, 0,
  			AC_VERB_SET_PROC_COEF, 0x680);
  
  	snd_hda_codec_write(codec, 0x20, 0,
  			AC_VERB_SET_COEF_INDEX, 0x0c);
  	snd_hda_codec_write(codec, 0x20, 0,
  			AC_VERB_SET_PROC_COEF, 0x480);
  }
  
  static void alc269_fixup_quanta_mute(struct hda_codec *codec,
  				     const struct alc_fixup *fix, int action)
  {
  	struct alc_spec *spec = codec->spec;
  	if (action != ALC_FIXUP_ACT_PROBE)
  		return;
  	spec->automute_hook = alc269_quanta_automute;
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
5016
5017
5018
5019
5020
5021
5022
5023
5024
  enum {
  	ALC269_FIXUP_SONY_VAIO,
  	ALC275_FIXUP_SONY_VAIO_GPIO2,
  	ALC269_FIXUP_DELL_M101Z,
  	ALC269_FIXUP_SKU_IGNORE,
  	ALC269_FIXUP_ASUS_G73JW,
  	ALC269_FIXUP_LENOVO_EAPD,
  	ALC275_FIXUP_SONY_HWEQ,
  	ALC271_FIXUP_DMIC,
017f2a104   Takashi Iwai   ALSA: hda - Imple...
5025
  	ALC269_FIXUP_PCM_44K,
adabb3ec8   Takashi Iwai   ALSA: hda - Fix d...
5026
  	ALC269_FIXUP_STEREO_DMIC,
245199116   Takashi Iwai   ALSA: hda - Repla...
5027
5028
  	ALC269_FIXUP_QUANTA_MUTE,
  	ALC269_FIXUP_LIFEBOOK,
a4297b5db   Takashi Iwai   ALSA: hda - Rewri...
5029
5030
5031
5032
  	ALC269_FIXUP_AMIC,
  	ALC269_FIXUP_DMIC,
  	ALC269VB_FIXUP_AMIC,
  	ALC269VB_FIXUP_DMIC,
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
5033
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
5034
5035
5036
5037
5038
5039
5040
  static const struct alc_fixup alc269_fixups[] = {
  	[ALC269_FIXUP_SONY_VAIO] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			{0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD},
  			{}
  		}
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
5041
  	},
1d045db96   Takashi Iwai   ALSA: hda - Split...
5042
5043
5044
5045
5046
5047
5048
5049
5050
5051
5052
5053
5054
5055
5056
5057
5058
5059
5060
5061
5062
5063
5064
5065
5066
5067
5068
5069
5070
5071
5072
5073
5074
5075
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
  	[ALC275_FIXUP_SONY_VAIO_GPIO2] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			{0x01, AC_VERB_SET_GPIO_MASK, 0x04},
  			{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04},
  			{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC269_FIXUP_SONY_VAIO
  	},
  	[ALC269_FIXUP_DELL_M101Z] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			/* Enables internal speaker */
  			{0x20, AC_VERB_SET_COEF_INDEX, 13},
  			{0x20, AC_VERB_SET_PROC_COEF, 0x4040},
  			{}
  		}
  	},
  	[ALC269_FIXUP_SKU_IGNORE] = {
  		.type = ALC_FIXUP_SKU,
  		.v.sku = ALC_FIXUP_SKU_IGNORE,
  	},
  	[ALC269_FIXUP_ASUS_G73JW] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x17, 0x99130111 }, /* subwoofer */
  			{ }
  		}
  	},
  	[ALC269_FIXUP_LENOVO_EAPD] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			{0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
  			{}
  		}
  	},
  	[ALC275_FIXUP_SONY_HWEQ] = {
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc269_fixup_hweq,
  		.chained = true,
  		.chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
  	},
  	[ALC271_FIXUP_DMIC] = {
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc271_fixup_dmic,
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
5089
  	},
017f2a104   Takashi Iwai   ALSA: hda - Imple...
5090
5091
5092
5093
  	[ALC269_FIXUP_PCM_44K] = {
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc269_fixup_pcm_44k,
  	},
adabb3ec8   Takashi Iwai   ALSA: hda - Fix d...
5094
5095
5096
5097
  	[ALC269_FIXUP_STEREO_DMIC] = {
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc269_fixup_stereo_dmic,
  	},
245199116   Takashi Iwai   ALSA: hda - Repla...
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
5111
  	[ALC269_FIXUP_QUANTA_MUTE] = {
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc269_fixup_quanta_mute,
  	},
  	[ALC269_FIXUP_LIFEBOOK] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x1a, 0x2101103f }, /* dock line-out */
  			{ 0x1b, 0x23a11040 }, /* dock mic-in */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC269_FIXUP_QUANTA_MUTE
  	},
a4297b5db   Takashi Iwai   ALSA: hda - Rewri...
5112
5113
5114
5115
5116
5117
5118
5119
5120
5121
5122
5123
5124
5125
5126
5127
5128
5129
5130
5131
5132
5133
5134
5135
5136
5137
5138
5139
5140
5141
  	[ALC269_FIXUP_AMIC] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x15, 0x0121401f }, /* HP out */
  			{ 0x18, 0x01a19c20 }, /* mic */
  			{ 0x19, 0x99a3092f }, /* int-mic */
  			{ }
  		},
  	},
  	[ALC269_FIXUP_DMIC] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x12, 0x99a3092f }, /* int-mic */
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x15, 0x0121401f }, /* HP out */
  			{ 0x18, 0x01a19c20 }, /* mic */
  			{ }
  		},
  	},
  	[ALC269VB_FIXUP_AMIC] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x18, 0x01a19c20 }, /* mic */
  			{ 0x19, 0x99a3092f }, /* int-mic */
  			{ 0x21, 0x0121401f }, /* HP out */
  			{ }
  		},
  	},
2267ea976   David Henningsson   ALSA: HDA: Fix ty...
5142
  	[ALC269VB_FIXUP_DMIC] = {
a4297b5db   Takashi Iwai   ALSA: hda - Rewri...
5143
5144
5145
5146
5147
5148
5149
5150
5151
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x12, 0x99a3092f }, /* int-mic */
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x18, 0x01a19c20 }, /* mic */
  			{ 0x21, 0x0121401f }, /* HP out */
  			{ }
  		},
  	},
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
5152
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
5153
  static const struct snd_pci_quirk alc269_fixup_tbl[] = {
017f2a104   Takashi Iwai   ALSA: hda - Imple...
5154
  	SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
adabb3ec8   Takashi Iwai   ALSA: hda - Fix d...
5155
5156
5157
5158
5159
  	SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
  	SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
  	SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
  	SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
  	SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
1d045db96   Takashi Iwai   ALSA: hda - Split...
5160
5161
5162
5163
5164
5165
  	SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
  	SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
  	SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
  	SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
  	SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
  	SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
245199116   Takashi Iwai   ALSA: hda - Repla...
5166
  	SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
1d045db96   Takashi Iwai   ALSA: hda - Split...
5167
5168
5169
5170
5171
  	SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
  	SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
  	SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
  	SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
  	SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
245199116   Takashi Iwai   ALSA: hda - Repla...
5172
  	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_QUANTA_MUTE),
017f2a104   Takashi Iwai   ALSA: hda - Imple...
5173
  	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Lenovo Ideapd", ALC269_FIXUP_PCM_44K),
1d045db96   Takashi Iwai   ALSA: hda - Split...
5174
  	SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
a4297b5db   Takashi Iwai   ALSA: hda - Rewri...
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
  
  #if 1
  	/* Below is a quirk table taken from the old code.
  	 * Basically the device should work as is without the fixup table.
  	 * If BIOS doesn't give a proper info, enable the corresponding
  	 * fixup entry.
  	 */ 
  	SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
  		      ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1113, "ASUS N63Jn", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_FIXUP_DMIC),
  	SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_AMIC),
  	SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_FIXUP_DMIC),
  	SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_FIXUP_DMIC),
  #endif
  	{}
  };
  
  static const struct alc_model_fixup alc269_fixup_models[] = {
  	{.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
  	{.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
1d045db96   Takashi Iwai   ALSA: hda - Split...
5231
  	{}
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
5232
  };
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
5233

1d045db96   Takashi Iwai   ALSA: hda - Split...
5234
5235
5236
  static int alc269_fill_coef(struct hda_codec *codec)
  {
  	int val;
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5237

1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5238
  	if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5239
5240
5241
  		alc_write_coef_idx(codec, 0xf, 0x960b);
  		alc_write_coef_idx(codec, 0xe, 0x8817);
  	}
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5242

1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5243
  	if ((alc_get_coef0(codec) & 0x00ff) == 0x016) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5244
5245
5246
  		alc_write_coef_idx(codec, 0xf, 0x960b);
  		alc_write_coef_idx(codec, 0xe, 0x8814);
  	}
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5247

1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5248
  	if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5249
5250
5251
5252
  		val = alc_read_coef_idx(codec, 0x04);
  		/* Power up output pin */
  		alc_write_coef_idx(codec, 0x04, val | (1<<11));
  	}
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5253

1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5254
  	if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
  		val = alc_read_coef_idx(codec, 0xd);
  		if ((val & 0x0c00) >> 10 != 0x1) {
  			/* Capless ramp up clock control */
  			alc_write_coef_idx(codec, 0xd, val | (1<<10));
  		}
  		val = alc_read_coef_idx(codec, 0x17);
  		if ((val & 0x01c0) >> 6 != 0x4) {
  			/* Class D power on reset */
  			alc_write_coef_idx(codec, 0x17, val | (1<<7));
  		}
  	}
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5266

1d045db96   Takashi Iwai   ALSA: hda - Split...
5267
5268
  	val = alc_read_coef_idx(codec, 0xd); /* Class D */
  	alc_write_coef_idx(codec, 0xd, val | (1<<14));
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5269

1d045db96   Takashi Iwai   ALSA: hda - Split...
5270
5271
  	val = alc_read_coef_idx(codec, 0x4); /* HP */
  	alc_write_coef_idx(codec, 0x4, val | (1<<11));
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
5272

1d045db96   Takashi Iwai   ALSA: hda - Split...
5273
5274
  	return 0;
  }
a7f2371f9   Takashi Iwai   ALSA: hda - Split...
5275

1d045db96   Takashi Iwai   ALSA: hda - Split...
5276
5277
  /*
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
5278
5279
5280
  static int patch_alc269(struct hda_codec *codec)
  {
  	struct alc_spec *spec;
20ca0c350   Takashi Iwai   ALSA: hda/realtek...
5281
  	int err = 0;
291702f01   Kailang Yang   [ALSA] Support A...
5282

1d045db96   Takashi Iwai   ALSA: hda - Split...
5283
5284
5285
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (spec == NULL)
  		return -ENOMEM;
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5286

1d045db96   Takashi Iwai   ALSA: hda - Split...
5287
  	codec->spec = spec;
8c427226e   Kailang Yang   [ALSA] hda-codec ...
5288

1d045db96   Takashi Iwai   ALSA: hda - Split...
5289
  	spec->mixer_nid = 0x0b;
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
5290

1d045db96   Takashi Iwai   ALSA: hda - Split...
5291
  	alc_auto_parse_customize_define(codec);
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
5292

e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5293
5294
5295
  	err = alc_codec_rename_from_preset(codec);
  	if (err < 0)
  		goto error;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5296
5297
  	if (codec->vendor_id == 0x10ec0269) {
  		spec->codec_variant = ALC269_TYPE_ALC269VA;
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5298
5299
  		switch (alc_get_coef0(codec) & 0x00f0) {
  		case 0x0010:
1d045db96   Takashi Iwai   ALSA: hda - Split...
5300
  			if (codec->bus->pci->subsystem_vendor == 0x1025 &&
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5301
  			    spec->cdefine.platform_type == 1)
20ca0c350   Takashi Iwai   ALSA: hda/realtek...
5302
  				err = alc_codec_rename(codec, "ALC271X");
1d045db96   Takashi Iwai   ALSA: hda - Split...
5303
  			spec->codec_variant = ALC269_TYPE_ALC269VB;
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5304
5305
  			break;
  		case 0x0020:
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5306
5307
  			if (codec->bus->pci->subsystem_vendor == 0x17aa &&
  			    codec->bus->pci->subsystem_device == 0x21f3)
20ca0c350   Takashi Iwai   ALSA: hda/realtek...
5308
  				err = alc_codec_rename(codec, "ALC3202");
1d045db96   Takashi Iwai   ALSA: hda - Split...
5309
  			spec->codec_variant = ALC269_TYPE_ALC269VC;
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5310
5311
  			break;
  		default:
1d045db96   Takashi Iwai   ALSA: hda - Split...
5312
  			alc_fix_pll_init(codec, 0x20, 0x04, 15);
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5313
  		}
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5314
5315
  		if (err < 0)
  			goto error;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5316
5317
  		alc269_fill_coef(codec);
  	}
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
5318

a4297b5db   Takashi Iwai   ALSA: hda - Rewri...
5319
5320
5321
  	alc_pick_fixup(codec, alc269_fixup_models,
  		       alc269_fixup_tbl, alc269_fixups);
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
5322

a4297b5db   Takashi Iwai   ALSA: hda - Rewri...
5323
5324
  	/* automatic parse from the BIOS config */
  	err = alc269_parse_auto_config(codec);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5325
5326
  	if (err < 0)
  		goto error;
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
5327

60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
5328
  	if (!spec->no_analog && !spec->adc_nids) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5329
5330
5331
5332
  		alc_auto_fill_adc_caps(codec);
  		alc_rebuild_imux_for_auto_mic(codec);
  		alc_remove_invalid_adc_nids(codec);
  	}
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
5333

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5334
  	if (!spec->no_analog && !spec->cap_mixer)
1d045db96   Takashi Iwai   ALSA: hda - Split...
5335
  		set_capture_mixer(codec);
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5336
5337
5338
  
  	if (!spec->no_analog && has_cdefine_beep(codec)) {
  		err = snd_hda_attach_beep_device(codec, 0x1);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5339
5340
  		if (err < 0)
  			goto error;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5341
  		set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5342
  	}
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
5343

1d045db96   Takashi Iwai   ALSA: hda - Split...
5344
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
622e84cdf   Kailang Yang   ALSA: hda - Add q...
5345

1d045db96   Takashi Iwai   ALSA: hda - Split...
5346
  	codec->patch_ops = alc_patch_ops;
2a43952a9   Takashi Iwai   ALSA: hda - Make ...
5347
  #ifdef CONFIG_PM
1d045db96   Takashi Iwai   ALSA: hda - Split...
5348
5349
  	codec->patch_ops.resume = alc269_resume;
  #endif
a4297b5db   Takashi Iwai   ALSA: hda - Rewri...
5350
  	spec->init_hook = alc_auto_init_std;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5351
  	spec->shutup = alc269_shutup;
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5352

1d045db96   Takashi Iwai   ALSA: hda - Split...
5353
5354
5355
5356
5357
5358
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  	if (!spec->loopback.amplist)
  		spec->loopback.amplist = alc269_loopbacks;
  	if (alc269_mic2_for_mute_led(codec))
  		codec->patch_ops.check_power_status = alc269_mic2_mute_check_ps;
  #endif
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5359

1d045db96   Takashi Iwai   ALSA: hda - Split...
5360
  	return 0;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5361
5362
5363
5364
  
   error:
  	alc_free(codec);
  	return err;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5365
  }
f1d4e28b2   Kailang Yang   ALSA: hda - Add m...
5366

1d045db96   Takashi Iwai   ALSA: hda - Split...
5367
5368
5369
  /*
   * ALC861
   */
622e84cdf   Kailang Yang   ALSA: hda - Add q...
5370

1d045db96   Takashi Iwai   ALSA: hda - Split...
5371
  static int alc861_parse_auto_config(struct hda_codec *codec)
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
5372
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5373
  	static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5374
5375
  	static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
  	return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
604401a92   Takashi Iwai   ALSA: hda - Minor...
5376
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
5377
5378
5379
5380
5381
5382
5383
5384
5385
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  static const struct hda_amp_list alc861_loopbacks[] = {
  	{ 0x15, HDA_INPUT, 0 },
  	{ 0x15, HDA_INPUT, 1 },
  	{ 0x15, HDA_INPUT, 2 },
  	{ 0x15, HDA_INPUT, 3 },
  	{ } /* end */
  };
  #endif
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5386

ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5387

1d045db96   Takashi Iwai   ALSA: hda - Split...
5388
5389
5390
5391
  /* Pin config fixes */
  enum {
  	PINFIX_FSC_AMILO_PI1505,
  };
7085ec12a   Takashi Iwai   ALSA: hda - Fix /...
5392

1d045db96   Takashi Iwai   ALSA: hda - Split...
5393
5394
5395
5396
5397
5398
5399
5400
5401
5402
  static const struct alc_fixup alc861_fixups[] = {
  	[PINFIX_FSC_AMILO_PI1505] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x0b, 0x0221101f }, /* HP */
  			{ 0x0f, 0x90170310 }, /* speaker */
  			{ }
  		}
  	},
  };
7085ec12a   Takashi Iwai   ALSA: hda - Fix /...
5403

1d045db96   Takashi Iwai   ALSA: hda - Split...
5404
5405
5406
5407
  static const struct snd_pci_quirk alc861_fixup_tbl[] = {
  	SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505),
  	{}
  };
3af9ee6b8   Takashi Iwai   ALSA: hda - Check...
5408

1d045db96   Takashi Iwai   ALSA: hda - Split...
5409
5410
  /*
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
5411
  static int patch_alc861(struct hda_codec *codec)
7085ec12a   Takashi Iwai   ALSA: hda - Fix /...
5412
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5413
  	struct alc_spec *spec;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5414
  	int err;
7085ec12a   Takashi Iwai   ALSA: hda - Fix /...
5415

1d045db96   Takashi Iwai   ALSA: hda - Split...
5416
5417
5418
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (spec == NULL)
  		return -ENOMEM;
3af9ee6b8   Takashi Iwai   ALSA: hda - Check...
5419

1d045db96   Takashi Iwai   ALSA: hda - Split...
5420
5421
5422
  	codec->spec = spec;
  
  	spec->mixer_nid = 0x15;
cb4e48241   Takashi Iwai   ALSA: hda - Remov...
5423
5424
  	alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
3af9ee6b8   Takashi Iwai   ALSA: hda - Check...
5425

cb4e48241   Takashi Iwai   ALSA: hda - Remov...
5426
5427
  	/* automatic parse from the BIOS config */
  	err = alc861_parse_auto_config(codec);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5428
5429
  	if (err < 0)
  		goto error;
3af9ee6b8   Takashi Iwai   ALSA: hda - Check...
5430

60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
5431
  	if (!spec->no_analog && !spec->adc_nids) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5432
5433
5434
5435
  		alc_auto_fill_adc_caps(codec);
  		alc_rebuild_imux_for_auto_mic(codec);
  		alc_remove_invalid_adc_nids(codec);
  	}
7085ec12a   Takashi Iwai   ALSA: hda - Fix /...
5436

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5437
  	if (!spec->no_analog && !spec->cap_mixer)
1d045db96   Takashi Iwai   ALSA: hda - Split...
5438
  		set_capture_mixer(codec);
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5439
5440
5441
  
  	if (!spec->no_analog) {
  		err = snd_hda_attach_beep_device(codec, 0x23);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5442
5443
  		if (err < 0)
  			goto error;
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5444
5445
  		set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
  	}
7085ec12a   Takashi Iwai   ALSA: hda - Fix /...
5446

1d045db96   Takashi Iwai   ALSA: hda - Split...
5447
5448
5449
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
  
  	codec->patch_ops = alc_patch_ops;
cb4e48241   Takashi Iwai   ALSA: hda - Remov...
5450
  	spec->init_hook = alc_auto_init_std;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5451
  #ifdef CONFIG_SND_HDA_POWER_SAVE
cb4e48241   Takashi Iwai   ALSA: hda - Remov...
5452
  	spec->power_hook = alc_power_eapd;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5453
5454
5455
5456
5457
  	if (!spec->loopback.amplist)
  		spec->loopback.amplist = alc861_loopbacks;
  #endif
  
  	return 0;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5458
5459
5460
5461
  
   error:
  	alc_free(codec);
  	return err;
7085ec12a   Takashi Iwai   ALSA: hda - Fix /...
5462
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
5463
5464
5465
5466
5467
5468
5469
5470
5471
5472
  /*
   * ALC861-VD support
   *
   * Based on ALC882
   *
   * In addition, an independent DAC
   */
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  #define alc861vd_loopbacks	alc880_loopbacks
  #endif
1d045db96   Takashi Iwai   ALSA: hda - Split...
5473
  static int alc861vd_parse_auto_config(struct hda_codec *codec)
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5474
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5475
  	static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5476
5477
  	static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
  	return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5478
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
5479
  enum {
8fdcb6fe4   Takashi Iwai   ALSA: hda - Resto...
5480
5481
  	ALC660VD_FIX_ASUS_GPIO1,
  	ALC861VD_FIX_DALLAS,
1d045db96   Takashi Iwai   ALSA: hda - Split...
5482
  };
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5483

8fdcb6fe4   Takashi Iwai   ALSA: hda - Resto...
5484
5485
5486
5487
5488
5489
5490
5491
5492
  /* exclude VREF80 */
  static void alc861vd_fixup_dallas(struct hda_codec *codec,
  				  const struct alc_fixup *fix, int action)
  {
  	if (action == ALC_FIXUP_ACT_PRE_PROBE) {
  		snd_hda_override_pin_caps(codec, 0x18, 0x00001714);
  		snd_hda_override_pin_caps(codec, 0x19, 0x0000171c);
  	}
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
5493
5494
5495
5496
  static const struct alc_fixup alc861vd_fixups[] = {
  	[ALC660VD_FIX_ASUS_GPIO1] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
8fdcb6fe4   Takashi Iwai   ALSA: hda - Resto...
5497
  			/* reset GPIO1 */
1d045db96   Takashi Iwai   ALSA: hda - Split...
5498
5499
5500
5501
5502
5503
  			{0x01, AC_VERB_SET_GPIO_MASK, 0x03},
  			{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
  			{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
  			{ }
  		}
  	},
8fdcb6fe4   Takashi Iwai   ALSA: hda - Resto...
5504
5505
5506
5507
  	[ALC861VD_FIX_DALLAS] = {
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc861vd_fixup_dallas,
  	},
1d045db96   Takashi Iwai   ALSA: hda - Split...
5508
  };
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5509

1d045db96   Takashi Iwai   ALSA: hda - Split...
5510
  static const struct snd_pci_quirk alc861vd_fixup_tbl[] = {
8fdcb6fe4   Takashi Iwai   ALSA: hda - Resto...
5511
  	SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
1d045db96   Takashi Iwai   ALSA: hda - Split...
5512
  	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
8fdcb6fe4   Takashi Iwai   ALSA: hda - Resto...
5513
  	SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
1d045db96   Takashi Iwai   ALSA: hda - Split...
5514
5515
  	{}
  };
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5516

1d045db96   Takashi Iwai   ALSA: hda - Split...
5517
5518
5519
5520
  static const struct hda_verb alc660vd_eapd_verbs[] = {
  	{0x14, AC_VERB_SET_EAPD_BTLENABLE, 2},
  	{0x15, AC_VERB_SET_EAPD_BTLENABLE, 2},
  	{ }
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5521
  };
1d045db96   Takashi Iwai   ALSA: hda - Split...
5522
5523
  /*
   */
1d045db96   Takashi Iwai   ALSA: hda - Split...
5524
  static int patch_alc861vd(struct hda_codec *codec)
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5525
  {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5526
  	struct alc_spec *spec;
cb4e48241   Takashi Iwai   ALSA: hda - Remov...
5527
  	int err;
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5528

1d045db96   Takashi Iwai   ALSA: hda - Split...
5529
5530
5531
5532
5533
5534
5535
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (spec == NULL)
  		return -ENOMEM;
  
  	codec->spec = spec;
  
  	spec->mixer_nid = 0x0b;
cb4e48241   Takashi Iwai   ALSA: hda - Remov...
5536
5537
  	alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
1d045db96   Takashi Iwai   ALSA: hda - Split...
5538

cb4e48241   Takashi Iwai   ALSA: hda - Remov...
5539
5540
  	/* automatic parse from the BIOS config */
  	err = alc861vd_parse_auto_config(codec);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5541
5542
  	if (err < 0)
  		goto error;
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5543

1d045db96   Takashi Iwai   ALSA: hda - Split...
5544
5545
5546
5547
  	if (codec->vendor_id == 0x10ec0660) {
  		/* always turn on EAPD */
  		add_verb(spec, alc660vd_eapd_verbs);
  	}
60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
5548
  	if (!spec->no_analog && !spec->adc_nids) {
1d045db96   Takashi Iwai   ALSA: hda - Split...
5549
5550
5551
  		alc_auto_fill_adc_caps(codec);
  		alc_rebuild_imux_for_auto_mic(codec);
  		alc_remove_invalid_adc_nids(codec);
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5552
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
5553

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5554
5555
5556
5557
5558
  	if (!spec->no_analog && !spec->cap_mixer)
  		set_capture_mixer(codec);
  
  	if (!spec->no_analog) {
  		err = snd_hda_attach_beep_device(codec, 0x23);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5559
5560
  		if (err < 0)
  			goto error;
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5561
5562
  		set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
  	}
1d045db96   Takashi Iwai   ALSA: hda - Split...
5563

1d045db96   Takashi Iwai   ALSA: hda - Split...
5564
5565
5566
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
  
  	codec->patch_ops = alc_patch_ops;
cb4e48241   Takashi Iwai   ALSA: hda - Remov...
5567
  	spec->init_hook = alc_auto_init_std;
1d045db96   Takashi Iwai   ALSA: hda - Split...
5568
5569
5570
5571
5572
  	spec->shutup = alc_eapd_shutup;
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  	if (!spec->loopback.amplist)
  		spec->loopback.amplist = alc861vd_loopbacks;
  #endif
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5573
  	return 0;
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5574
5575
5576
5577
  
   error:
  	alc_free(codec);
  	return err;
ce764ab22   Takashi Iwai   ALSA: hda - Add c...
5578
  }
1d045db96   Takashi Iwai   ALSA: hda - Split...
5579
5580
5581
5582
5583
5584
5585
5586
5587
5588
5589
5590
5591
5592
5593
5594
5595
5596
  /*
   * ALC662 support
   *
   * ALC662 is almost identical with ALC880 but has cleaner and more flexible
   * configuration.  Each pin widget can choose any input DACs and a mixer.
   * Each ADC is connected from a mixer of all inputs.  This makes possible
   * 6-channel independent captures.
   *
   * In addition, an independent DAC for the multi-playback (not used in this
   * driver yet).
   */
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  #define alc662_loopbacks	alc880_loopbacks
  #endif
  
  /*
   * BIOS auto configuration
   */
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5597
5598
  static int alc662_parse_auto_config(struct hda_codec *codec)
  {
4c6d72d13   Takashi Iwai   ALSA: hda - Const...
5599
  	static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5600
5601
5602
  	static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
  	static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
  	const hda_nid_t *ssids;
ee979a143   Takashi Iwai   ALSA: hda - Add m...
5603

6227cdced   Kailang Yang   ALSA: hda - Add A...
5604
5605
  	if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 ||
  	    codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670)
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5606
  		ssids = alc663_ssids;
6227cdced   Kailang Yang   ALSA: hda - Add A...
5607
  	else
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5608
5609
  		ssids = alc662_ssids;
  	return alc_parse_auto_config(codec, alc662_ignore, ssids);
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5610
  }
6be7948ff   Todd Broch   ALSA: hda: Add fi...
5611
  static void alc272_fixup_mario(struct hda_codec *codec,
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
5612
  			       const struct alc_fixup *fix, int action)
6fc398cb3   Takashi Iwai   ALSA: hda - Apply...
5613
  {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
5614
  	if (action != ALC_FIXUP_ACT_PROBE)
6fc398cb3   Takashi Iwai   ALSA: hda - Apply...
5615
  		return;
6be7948ff   Todd Broch   ALSA: hda: Add fi...
5616
5617
5618
5619
5620
5621
5622
5623
5624
  	if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
  				      (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
  				      (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
  				      (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
  				      (0 << AC_AMPCAP_MUTE_SHIFT)))
  		printk(KERN_WARNING
  		       "hda_codec: failed to override amp caps for NID 0x2
  ");
  }
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5625
  enum {
2df03514d   Daniel T Chen   ALSA: hda: Add sp...
5626
  	ALC662_FIXUP_ASPIRE,
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5627
  	ALC662_FIXUP_IDEAPAD,
6be7948ff   Todd Broch   ALSA: hda: Add fi...
5628
  	ALC272_FIXUP_MARIO,
d2ebd4798   Anisse Astier   ALSA: hda - Fix E...
5629
  	ALC662_FIXUP_CZC_P10T,
94024cd1a   David Henningsson   ALSA: HDA: Fix au...
5630
  	ALC662_FIXUP_SKU_IGNORE,
e59ea3ed9   Takashi Iwai   ALSA: hda - Add a...
5631
  	ALC662_FIXUP_HP_RP5800,
53c334add   Takashi Iwai   ALSA: hda - Rewri...
5632
5633
5634
5635
5636
5637
5638
5639
  	ALC662_FIXUP_ASUS_MODE1,
  	ALC662_FIXUP_ASUS_MODE2,
  	ALC662_FIXUP_ASUS_MODE3,
  	ALC662_FIXUP_ASUS_MODE4,
  	ALC662_FIXUP_ASUS_MODE5,
  	ALC662_FIXUP_ASUS_MODE6,
  	ALC662_FIXUP_ASUS_MODE7,
  	ALC662_FIXUP_ASUS_MODE8,
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5640
5641
5642
  };
  
  static const struct alc_fixup alc662_fixups[] = {
2df03514d   Daniel T Chen   ALSA: hda: Add sp...
5643
  	[ALC662_FIXUP_ASPIRE] = {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
5644
5645
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
2df03514d   Daniel T Chen   ALSA: hda: Add sp...
5646
5647
5648
5649
  			{ 0x15, 0x99130112 }, /* subwoofer */
  			{ }
  		}
  	},
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5650
  	[ALC662_FIXUP_IDEAPAD] = {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
5651
5652
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5653
5654
5655
5656
  			{ 0x17, 0x99130112 }, /* subwoofer */
  			{ }
  		}
  	},
6be7948ff   Todd Broch   ALSA: hda: Add fi...
5657
  	[ALC272_FIXUP_MARIO] = {
b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
5658
5659
  		.type = ALC_FIXUP_FUNC,
  		.v.func = alc272_fixup_mario,
d2ebd4798   Anisse Astier   ALSA: hda - Fix E...
5660
5661
5662
5663
5664
5665
5666
5667
  	},
  	[ALC662_FIXUP_CZC_P10T] = {
  		.type = ALC_FIXUP_VERBS,
  		.v.verbs = (const struct hda_verb[]) {
  			{0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
  			{}
  		}
  	},
94024cd1a   David Henningsson   ALSA: HDA: Fix au...
5668
5669
5670
  	[ALC662_FIXUP_SKU_IGNORE] = {
  		.type = ALC_FIXUP_SKU,
  		.v.sku = ALC_FIXUP_SKU_IGNORE,
c6b358748   Takashi Iwai   ALSA: hda - Fix p...
5671
  	},
e59ea3ed9   Takashi Iwai   ALSA: hda - Add a...
5672
5673
5674
5675
5676
5677
5678
5679
5680
  	[ALC662_FIXUP_HP_RP5800] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x0221201f }, /* HP out */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
  	},
53c334add   Takashi Iwai   ALSA: hda - Rewri...
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
  	[ALC662_FIXUP_ASUS_MODE1] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x18, 0x01a19c20 }, /* mic */
  			{ 0x19, 0x99a3092f }, /* int-mic */
  			{ 0x21, 0x0121401f }, /* HP out */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
  	},
  	[ALC662_FIXUP_ASUS_MODE2] = {
2996bdbaa   Takashi Iwai   ALSA: hda - Remov...
5694
5695
5696
5697
5698
5699
5700
5701
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x18, 0x01a19820 }, /* mic */
  			{ 0x19, 0x99a3092f }, /* int-mic */
  			{ 0x1b, 0x0121401f }, /* HP out */
  			{ }
  		},
53c334add   Takashi Iwai   ALSA: hda - Rewri...
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716
5717
5718
5719
5720
5721
5722
5723
5724
5725
5726
5727
5728
5729
5730
5731
5732
5733
5734
5735
5736
5737
5738
5739
5740
5741
5742
5743
5744
5745
5746
5747
5748
5749
5750
5751
5752
5753
5754
5755
5756
5757
5758
5759
5760
5761
5762
5763
5764
5765
5766
5767
5768
5769
5770
5771
5772
5773
5774
5775
5776
5777
5778
5779
5780
5781
5782
5783
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
  	},
  	[ALC662_FIXUP_ASUS_MODE3] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x15, 0x0121441f }, /* HP */
  			{ 0x18, 0x01a19840 }, /* mic */
  			{ 0x19, 0x99a3094f }, /* int-mic */
  			{ 0x21, 0x01211420 }, /* HP2 */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
  	},
  	[ALC662_FIXUP_ASUS_MODE4] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x16, 0x99130111 }, /* speaker */
  			{ 0x18, 0x01a19840 }, /* mic */
  			{ 0x19, 0x99a3094f }, /* int-mic */
  			{ 0x21, 0x0121441f }, /* HP */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
  	},
  	[ALC662_FIXUP_ASUS_MODE5] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x15, 0x0121441f }, /* HP */
  			{ 0x16, 0x99130111 }, /* speaker */
  			{ 0x18, 0x01a19840 }, /* mic */
  			{ 0x19, 0x99a3094f }, /* int-mic */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
  	},
  	[ALC662_FIXUP_ASUS_MODE6] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x15, 0x01211420 }, /* HP2 */
  			{ 0x18, 0x01a19840 }, /* mic */
  			{ 0x19, 0x99a3094f }, /* int-mic */
  			{ 0x1b, 0x0121441f }, /* HP */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
  	},
  	[ALC662_FIXUP_ASUS_MODE7] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x17, 0x99130111 }, /* speaker */
  			{ 0x18, 0x01a19840 }, /* mic */
  			{ 0x19, 0x99a3094f }, /* int-mic */
  			{ 0x1b, 0x01214020 }, /* HP */
  			{ 0x21, 0x0121401f }, /* HP */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
  	},
  	[ALC662_FIXUP_ASUS_MODE8] = {
  		.type = ALC_FIXUP_PINS,
  		.v.pins = (const struct alc_pincfg[]) {
  			{ 0x14, 0x99130110 }, /* speaker */
  			{ 0x12, 0x99a30970 }, /* int-mic */
  			{ 0x15, 0x01214020 }, /* HP */
  			{ 0x17, 0x99130111 }, /* speaker */
  			{ 0x18, 0x01a19840 }, /* mic */
  			{ 0x21, 0x0121401f }, /* HP */
  			{ }
  		},
  		.chained = true,
  		.chain_id = ALC662_FIXUP_SKU_IGNORE
2996bdbaa   Takashi Iwai   ALSA: hda - Remov...
5784
  	},
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5785
  };
a9111321f   Takashi Iwai   ALSA: hda - Const...
5786
  static const struct snd_pci_quirk alc662_fixup_tbl[] = {
53c334add   Takashi Iwai   ALSA: hda - Rewri...
5787
  	SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
a6c47a85b   David Henningsson   ALSA: HDA: Add su...
5788
  	SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
94024cd1a   David Henningsson   ALSA: HDA: Fix au...
5789
  	SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
2df03514d   Daniel T Chen   ALSA: hda: Add sp...
5790
  	SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
e59ea3ed9   Takashi Iwai   ALSA: hda - Add a...
5791
  	SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
53c334add   Takashi Iwai   ALSA: hda - Rewri...
5792
  	SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
a0e90acc6   Daniel T Chen   ALSA: hda: Add Sa...
5793
  	SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
d41185882   Valentine Sinitsyn   ALSA: hda - Added...
5794
  	SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5795
  	SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
d2ebd4798   Anisse Astier   ALSA: hda - Fix E...
5796
  	SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
53c334add   Takashi Iwai   ALSA: hda - Rewri...
5797
5798
5799
5800
5801
5802
5803
5804
5805
5806
5807
5808
5809
5810
5811
5812
5813
5814
5815
5816
5817
5818
5819
5820
5821
5822
5823
5824
5825
5826
5827
5828
5829
5830
5831
5832
5833
5834
5835
5836
5837
5838
5839
5840
5841
5842
5843
5844
5845
5846
5847
5848
5849
5850
5851
5852
5853
5854
  
  #if 0
  	/* Below is a quirk table taken from the old code.
  	 * Basically the device should work as is without the fixup table.
  	 * If BIOS doesn't give a proper info, enable the corresponding
  	 * fixup entry.
  	 */ 
  	SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
  	SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
  	SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
  	SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
  	SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
  	SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
  	SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
  	SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
  	SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
  	SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
  	SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
  	SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
  	SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
  	SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
  	SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
  	SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
  	SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
  #endif
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5855
5856
  	{}
  };
6be7948ff   Todd Broch   ALSA: hda: Add fi...
5857
5858
  static const struct alc_model_fixup alc662_fixup_models[] = {
  	{.id = ALC272_FIXUP_MARIO, .name = "mario"},
53c334add   Takashi Iwai   ALSA: hda - Rewri...
5859
5860
5861
5862
5863
5864
5865
5866
  	{.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
  	{.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
  	{.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
  	{.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
  	{.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
  	{.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
  	{.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
  	{.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
6be7948ff   Todd Broch   ALSA: hda: Add fi...
5867
5868
  	{}
  };
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5869

1d045db96   Takashi Iwai   ALSA: hda - Split...
5870
5871
  /*
   */
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5872
5873
5874
  static int patch_alc662(struct hda_codec *codec)
  {
  	struct alc_spec *spec;
20ca0c350   Takashi Iwai   ALSA: hda/realtek...
5875
  	int err = 0;
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5876
5877
5878
5879
5880
5881
  
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (!spec)
  		return -ENOMEM;
  
  	codec->spec = spec;
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
5882
  	spec->mixer_nid = 0x0b;
53c334add   Takashi Iwai   ALSA: hda - Rewri...
5883
5884
  	/* handle multiple HPs as is */
  	spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
da00c2449   Kailang Yang   ALSA: hda - Add p...
5885
  	alc_auto_parse_customize_define(codec);
2c3bf9abb   Takashi Iwai   [ALSA] hda - Fix ...
5886
  	alc_fix_pll_init(codec, 0x20, 0x04, 15);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5887
5888
5889
  	err = alc_codec_rename_from_preset(codec);
  	if (err < 0)
  		goto error;
1bb7e43e2   Takashi Iwai   ALSA: hda/realtek...
5890
  	if ((alc_get_coef0(codec) & (1 << 14)) &&
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5891
5892
5893
5894
  	    codec->bus->pci->subsystem_vendor == 0x1025 &&
  	    spec->cdefine.platform_type == 1) {
  		if (alc_codec_rename(codec, "ALC272X") < 0)
  			goto error;
20ca0c350   Takashi Iwai   ALSA: hda/realtek...
5895
  	}
274693f37   Kailang Yang   ALSA: hda - Add A...
5896

b9c5106cd   Takashi Iwai   ALSA: hda - Remov...
5897
5898
5899
5900
5901
  	alc_pick_fixup(codec, alc662_fixup_models,
  		       alc662_fixup_tbl, alc662_fixups);
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE);
  	/* automatic parse from the BIOS config */
  	err = alc662_parse_auto_config(codec);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5902
5903
  	if (err < 0)
  		goto error;
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5904

60a6a8425   Takashi Iwai   ALSA: hda - Fix O...
5905
  	if (!spec->no_analog && !spec->adc_nids) {
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
5906
  		alc_auto_fill_adc_caps(codec);
21268961d   Takashi Iwai   ALSA: hda - More ...
5907
  		alc_rebuild_imux_for_auto_mic(codec);
d6cc9fabd   Takashi Iwai   ALSA: hda - Parse...
5908
  		alc_remove_invalid_adc_nids(codec);
dd704698f   Takashi Iwai   ALSA: hda - Don't...
5909
  	}
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5910

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5911
  	if (!spec->no_analog && !spec->cap_mixer)
b59bdf3b0   Takashi Iwai   ALSA: hda - Check...
5912
  		set_capture_mixer(codec);
cec27c891   Kailang Yang   ALSA: hda - Add s...
5913

3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5914
5915
  	if (!spec->no_analog && has_cdefine_beep(codec)) {
  		err = snd_hda_attach_beep_device(codec, 0x1);
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5916
5917
  		if (err < 0)
  			goto error;
da00c2449   Kailang Yang   ALSA: hda - Add p...
5918
5919
5920
5921
5922
5923
5924
5925
5926
5927
5928
5929
5930
  		switch (codec->vendor_id) {
  		case 0x10ec0662:
  			set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
  			break;
  		case 0x10ec0272:
  		case 0x10ec0663:
  		case 0x10ec0665:
  			set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
  			break;
  		case 0x10ec0273:
  			set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
  			break;
  		}
cec27c891   Kailang Yang   ALSA: hda - Add s...
5931
  	}
2134ea4f3   Takashi Iwai   [ALSA] hda-codec ...
5932

b5bfbc670   Takashi Iwai   ALSA: hda - Reorg...
5933
  	alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE);
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5934
  	codec->patch_ops = alc_patch_ops;
b9c5106cd   Takashi Iwai   ALSA: hda - Remov...
5935
  	spec->init_hook = alc_auto_init_std;
1c716153a   Takashi Iwai   ALSA: hda - Intro...
5936
  	spec->shutup = alc_eapd_shutup;
6cb3b707f   David Henningsson   ALSA: HDA: Add fi...
5937

cb53c626e   Takashi Iwai   [ALSA] hda-intel ...
5938
5939
5940
5941
  #ifdef CONFIG_SND_HDA_POWER_SAVE
  	if (!spec->loopback.amplist)
  		spec->loopback.amplist = alc662_loopbacks;
  #endif
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5942
5943
  
  	return 0;
801f49d3b   Kailang Yang   ALSA: hda - ALC88...
5944

e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
5945
5946
5947
   error:
  	alc_free(codec);
  	return err;
b478b9984   Kailang Yang   ALSA: hda - Add s...
5948
  }
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5949
  /*
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5950
5951
   * ALC680 support
   */
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5952

d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5953
5954
  static int alc680_parse_auto_config(struct hda_codec *codec)
  {
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5955
  	return alc_parse_auto_config(codec, NULL, NULL);
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5956
  }
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5957
  /*
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5958
   */
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5959
5960
5961
  static int patch_alc680(struct hda_codec *codec)
  {
  	struct alc_spec *spec;
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5962
5963
5964
5965
5966
5967
5968
  	int err;
  
  	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
  	if (spec == NULL)
  		return -ENOMEM;
  
  	codec->spec = spec;
1f0f4b803   Takashi Iwai   ALSA: hda - Reduc...
5969
  	/* ALC680 has no aa-loopback mixer */
1ebec5f2a   Takashi Iwai   ALSA: hda - Remov...
5970
5971
5972
5973
5974
  	/* automatic parse from the BIOS config */
  	err = alc680_parse_auto_config(codec);
  	if (err < 0) {
  		alc_free(codec);
  		return err;
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5975
  	}
3e6179b84   Takashi Iwai   ALSA: hda - Merge...
5976
  	if (!spec->no_analog && !spec->cap_mixer)
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5977
  		set_capture_mixer(codec);
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5978
  	codec->patch_ops = alc_patch_ops;
1ebec5f2a   Takashi Iwai   ALSA: hda - Remov...
5979
  	spec->init_hook = alc_auto_init_std;
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
5980
5981
5982
5983
5984
  
  	return 0;
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5985
5986
   * patch entries
   */
a9111321f   Takashi Iwai   ALSA: hda - Const...
5987
  static const struct hda_codec_preset snd_hda_preset_realtek[] = {
296f03380   Kailang Yang   ALSA: hda - Add s...
5988
  	{ .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5989
  	{ .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 },
df694daa3   Kailang Yang   [ALSA] hda-codec ...
5990
  	{ .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 },
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
5991
  	{ .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 },
a361d84bf   Kailang Yang   [ALSA] hda-codec ...
5992
  	{ .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 },
f6a92248a   Kailang Yang   [ALSA] hda-codec ...
5993
  	{ .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 },
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5994
  	{ .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 },
01afd41f5   Kailang Yang   ALSA: hda - Add s...
5995
  	{ .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 },
ebb83eeb6   Kailang Yang   ALSA: hda - More ...
5996
  	{ .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 },
296f03380   Kailang Yang   ALSA: hda - Add s...
5997
  	{ .id = 0x10ec0276, .name = "ALC276", .patch = patch_alc269 },
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
5998
  	{ .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660",
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
5999
  	  .patch = patch_alc861 },
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
6000
6001
6002
  	{ .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd },
  	{ .id = 0x10ec0861, .name = "ALC861", .patch = patch_alc861 },
  	{ .id = 0x10ec0862, .name = "ALC861-VD", .patch = patch_alc861vd },
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
6003
  	{ .id = 0x10ec0662, .rev = 0x100002, .name = "ALC662 rev2",
4953550a6   Takashi Iwai   ALSA: hda - Merge...
6004
  	  .patch = patch_alc882 },
bc9f98a98   Kailang Yang   [ALSA] hda-codec ...
6005
6006
  	{ .id = 0x10ec0662, .rev = 0x100101, .name = "ALC662 rev1",
  	  .patch = patch_alc662 },
cc667a72d   David Henningsson   ALSA: HDA: Add ne...
6007
6008
  	{ .id = 0x10ec0662, .rev = 0x100300, .name = "ALC662 rev3",
  	  .patch = patch_alc662 },
6dda9f4a9   Kailang Yang   [ALSA] hda - Add ...
6009
  	{ .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 },
cec27c891   Kailang Yang   ALSA: hda - Add s...
6010
  	{ .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 },
6227cdced   Kailang Yang   ALSA: hda - Add A...
6011
  	{ .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 },
d1eb57f47   Kailang Yang   ALSA: hda - Suppo...
6012
  	{ .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 },
f32610eda   Jakub Schmidtke   [ALSA] hda-codec ...
6013
  	{ .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6014
  	{ .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 },
4953550a6   Takashi Iwai   ALSA: hda - Merge...
6015
  	{ .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 },
669faba27   Clive Messer   ALSA: hda - Fix a...
6016
  	{ .id = 0x10ec0885, .rev = 0x100101, .name = "ALC889A",
4953550a6   Takashi Iwai   ALSA: hda - Merge...
6017
  	  .patch = patch_alc882 },
cb308f97a   Takashi Iwai   [ALSA] hda - Fix ...
6018
  	{ .id = 0x10ec0885, .rev = 0x100103, .name = "ALC889A",
4953550a6   Takashi Iwai   ALSA: hda - Merge...
6019
  	  .patch = patch_alc882 },
df694daa3   Kailang Yang   [ALSA] hda-codec ...
6020
  	{ .id = 0x10ec0885, .name = "ALC885", .patch = patch_alc882 },
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
6021
  	{ .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 },
4442608d4   Kailang Yang   ALSA: hda - Add A...
6022
  	{ .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200",
4953550a6   Takashi Iwai   ALSA: hda - Merge...
6023
  	  .patch = patch_alc882 },
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
6024
  	{ .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 },
4953550a6   Takashi Iwai   ALSA: hda - Merge...
6025
  	{ .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 },
274693f37   Kailang Yang   ALSA: hda - Add A...
6026
  	{ .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 },
e16fb6d14   Takashi Iwai   ALSA: hda/realtek...
6027
  	{ .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6028
6029
  	{} /* terminator */
  };
1289e9e8b   Takashi Iwai   ALSA: hda - Modul...
6030
6031
6032
6033
6034
6035
6036
6037
6038
6039
6040
6041
6042
6043
6044
6045
6046
6047
6048
6049
6050
6051
6052
  
  MODULE_ALIAS("snd-hda-codec-id:10ec*");
  
  MODULE_LICENSE("GPL");
  MODULE_DESCRIPTION("Realtek HD-audio codec");
  
  static struct hda_codec_preset_list realtek_list = {
  	.preset = snd_hda_preset_realtek,
  	.owner = THIS_MODULE,
  };
  
  static int __init patch_realtek_init(void)
  {
  	return snd_hda_add_codec_preset(&realtek_list);
  }
  
  static void __exit patch_realtek_exit(void)
  {
  	snd_hda_delete_codec_preset(&realtek_list);
  }
  
  module_init(patch_realtek_init)
  module_exit(patch_realtek_exit)