blob: 290e09825b825716ec1c72abf37b35b8ba442db2 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Takashi Iwai0ac85512007-06-20 15:46:13 +02002 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
3 * AD1986A, AD1988
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Takashi Iwai2bac6472007-05-18 18:21:41 +02005 * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 *
7 * This driver is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This driver is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/slab.h>
24#include <linux/pci.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040025#include <linux/module.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010026
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <sound/core.h>
28#include "hda_codec.h"
29#include "hda_local.h"
Takashi Iwai128bc4b2012-05-07 17:42:31 +020030#include "hda_auto_parser.h"
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010031#include "hda_beep.h"
Takashi Iwai1835a0f2011-10-27 22:12:46 +020032#include "hda_jack.h"
Takashi Iwai78bb3cb2012-12-21 15:17:06 +010033#include "hda_generic.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034
Takashi Iwai9ff4bc82013-01-22 16:45:58 +010035#define ENABLE_AD_STATIC_QUIRKS
36
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020037struct ad198x_spec {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +010038 struct hda_gen_spec gen;
39
Takashi Iwai272f3ea2013-01-22 15:31:33 +010040 /* for auto parser */
41 int smux_paths[4];
42 unsigned int cur_smux;
Takashi Iwaia928bd22013-01-22 18:18:42 +010043 hda_nid_t eapd_nid;
Takashi Iwai272f3ea2013-01-22 15:31:33 +010044
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010045 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Takashi Iwai9ff4bc82013-01-22 16:45:58 +010046
47#ifdef ENABLE_AD_STATIC_QUIRKS
48 const struct snd_kcontrol_new *mixers[6];
49 int num_mixers;
Raymond Yau28220842011-02-08 19:58:25 +080050 const struct hda_verb *init_verbs[6]; /* initialization verbs
Takashi Iwai985be542005-11-02 18:26:49 +010051 * don't forget NULL termination!
52 */
53 unsigned int num_init_verbs;
54
55 /* playback */
56 struct hda_multi_out multiout; /* playback set-up
57 * max_channels, dacs must be set
58 * dig_out_nid and hp_nid are optional
59 */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +010060 unsigned int cur_eapd;
Takashi Iwai2125cad2006-03-27 12:52:22 +020061 unsigned int need_dac_fix;
Takashi Iwai985be542005-11-02 18:26:49 +010062
63 /* capture */
64 unsigned int num_adc_nids;
Takashi Iwai498f5b12011-05-02 11:33:15 +020065 const hda_nid_t *adc_nids;
Takashi Iwai985be542005-11-02 18:26:49 +010066 hda_nid_t dig_in_nid; /* digital-in NID; optional */
67
68 /* capture source */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020069 const struct hda_input_mux *input_mux;
Takashi Iwai498f5b12011-05-02 11:33:15 +020070 const hda_nid_t *capsrc_nids;
Takashi Iwai985be542005-11-02 18:26:49 +010071 unsigned int cur_mux[3];
72
73 /* channel model */
Takashi Iwaid2a6d7d2005-11-17 11:06:29 +010074 const struct hda_channel_mode *channel_mode;
Takashi Iwai985be542005-11-02 18:26:49 +010075 int num_channel_mode;
76
77 /* PCM information */
Takashi Iwai2bac6472007-05-18 18:21:41 +020078 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
Takashi Iwai985be542005-11-02 18:26:49 +010079
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020080 unsigned int spdif_route;
Takashi Iwaid32410b12005-11-24 16:06:23 +010081
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +010082 unsigned int jack_present: 1;
83 unsigned int inv_jack_detect: 1;/* inverted jack-detection */
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +010084 unsigned int analog_beep: 1; /* analog beep input present */
Takashi Iwai18478e82012-03-09 17:51:10 +010085 unsigned int avoid_init_slave_vol:1;
Takashi Iwai8ab78c72007-09-06 14:29:53 +020086
Takashi Iwai83012a72012-08-24 18:38:08 +020087#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +020088 struct hda_loopback_check loopback;
89#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +010090 /* for virtual master */
91 hda_nid_t vmaster_nid;
Takashi Iwaiea734962011-01-17 11:29:34 +010092 const char * const *slave_vols;
93 const char * const *slave_sws;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +010094#endif /* ENABLE_AD_STATIC_QUIRKS */
Linus Torvalds1da177e2005-04-16 15:20:36 -070095};
96
Takashi Iwai9ff4bc82013-01-22 16:45:58 +010097#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020098/*
99 * input MUX handling (common part)
100 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100101static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200102{
103 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
104 struct ad198x_spec *spec = codec->spec;
105
106 return snd_hda_input_mux_info(spec->input_mux, uinfo);
107}
108
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100109static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200110{
111 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
112 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100113 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200114
Takashi Iwai985be542005-11-02 18:26:49 +0100115 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200116 return 0;
117}
118
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100119static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200120{
121 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
122 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100123 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200124
125 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
Takashi Iwai2e5b9562005-11-21 16:36:15 +0100126 spec->capsrc_nids[adc_idx],
127 &spec->cur_mux[adc_idx]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200128}
129
130/*
131 * initialization (common callbacks)
132 */
133static int ad198x_init(struct hda_codec *codec)
134{
135 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100136 int i;
137
138 for (i = 0; i < spec->num_init_verbs; i++)
139 snd_hda_sequence_write(codec, spec->init_verbs[i]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200140 return 0;
141}
142
Takashi Iwai9322ca52012-02-03 14:28:01 +0100143static const char * const ad_slave_pfxs[] = {
144 "Front", "Surround", "Center", "LFE", "Side",
145 "Headphone", "Mono", "Speaker", "IEC958",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100146 NULL
147};
148
Takashi Iwai9322ca52012-02-03 14:28:01 +0100149static const char * const ad1988_6stack_fp_slave_pfxs[] = {
150 "Front", "Surround", "Center", "LFE", "Side", "IEC958",
Takashi Iwai2134ea42008-01-10 16:53:55 +0100151 NULL
152};
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100153#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai2134ea42008-01-10 16:53:55 +0100154
Takashi Iwai67d634c2009-11-16 15:35:59 +0100155#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100156/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwai498f5b12011-05-02 11:33:15 +0200157static const struct snd_kcontrol_new ad_beep_mixer[] = {
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100158 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +0200159 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100160 { } /* end */
161};
162
Takashi Iwai498f5b12011-05-02 11:33:15 +0200163static const struct snd_kcontrol_new ad_beep2_mixer[] = {
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +0100164 HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
165 HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
166 { } /* end */
167};
168
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100169#define set_beep_amp(spec, nid, idx, dir) \
170 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
Takashi Iwai67d634c2009-11-16 15:35:59 +0100171#else
172#define set_beep_amp(spec, nid, idx, dir) /* NOP */
173#endif
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100174
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100175#ifdef CONFIG_SND_HDA_INPUT_BEEP
176static int create_beep_ctls(struct hda_codec *codec)
177{
178 struct ad198x_spec *spec = codec->spec;
179 const struct snd_kcontrol_new *knew;
180
181 if (!spec->beep_amp)
182 return 0;
183
184 knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
185 for ( ; knew->name; knew++) {
186 int err;
187 struct snd_kcontrol *kctl;
188 kctl = snd_ctl_new1(knew, codec);
189 if (!kctl)
190 return -ENOMEM;
191 kctl->private_value = spec->beep_amp;
192 err = snd_hda_ctl_add(codec, 0, kctl);
193 if (err < 0)
194 return err;
195 }
196 return 0;
197}
198#else
199#define create_beep_ctls(codec) 0
200#endif
201
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100202#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200203static int ad198x_build_controls(struct hda_codec *codec)
204{
205 struct ad198x_spec *spec = codec->spec;
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100206 struct snd_kcontrol *kctl;
Takashi Iwai985be542005-11-02 18:26:49 +0100207 unsigned int i;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200208 int err;
209
Takashi Iwai985be542005-11-02 18:26:49 +0100210 for (i = 0; i < spec->num_mixers; i++) {
211 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
212 if (err < 0)
213 return err;
214 }
215 if (spec->multiout.dig_out_nid) {
Stephen Warren74b654c2011-06-01 11:14:18 -0600216 err = snd_hda_create_spdif_out_ctls(codec,
217 spec->multiout.dig_out_nid,
218 spec->multiout.dig_out_nid);
Takashi Iwai985be542005-11-02 18:26:49 +0100219 if (err < 0)
220 return err;
Takashi Iwai9a081602008-02-12 18:37:26 +0100221 err = snd_hda_create_spdif_share_sw(codec,
222 &spec->multiout);
223 if (err < 0)
224 return err;
225 spec->multiout.share_spdif = 1;
Takashi Iwai985be542005-11-02 18:26:49 +0100226 }
227 if (spec->dig_in_nid) {
228 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
229 if (err < 0)
230 return err;
231 }
Takashi Iwai2134ea42008-01-10 16:53:55 +0100232
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100233 /* create beep controls if needed */
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100234 err = create_beep_ctls(codec);
235 if (err < 0)
236 return err;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100237
Takashi Iwai2134ea42008-01-10 16:53:55 +0100238 /* if we have no master control, let's create it */
239 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100240 unsigned int vmaster_tlv[4];
Takashi Iwai2134ea42008-01-10 16:53:55 +0100241 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100242 HDA_OUTPUT, vmaster_tlv);
Takashi Iwai18478e82012-03-09 17:51:10 +0100243 err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
Takashi Iwai1c82ed12008-02-18 13:05:50 +0100244 vmaster_tlv,
Takashi Iwai2134ea42008-01-10 16:53:55 +0100245 (spec->slave_vols ?
Takashi Iwai9322ca52012-02-03 14:28:01 +0100246 spec->slave_vols : ad_slave_pfxs),
Takashi Iwai18478e82012-03-09 17:51:10 +0100247 "Playback Volume",
Takashi Iwai29e58532012-03-12 12:25:03 +0100248 !spec->avoid_init_slave_vol, NULL);
Takashi Iwai2134ea42008-01-10 16:53:55 +0100249 if (err < 0)
250 return err;
251 }
252 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
253 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
254 NULL,
255 (spec->slave_sws ?
Takashi Iwai9322ca52012-02-03 14:28:01 +0100256 spec->slave_sws : ad_slave_pfxs),
257 "Playback Switch");
Takashi Iwai2134ea42008-01-10 16:53:55 +0100258 if (err < 0)
259 return err;
260 }
261
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100262 /* assign Capture Source enums to NID */
263 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
264 if (!kctl)
265 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
266 for (i = 0; kctl && i < kctl->count; i++) {
Takashi Iwai21949f02009-12-23 08:31:59 +0100267 err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100268 if (err < 0)
269 return err;
270 }
271
272 /* assign IEC958 enums to NID */
273 kctl = snd_hda_find_mixer_ctl(codec,
274 SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
275 if (kctl) {
276 err = snd_hda_add_nid(codec, kctl, 0,
277 spec->multiout.dig_out_nid);
278 if (err < 0)
279 return err;
280 }
281
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200282 return 0;
283}
284
Takashi Iwai83012a72012-08-24 18:38:08 +0200285#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +0200286static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
287{
288 struct ad198x_spec *spec = codec->spec;
289 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
290}
291#endif
292
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200293/*
294 * Analog playback callbacks
295 */
296static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
297 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100298 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200299{
300 struct ad198x_spec *spec = codec->spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100301 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
Takashi Iwai9a081602008-02-12 18:37:26 +0100302 hinfo);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200303}
304
305static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
306 struct hda_codec *codec,
307 unsigned int stream_tag,
308 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100309 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200310{
311 struct ad198x_spec *spec = codec->spec;
312 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
313 format, substream);
314}
315
316static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
317 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100318 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200319{
320 struct ad198x_spec *spec = codec->spec;
321 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
322}
323
324/*
325 * Digital out
326 */
327static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
328 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100329 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200330{
331 struct ad198x_spec *spec = codec->spec;
332 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
333}
334
335static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
336 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100337 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200338{
339 struct ad198x_spec *spec = codec->spec;
340 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
341}
342
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200343static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
344 struct hda_codec *codec,
345 unsigned int stream_tag,
346 unsigned int format,
347 struct snd_pcm_substream *substream)
348{
349 struct ad198x_spec *spec = codec->spec;
350 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
351 format, substream);
352}
353
Takashi Iwai9411e212009-02-13 11:32:28 +0100354static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
355 struct hda_codec *codec,
356 struct snd_pcm_substream *substream)
357{
358 struct ad198x_spec *spec = codec->spec;
359 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
360}
361
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200362/*
363 * Analog capture
364 */
365static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
366 struct hda_codec *codec,
367 unsigned int stream_tag,
368 unsigned int format,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100369 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200370{
371 struct ad198x_spec *spec = codec->spec;
Takashi Iwai985be542005-11-02 18:26:49 +0100372 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
373 stream_tag, 0, format);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200374 return 0;
375}
376
377static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
378 struct hda_codec *codec,
Takashi Iwaic8b6bf92005-11-17 14:57:47 +0100379 struct snd_pcm_substream *substream)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200380{
381 struct ad198x_spec *spec = codec->spec;
Takashi Iwai888afa12008-03-18 09:57:50 +0100382 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200383 return 0;
384}
385
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200386/*
387 */
Takashi Iwai498f5b12011-05-02 11:33:15 +0200388static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200389 .substreams = 1,
390 .channels_min = 2,
Takashi Iwai985be542005-11-02 18:26:49 +0100391 .channels_max = 6, /* changed later */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200392 .nid = 0, /* fill later */
393 .ops = {
394 .open = ad198x_playback_pcm_open,
395 .prepare = ad198x_playback_pcm_prepare,
Raymond Yau34588702011-09-23 19:03:25 +0800396 .cleanup = ad198x_playback_pcm_cleanup,
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200397 },
398};
399
Takashi Iwai498f5b12011-05-02 11:33:15 +0200400static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
Takashi Iwai985be542005-11-02 18:26:49 +0100401 .substreams = 1,
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200402 .channels_min = 2,
403 .channels_max = 2,
404 .nid = 0, /* fill later */
405 .ops = {
406 .prepare = ad198x_capture_pcm_prepare,
407 .cleanup = ad198x_capture_pcm_cleanup
408 },
409};
410
Takashi Iwai498f5b12011-05-02 11:33:15 +0200411static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200412 .substreams = 1,
413 .channels_min = 2,
414 .channels_max = 2,
415 .nid = 0, /* fill later */
416 .ops = {
417 .open = ad198x_dig_playback_pcm_open,
Takashi Iwai6b97eb42007-04-05 14:51:48 +0200418 .close = ad198x_dig_playback_pcm_close,
Takashi Iwai9411e212009-02-13 11:32:28 +0100419 .prepare = ad198x_dig_playback_pcm_prepare,
420 .cleanup = ad198x_dig_playback_pcm_cleanup
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200421 },
422};
423
Takashi Iwai498f5b12011-05-02 11:33:15 +0200424static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
Takashi Iwai985be542005-11-02 18:26:49 +0100425 .substreams = 1,
426 .channels_min = 2,
427 .channels_max = 2,
428 /* NID is set in alc_build_pcms */
429};
430
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200431static int ad198x_build_pcms(struct hda_codec *codec)
432{
433 struct ad198x_spec *spec = codec->spec;
434 struct hda_pcm *info = spec->pcm_rec;
435
436 codec->num_pcms = 1;
437 codec->pcm_info = info;
438
439 info->name = "AD198x Analog";
440 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
441 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
442 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
443 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
Takashi Iwai985be542005-11-02 18:26:49 +0100444 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
445 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200446
447 if (spec->multiout.dig_out_nid) {
448 info++;
449 codec->num_pcms++;
Takashi Iwaiae24c312012-11-05 12:32:46 +0100450 codec->spdif_status_reset = 1;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200451 info->name = "AD198x Digital";
Takashi Iwai7ba72ba2008-02-06 14:03:20 +0100452 info->pcm_type = HDA_PCM_TYPE_SPDIF;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200453 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
454 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
Takashi Iwai985be542005-11-02 18:26:49 +0100455 if (spec->dig_in_nid) {
456 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
457 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
458 }
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200459 }
460
461 return 0;
462}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100463#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200464
Daniel T Chenea52bf22009-12-27 18:48:29 -0500465static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
466 hda_nid_t hp)
467{
Raymond Yaua01ef052011-06-01 15:09:48 +0800468 if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
469 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100470 !codec->inv_eapd ? 0x00 : 0x02);
Raymond Yaua01ef052011-06-01 15:09:48 +0800471 if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
472 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100473 !codec->inv_eapd ? 0x00 : 0x02);
Daniel T Chenea52bf22009-12-27 18:48:29 -0500474}
475
476static void ad198x_power_eapd(struct hda_codec *codec)
477{
478 /* We currently only handle front, HP */
479 switch (codec->vendor_id) {
480 case 0x11d41882:
481 case 0x11d4882a:
482 case 0x11d41884:
483 case 0x11d41984:
484 case 0x11d41883:
485 case 0x11d4184a:
486 case 0x11d4194a:
487 case 0x11d4194b:
Takashi Iwai4dffbe02011-06-03 10:05:02 +0200488 case 0x11d41988:
489 case 0x11d4198b:
490 case 0x11d4989a:
491 case 0x11d4989b:
Daniel T Chenea52bf22009-12-27 18:48:29 -0500492 ad198x_power_eapd_write(codec, 0x12, 0x11);
493 break;
494 case 0x11d41981:
495 case 0x11d41983:
496 ad198x_power_eapd_write(codec, 0x05, 0x06);
497 break;
498 case 0x11d41986:
499 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
500 break;
Daniel T Chenea52bf22009-12-27 18:48:29 -0500501 }
502}
503
Takashi Iwai0da26922011-04-26 15:18:33 +0200504static void ad198x_shutup(struct hda_codec *codec)
505{
506 snd_hda_shutup_pins(codec);
507 ad198x_power_eapd(codec);
508}
509
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200510static void ad198x_free(struct hda_codec *codec)
511{
Takashi Iwaid32410b12005-11-24 16:06:23 +0100512 struct ad198x_spec *spec = codec->spec;
Takashi Iwaid32410b12005-11-24 16:06:23 +0100513
Takashi Iwai603c4012008-07-30 15:01:44 +0200514 if (!spec)
515 return;
516
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100517 snd_hda_gen_spec_free(&spec->gen);
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100518 kfree(spec);
519 snd_hda_detach_beep_device(codec);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200520}
521
Takashi Iwai2a439522011-07-26 09:52:50 +0200522#ifdef CONFIG_PM
Takashi Iwai68cb2b52012-07-02 15:20:37 +0200523static int ad198x_suspend(struct hda_codec *codec)
Daniel T Chenea52bf22009-12-27 18:48:29 -0500524{
525 ad198x_shutup(codec);
Daniel T Chenea52bf22009-12-27 18:48:29 -0500526 return 0;
527}
Daniel T Chenea52bf22009-12-27 18:48:29 -0500528#endif
529
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100530#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai498f5b12011-05-02 11:33:15 +0200531static const struct hda_codec_ops ad198x_patch_ops = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200532 .build_controls = ad198x_build_controls,
533 .build_pcms = ad198x_build_pcms,
534 .init = ad198x_init,
535 .free = ad198x_free,
Takashi Iwai2a439522011-07-26 09:52:50 +0200536#ifdef CONFIG_PM
Takashi Iwai83012a72012-08-24 18:38:08 +0200537 .check_power_status = ad198x_check_power_status,
Daniel T Chenea52bf22009-12-27 18:48:29 -0500538 .suspend = ad198x_suspend,
Daniel T Chenea52bf22009-12-27 18:48:29 -0500539#endif
540 .reboot_notify = ad198x_shutup,
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200541};
542
543
544/*
Takashi Iwai18a815d2006-03-01 19:54:39 +0100545 * EAPD control
Takashi Iwaiee6e3652009-12-08 17:23:33 +0100546 * the private value = nid
Takashi Iwai18a815d2006-03-01 19:54:39 +0100547 */
Takashi Iwaia5ce8892007-07-23 15:42:26 +0200548#define ad198x_eapd_info snd_ctl_boolean_mono_info
Takashi Iwai18a815d2006-03-01 19:54:39 +0100549
550static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
551 struct snd_ctl_elem_value *ucontrol)
552{
553 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
554 struct ad198x_spec *spec = codec->spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100555 if (codec->inv_eapd)
Takashi Iwai18a815d2006-03-01 19:54:39 +0100556 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
557 else
558 ucontrol->value.integer.value[0] = spec->cur_eapd;
559 return 0;
560}
561
562static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
563 struct snd_ctl_elem_value *ucontrol)
564{
565 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
566 struct ad198x_spec *spec = codec->spec;
Takashi Iwai18a815d2006-03-01 19:54:39 +0100567 hda_nid_t nid = kcontrol->private_value & 0xff;
568 unsigned int eapd;
Takashi Iwai68ea7b22007-11-15 15:54:38 +0100569 eapd = !!ucontrol->value.integer.value[0];
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100570 if (codec->inv_eapd)
Takashi Iwai18a815d2006-03-01 19:54:39 +0100571 eapd = !eapd;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200572 if (eapd == spec->cur_eapd)
Takashi Iwai18a815d2006-03-01 19:54:39 +0100573 return 0;
574 spec->cur_eapd = eapd;
Takashi Iwai82beb8f2007-08-10 17:09:26 +0200575 snd_hda_codec_write_cache(codec, nid,
576 0, AC_VERB_SET_EAPD_BTLENABLE,
577 eapd ? 0x02 : 0x00);
Takashi Iwai18a815d2006-03-01 19:54:39 +0100578 return 1;
579}
580
Takashi Iwai9230d212006-03-13 13:49:49 +0100581static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
582 struct snd_ctl_elem_info *uinfo);
583static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
584 struct snd_ctl_elem_value *ucontrol);
585static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
586 struct snd_ctl_elem_value *ucontrol);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100587#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai9230d212006-03-13 13:49:49 +0100588
589
Takashi Iwai18a815d2006-03-01 19:54:39 +0100590/*
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100591 * Automatic parse of I/O pins from the BIOS configuration
592 */
593
594static int ad198x_auto_build_controls(struct hda_codec *codec)
595{
596 int err;
597
598 err = snd_hda_gen_build_controls(codec);
599 if (err < 0)
600 return err;
601 err = create_beep_ctls(codec);
602 if (err < 0)
603 return err;
604 return 0;
605}
606
607static const struct hda_codec_ops ad198x_auto_patch_ops = {
608 .build_controls = ad198x_auto_build_controls,
609 .build_pcms = snd_hda_gen_build_pcms,
610 .init = snd_hda_gen_init,
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100611 .free = snd_hda_gen_free,
Takashi Iwai8a6c21a2013-01-18 07:51:17 +0100612 .unsol_event = snd_hda_jack_unsol_event,
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100613#ifdef CONFIG_PM
614 .check_power_status = snd_hda_gen_check_power_status,
615 .suspend = ad198x_suspend,
616#endif
617 .reboot_notify = ad198x_shutup,
618};
619
620
621static int ad198x_parse_auto_config(struct hda_codec *codec)
622{
623 struct ad198x_spec *spec = codec->spec;
624 struct auto_pin_cfg *cfg = &spec->gen.autocfg;
625 int err;
626
627 codec->spdif_status_reset = 1;
628 codec->no_trigger_sense = 1;
629 codec->no_sticky_stream = 1;
630
631 spec->gen.indep_hp = 1;
632
633 err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
634 if (err < 0)
635 return err;
636 err = snd_hda_gen_parse_auto_config(codec, cfg);
637 if (err < 0)
638 return err;
639
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100640 codec->patch_ops = ad198x_auto_patch_ops;
641
642 return 0;
643}
644
645/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200646 * AD1986A specific
647 */
648
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100649#ifdef ENABLE_AD_STATIC_QUIRKS
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650#define AD1986A_SPDIF_OUT 0x02
651#define AD1986A_FRONT_DAC 0x03
652#define AD1986A_SURR_DAC 0x04
653#define AD1986A_CLFE_DAC 0x05
654#define AD1986A_ADC 0x06
655
Takashi Iwai498f5b12011-05-02 11:33:15 +0200656static const hda_nid_t ad1986a_dac_nids[3] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
658};
Takashi Iwai498f5b12011-05-02 11:33:15 +0200659static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
660static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Takashi Iwai498f5b12011-05-02 11:33:15 +0200662static const struct hda_input_mux ad1986a_capture_source = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 .num_items = 7,
664 .items = {
665 { "Mic", 0x0 },
666 { "CD", 0x1 },
667 { "Aux", 0x3 },
668 { "Line", 0x4 },
669 { "Mix", 0x5 },
670 { "Mono", 0x6 },
671 { "Phone", 0x7 },
672 },
673};
674
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675
Takashi Iwai498f5b12011-05-02 11:33:15 +0200676static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
Takashi Iwai532d5382007-07-27 19:02:40 +0200677 .ops = &snd_hda_bind_vol,
678 .values = {
679 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
680 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
681 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
682 0
683 },
684};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700685
Takashi Iwai498f5b12011-05-02 11:33:15 +0200686static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
Takashi Iwai532d5382007-07-27 19:02:40 +0200687 .ops = &snd_hda_bind_sw,
688 .values = {
689 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
690 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
691 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
692 0
693 },
694};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695
696/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 * mixers
698 */
Takashi Iwai498f5b12011-05-02 11:33:15 +0200699static const struct snd_kcontrol_new ad1986a_mixers[] = {
Takashi Iwai532d5382007-07-27 19:02:40 +0200700 /*
701 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
702 */
703 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
704 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
706 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
707 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
708 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
709 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
710 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
711 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
712 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
713 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
714 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
715 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
716 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
717 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
718 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
719 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
720 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
721 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
722 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +0100723 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
725 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
726 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
727 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
728 {
729 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
730 .name = "Capture Source",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200731 .info = ad198x_mux_enum_info,
732 .get = ad198x_mux_enum_get,
733 .put = ad198x_mux_enum_put,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 },
735 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
736 { } /* end */
737};
738
Takashi Iwai9230d212006-03-13 13:49:49 +0100739/* additional mixers for 3stack mode */
Takashi Iwai498f5b12011-05-02 11:33:15 +0200740static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
Takashi Iwai9230d212006-03-13 13:49:49 +0100741 {
742 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
743 .name = "Channel Mode",
744 .info = ad198x_ch_mode_info,
745 .get = ad198x_ch_mode_get,
746 .put = ad198x_ch_mode_put,
747 },
748 { } /* end */
749};
750
751/* laptop model - 2ch only */
Takashi Iwai498f5b12011-05-02 11:33:15 +0200752static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
Takashi Iwai9230d212006-03-13 13:49:49 +0100753
Takashi Iwai20a45e82007-08-15 22:20:45 +0200754/* master controls both pins 0x1a and 0x1b */
Takashi Iwai498f5b12011-05-02 11:33:15 +0200755static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
Takashi Iwai20a45e82007-08-15 22:20:45 +0200756 .ops = &snd_hda_bind_vol,
757 .values = {
758 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
759 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
760 0,
761 },
762};
763
Takashi Iwai498f5b12011-05-02 11:33:15 +0200764static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
Takashi Iwai20a45e82007-08-15 22:20:45 +0200765 .ops = &snd_hda_bind_sw,
766 .values = {
767 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
768 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
769 0,
770 },
771};
772
Takashi Iwai498f5b12011-05-02 11:33:15 +0200773static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
Takashi Iwai9230d212006-03-13 13:49:49 +0100774 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
775 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
Takashi Iwai20a45e82007-08-15 22:20:45 +0200776 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
777 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
Takashi Iwai9230d212006-03-13 13:49:49 +0100778 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
779 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
780 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
781 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
782 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
783 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
784 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
785 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +0100786 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100787 /*
Takashi Iwai9230d212006-03-13 13:49:49 +0100788 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
789 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
790 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
791 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
792 {
793 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
794 .name = "Capture Source",
795 .info = ad198x_mux_enum_info,
796 .get = ad198x_mux_enum_get,
797 .put = ad198x_mux_enum_put,
798 },
799 { } /* end */
800};
801
Takashi Iwai825aa9722006-03-17 10:50:49 +0100802/* laptop-eapd model - 2ch only */
803
Takashi Iwai498f5b12011-05-02 11:33:15 +0200804static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
Takashi Iwai825aa9722006-03-17 10:50:49 +0100805 .num_items = 3,
806 .items = {
807 { "Mic", 0x0 },
808 { "Internal Mic", 0x4 },
809 { "Mix", 0x5 },
810 },
811};
812
Takashi Iwai498f5b12011-05-02 11:33:15 +0200813static const struct hda_input_mux ad1986a_automic_capture_source = {
Takashi Iwai5d5d5f42008-02-12 12:11:36 +0100814 .num_items = 2,
815 .items = {
816 { "Mic", 0x0 },
817 { "Mix", 0x5 },
818 },
819};
820
Takashi Iwai498f5b12011-05-02 11:33:15 +0200821static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
Takashi Iwai532d5382007-07-27 19:02:40 +0200822 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
823 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
Takashi Iwai16d11a82009-06-24 14:07:53 +0200824 { } /* end */
825};
826
Takashi Iwai498f5b12011-05-02 11:33:15 +0200827static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
Takashi Iwai825aa9722006-03-17 10:50:49 +0100828 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
829 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
Takashi Iwai1725b822008-11-21 02:25:48 +0100830 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
831 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +0100832 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
Takashi Iwai1725b822008-11-21 02:25:48 +0100833 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
834 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
835 {
836 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
837 .name = "Capture Source",
838 .info = ad198x_mux_enum_info,
839 .get = ad198x_mux_enum_get,
840 .put = ad198x_mux_enum_put,
841 },
842 {
843 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
844 .name = "External Amplifier",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +0100845 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
Takashi Iwai1725b822008-11-21 02:25:48 +0100846 .info = ad198x_eapd_info,
847 .get = ad198x_eapd_get,
848 .put = ad198x_eapd_put,
Takashi Iwaiee6e3652009-12-08 17:23:33 +0100849 .private_value = 0x1b, /* port-D */
Takashi Iwai1725b822008-11-21 02:25:48 +0100850 },
851 { } /* end */
852};
853
Takashi Iwai498f5b12011-05-02 11:33:15 +0200854static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
Takashi Iwai16d11a82009-06-24 14:07:53 +0200855 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
856 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
Takashi Iwai825aa9722006-03-17 10:50:49 +0100857 { } /* end */
858};
859
Takashi Iwai5d5d5f42008-02-12 12:11:36 +0100860/* re-connect the mic boost input according to the jack sensing */
861static void ad1986a_automic(struct hda_codec *codec)
862{
863 unsigned int present;
Takashi Iwaid56757a2009-11-18 08:00:14 +0100864 present = snd_hda_jack_detect(codec, 0x1f);
Takashi Iwai5d5d5f42008-02-12 12:11:36 +0100865 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
866 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
Takashi Iwaid56757a2009-11-18 08:00:14 +0100867 present ? 0 : 2);
Takashi Iwai5d5d5f42008-02-12 12:11:36 +0100868}
869
870#define AD1986A_MIC_EVENT 0x36
871
872static void ad1986a_automic_unsol_event(struct hda_codec *codec,
873 unsigned int res)
874{
875 if ((res >> 26) != AD1986A_MIC_EVENT)
876 return;
877 ad1986a_automic(codec);
878}
879
880static int ad1986a_automic_init(struct hda_codec *codec)
881{
882 ad198x_init(codec);
883 ad1986a_automic(codec);
884 return 0;
885}
886
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200887/* laptop-automute - 2ch only */
888
889static void ad1986a_update_hp(struct hda_codec *codec)
890{
891 struct ad198x_spec *spec = codec->spec;
892 unsigned int mute;
893
894 if (spec->jack_present)
895 mute = HDA_AMP_MUTE; /* mute internal speaker */
896 else
897 /* unmute internal speaker if necessary */
898 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
899 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
900 HDA_AMP_MUTE, mute);
901}
902
903static void ad1986a_hp_automute(struct hda_codec *codec)
904{
905 struct ad198x_spec *spec = codec->spec;
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200906
Takashi Iwaid56757a2009-11-18 08:00:14 +0100907 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
Takashi Iwai03c405a2009-06-24 14:10:15 +0200908 if (spec->inv_jack_detect)
909 spec->jack_present = !spec->jack_present;
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200910 ad1986a_update_hp(codec);
911}
912
913#define AD1986A_HP_EVENT 0x37
914
915static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
916{
917 if ((res >> 26) != AD1986A_HP_EVENT)
918 return;
919 ad1986a_hp_automute(codec);
920}
921
922static int ad1986a_hp_init(struct hda_codec *codec)
923{
924 ad198x_init(codec);
925 ad1986a_hp_automute(codec);
926 return 0;
927}
928
929/* bind hp and internal speaker mute (with plug check) */
930static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
931 struct snd_ctl_elem_value *ucontrol)
932{
933 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai8092e602012-12-13 17:03:30 +0100934 int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200935 if (change)
936 ad1986a_update_hp(codec);
937 return change;
938}
939
Takashi Iwai498f5b12011-05-02 11:33:15 +0200940static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200941 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
942 {
943 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
944 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +0100945 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200946 .info = snd_hda_mixer_amp_switch_info,
947 .get = snd_hda_mixer_amp_switch_get,
948 .put = ad1986a_hp_master_sw_put,
949 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
950 },
Takashi Iwai8ab78c72007-09-06 14:29:53 +0200951 { } /* end */
952};
953
Takashi Iwai16d11a82009-06-24 14:07:53 +0200954
Linus Torvalds1da177e2005-04-16 15:20:36 -0700955/*
956 * initialization verbs
957 */
Takashi Iwai498f5b12011-05-02 11:33:15 +0200958static const struct hda_verb ad1986a_init_verbs[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700959 /* Front, Surround, CLFE DAC; mute as default */
960 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
961 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
962 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
963 /* Downmix - off */
964 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
965 /* HP, Line-Out, Surround, CLFE selectors */
966 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
967 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
968 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
969 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
970 /* Mono selector */
971 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
972 /* Mic selector: Mic 1/2 pin */
973 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
974 /* Line-in selector: Line-in */
975 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
976 /* Mic 1/2 swap */
977 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
978 /* Record selector: mic */
979 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
980 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
981 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
982 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
983 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
984 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
985 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
986 /* PC beep */
987 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
988 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
989 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
990 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
991 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
992 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
993 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200994 /* HP Pin */
995 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
996 /* Front, Surround, CLFE Pins */
997 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
998 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
999 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1000 /* Mono Pin */
1001 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1002 /* Mic Pin */
1003 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1004 /* Line, Aux, CD, Beep-In Pin */
1005 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1006 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1007 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1008 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1009 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 { } /* end */
1011};
1012
Takashi Iwai498f5b12011-05-02 11:33:15 +02001013static const struct hda_verb ad1986a_ch2_init[] = {
Takashi Iwai9230d212006-03-13 13:49:49 +01001014 /* Surround out -> Line In */
Takashi Iwaifb956c12007-04-18 23:03:56 +02001015 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1016 /* Line-in selectors */
1017 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
Takashi Iwai9230d212006-03-13 13:49:49 +01001018 /* CLFE -> Mic in */
Takashi Iwaifb956c12007-04-18 23:03:56 +02001019 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1020 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
1021 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
Takashi Iwai9230d212006-03-13 13:49:49 +01001022 { } /* end */
1023};
1024
Takashi Iwai498f5b12011-05-02 11:33:15 +02001025static const struct hda_verb ad1986a_ch4_init[] = {
Takashi Iwai9230d212006-03-13 13:49:49 +01001026 /* Surround out -> Surround */
Takashi Iwaifb956c12007-04-18 23:03:56 +02001027 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1028 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
Takashi Iwai9230d212006-03-13 13:49:49 +01001029 /* CLFE -> Mic in */
Takashi Iwaifb956c12007-04-18 23:03:56 +02001030 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1031 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
Takashi Iwai9230d212006-03-13 13:49:49 +01001032 { } /* end */
1033};
1034
Takashi Iwai498f5b12011-05-02 11:33:15 +02001035static const struct hda_verb ad1986a_ch6_init[] = {
Takashi Iwai9230d212006-03-13 13:49:49 +01001036 /* Surround out -> Surround out */
Takashi Iwaifb956c12007-04-18 23:03:56 +02001037 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1038 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
Takashi Iwai9230d212006-03-13 13:49:49 +01001039 /* CLFE -> CLFE */
Takashi Iwaifb956c12007-04-18 23:03:56 +02001040 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1041 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
Takashi Iwai9230d212006-03-13 13:49:49 +01001042 { } /* end */
1043};
1044
Takashi Iwai498f5b12011-05-02 11:33:15 +02001045static const struct hda_channel_mode ad1986a_modes[3] = {
Takashi Iwai9230d212006-03-13 13:49:49 +01001046 { 2, ad1986a_ch2_init },
1047 { 4, ad1986a_ch4_init },
1048 { 6, ad1986a_ch6_init },
1049};
1050
Takashi Iwai825aa9722006-03-17 10:50:49 +01001051/* eapd initialization */
Takashi Iwai498f5b12011-05-02 11:33:15 +02001052static const struct hda_verb ad1986a_eapd_init_verbs[] = {
Tobin Davisf36090f2007-01-08 11:07:12 +01001053 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
Takashi Iwai825aa9722006-03-17 10:50:49 +01001054 {}
1055};
1056
Takashi Iwai498f5b12011-05-02 11:33:15 +02001057static const struct hda_verb ad1986a_automic_verbs[] = {
Takashi Iwai5d5d5f42008-02-12 12:11:36 +01001058 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1059 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1060 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
1061 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1062 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
1063 {}
1064};
1065
Tobin Davisf36090f2007-01-08 11:07:12 +01001066/* Ultra initialization */
Takashi Iwai498f5b12011-05-02 11:33:15 +02001067static const struct hda_verb ad1986a_ultra_init[] = {
Tobin Davisf36090f2007-01-08 11:07:12 +01001068 /* eapd initialization */
1069 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1070 /* CLFE -> Mic in */
1071 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
1072 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1073 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
1074 { } /* end */
1075};
1076
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001077/* pin sensing on HP jack */
Takashi Iwai498f5b12011-05-02 11:33:15 +02001078static const struct hda_verb ad1986a_hp_init_verbs[] = {
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001079 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1080 {}
1081};
1082
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001083static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
1084 unsigned int res)
1085{
1086 switch (res >> 26) {
1087 case AD1986A_HP_EVENT:
1088 ad1986a_hp_automute(codec);
1089 break;
1090 case AD1986A_MIC_EVENT:
1091 ad1986a_automic(codec);
1092 break;
1093 }
1094}
1095
1096static int ad1986a_samsung_p50_init(struct hda_codec *codec)
1097{
1098 ad198x_init(codec);
1099 ad1986a_hp_automute(codec);
1100 ad1986a_automic(codec);
1101 return 0;
1102}
1103
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001104
Takashi Iwai9230d212006-03-13 13:49:49 +01001105/* models */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001106enum {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001107 AD1986A_AUTO,
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001108 AD1986A_6STACK,
1109 AD1986A_3STACK,
1110 AD1986A_LAPTOP,
1111 AD1986A_LAPTOP_EAPD,
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001112 AD1986A_LAPTOP_AUTOMUTE,
Tobin Davisf36090f2007-01-08 11:07:12 +01001113 AD1986A_ULTRA,
Takashi Iwai1725b822008-11-21 02:25:48 +01001114 AD1986A_SAMSUNG,
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001115 AD1986A_SAMSUNG_P50,
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001116 AD1986A_MODELS
1117};
Takashi Iwai9230d212006-03-13 13:49:49 +01001118
Takashi Iwaiea734962011-01-17 11:29:34 +01001119static const char * const ad1986a_models[AD1986A_MODELS] = {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001120 [AD1986A_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001121 [AD1986A_6STACK] = "6stack",
1122 [AD1986A_3STACK] = "3stack",
1123 [AD1986A_LAPTOP] = "laptop",
1124 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001125 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
Tobin Davisf36090f2007-01-08 11:07:12 +01001126 [AD1986A_ULTRA] = "ultra",
Takashi Iwai1725b822008-11-21 02:25:48 +01001127 [AD1986A_SAMSUNG] = "samsung",
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001128 [AD1986A_SAMSUNG_P50] = "samsung-p50",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001129};
1130
Takashi Iwai498f5b12011-05-02 11:33:15 +02001131static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001132 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001133 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001134 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001135 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001136 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
1137 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
1138 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
1139 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
Tobin Davisd9f9b8b2007-11-05 15:13:51 +01001140 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
Tobin Davis658fba02007-04-23 16:41:12 +02001141 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001142 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1143 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1144 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1145 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1146 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001147 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
Daniel T Chenba579eb2010-02-20 11:16:30 -05001148 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
Tobin Davis18768992007-03-12 22:20:51 +01001149 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001150 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001151 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
Tobin Davisf36090f2007-01-08 11:07:12 +01001152 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
Takashi Iwaidea0a502009-02-09 17:14:52 +01001153 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01001154 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
Tobin Davis18768992007-03-12 22:20:51 +01001155 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001156 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001157 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
Takashi Iwaif5fcc132006-11-24 17:07:44 +01001158 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
Takashi Iwai9230d212006-03-13 13:49:49 +01001159 {}
1160};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001161
Takashi Iwai83012a72012-08-24 18:38:08 +02001162#ifdef CONFIG_PM
Takashi Iwai498f5b12011-05-02 11:33:15 +02001163static const struct hda_amp_list ad1986a_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02001164 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1165 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1166 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1167 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1168 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1169 { } /* end */
1170};
1171#endif
1172
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001173static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1174{
Takashi Iwai2f334f92009-02-20 14:37:42 +01001175 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001176 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1177}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001178#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001179
Takashi Iwai361dab32012-05-09 14:35:27 +02001180static int alloc_ad_spec(struct hda_codec *codec)
1181{
1182 struct ad198x_spec *spec;
1183
1184 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1185 if (!spec)
1186 return -ENOMEM;
1187 codec->spec = spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001188 snd_hda_gen_spec_init(&spec->gen);
Takashi Iwai361dab32012-05-09 14:35:27 +02001189 return 0;
1190}
1191
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001192/*
Takashi Iwaia928bd22013-01-22 18:18:42 +01001193 * AD1986A fixup codes
1194 */
1195
1196/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
1197static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
1198 const struct hda_fixup *fix, int action)
1199{
Takashi Iwaib5c32fe2013-11-13 09:39:08 +01001200 struct ad198x_spec *spec = codec->spec;
1201
1202 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
Takashi Iwaia928bd22013-01-22 18:18:42 +01001203 codec->inv_jack_detect = 1;
Takashi Iwaib5c32fe2013-11-13 09:39:08 +01001204 spec->gen.keep_eapd_on = 1;
1205 }
Takashi Iwaia928bd22013-01-22 18:18:42 +01001206}
1207
1208enum {
1209 AD1986A_FIXUP_INV_JACK_DETECT,
1210};
1211
1212static const struct hda_fixup ad1986a_fixups[] = {
1213 [AD1986A_FIXUP_INV_JACK_DETECT] = {
1214 .type = HDA_FIXUP_FUNC,
1215 .v.func = ad_fixup_inv_jack_detect,
1216 },
1217};
1218
1219static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
1220 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
1221 {}
1222};
1223
1224/*
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001225 */
1226static int ad1986a_parse_auto_config(struct hda_codec *codec)
1227{
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001228 int err;
1229 struct ad198x_spec *spec;
Takashi Iwai2a9f6832013-12-10 17:29:26 +01001230 static hda_nid_t preferred_pairs[] = {
1231 0x1a, 0x03,
1232 0x1b, 0x03,
1233 0x1c, 0x04,
1234 0x1d, 0x05,
1235 0x1e, 0x03,
1236 0
1237 };
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001238
1239 err = alloc_ad_spec(codec);
1240 if (err < 0)
1241 return err;
1242 spec = codec->spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001243
1244 /* AD1986A has the inverted EAPD implementation */
1245 codec->inv_eapd = 1;
1246
Takashi Iwaif2f8be42013-01-21 16:40:16 +01001247 spec->gen.mixer_nid = 0x07;
Takashi Iwai7504b6c2013-03-18 11:25:51 +01001248 spec->gen.beep_nid = 0x19;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001249 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1250
1251 /* AD1986A has a hardware problem that it can't share a stream
1252 * with multiple output pins. The copy of front to surrounds
1253 * causes noisy or silent outputs at a certain timing, e.g.
1254 * changing the volume.
1255 * So, let's disable the shared stream.
1256 */
1257 spec->gen.multiout.no_share_stream = 1;
Takashi Iwai2a9f6832013-12-10 17:29:26 +01001258 /* give fixed DAC/pin pairs */
1259 spec->gen.preferred_dacs = preferred_pairs;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001260
Takashi Iwaia928bd22013-01-22 18:18:42 +01001261 snd_hda_pick_fixup(codec, NULL, ad1986a_fixup_tbl, ad1986a_fixups);
1262 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1263
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001264 err = ad198x_parse_auto_config(codec);
1265 if (err < 0) {
Takashi Iwai7504b6c2013-03-18 11:25:51 +01001266 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001267 return err;
1268 }
1269
Takashi Iwaia928bd22013-01-22 18:18:42 +01001270 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1271
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001272 return 0;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001273}
1274
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001275#ifdef ENABLE_AD_STATIC_QUIRKS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276static int patch_ad1986a(struct hda_codec *codec)
1277{
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001278 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001279 int err, board_config;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001281 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1282 ad1986a_models,
1283 ad1986a_cfg_tbl);
Takashi Iwai657e1b92013-01-22 18:42:39 +01001284 if (board_config < 0) {
1285 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
1286 codec->chip_name);
1287 board_config = AD1986A_AUTO;
1288 }
1289
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001290 if (board_config == AD1986A_AUTO)
1291 return ad1986a_parse_auto_config(codec);
1292
Takashi Iwai361dab32012-05-09 14:35:27 +02001293 err = alloc_ad_spec(codec);
1294 if (err < 0)
1295 return err;
1296 spec = codec->spec;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001297
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001298 err = snd_hda_attach_beep_device(codec, 0x19);
1299 if (err < 0) {
1300 ad198x_free(codec);
1301 return err;
1302 }
1303 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1304
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 spec->multiout.max_channels = 6;
1306 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1307 spec->multiout.dac_nids = ad1986a_dac_nids;
1308 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +01001309 spec->num_adc_nids = 1;
1310 spec->adc_nids = ad1986a_adc_nids;
Takashi Iwaia7ee8202006-03-01 20:05:39 +01001311 spec->capsrc_nids = ad1986a_capsrc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001312 spec->input_mux = &ad1986a_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +01001313 spec->num_mixers = 1;
1314 spec->mixers[0] = ad1986a_mixers;
1315 spec->num_init_verbs = 1;
1316 spec->init_verbs[0] = ad1986a_init_verbs;
Takashi Iwai83012a72012-08-24 18:38:08 +02001317#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +02001318 spec->loopback.amplist = ad1986a_loopbacks;
1319#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01001320 spec->vmaster_nid = 0x1b;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001321 codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001322
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001323 codec->patch_ops = ad198x_patch_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001324
Takashi Iwai9230d212006-03-13 13:49:49 +01001325 /* override some parameters */
Takashi Iwai9230d212006-03-13 13:49:49 +01001326 switch (board_config) {
1327 case AD1986A_3STACK:
1328 spec->num_mixers = 2;
1329 spec->mixers[1] = ad1986a_3st_mixers;
Takashi Iwaifb956c12007-04-18 23:03:56 +02001330 spec->num_init_verbs = 2;
1331 spec->init_verbs[1] = ad1986a_ch2_init;
Takashi Iwai9230d212006-03-13 13:49:49 +01001332 spec->channel_mode = ad1986a_modes;
1333 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
Takashi Iwai2125cad2006-03-27 12:52:22 +02001334 spec->need_dac_fix = 1;
1335 spec->multiout.max_channels = 2;
1336 spec->multiout.num_dacs = 1;
Takashi Iwai9230d212006-03-13 13:49:49 +01001337 break;
1338 case AD1986A_LAPTOP:
1339 spec->mixers[0] = ad1986a_laptop_mixers;
1340 spec->multiout.max_channels = 2;
1341 spec->multiout.num_dacs = 1;
1342 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1343 break;
Takashi Iwai825aa9722006-03-17 10:50:49 +01001344 case AD1986A_LAPTOP_EAPD:
Takashi Iwai16d11a82009-06-24 14:07:53 +02001345 spec->num_mixers = 3;
1346 spec->mixers[0] = ad1986a_laptop_master_mixers;
1347 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1348 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
Takashi Iwai1725b822008-11-21 02:25:48 +01001349 spec->num_init_verbs = 2;
1350 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1351 spec->multiout.max_channels = 2;
1352 spec->multiout.num_dacs = 1;
1353 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1354 if (!is_jack_available(codec, 0x25))
1355 spec->multiout.dig_out_nid = 0;
1356 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1357 break;
1358 case AD1986A_SAMSUNG:
Takashi Iwai16d11a82009-06-24 14:07:53 +02001359 spec->num_mixers = 2;
1360 spec->mixers[0] = ad1986a_laptop_master_mixers;
1361 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
Takashi Iwai5d5d5f42008-02-12 12:11:36 +01001362 spec->num_init_verbs = 3;
Takashi Iwai825aa9722006-03-17 10:50:49 +01001363 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
Takashi Iwai5d5d5f42008-02-12 12:11:36 +01001364 spec->init_verbs[2] = ad1986a_automic_verbs;
Takashi Iwai825aa9722006-03-17 10:50:49 +01001365 spec->multiout.max_channels = 2;
1366 spec->multiout.num_dacs = 1;
1367 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001368 if (!is_jack_available(codec, 0x25))
1369 spec->multiout.dig_out_nid = 0;
Takashi Iwai5d5d5f42008-02-12 12:11:36 +01001370 spec->input_mux = &ad1986a_automic_capture_source;
1371 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1372 codec->patch_ops.init = ad1986a_automic_init;
Takashi Iwai825aa9722006-03-17 10:50:49 +01001373 break;
Takashi Iwaic912e7a2009-06-24 14:14:34 +02001374 case AD1986A_SAMSUNG_P50:
1375 spec->num_mixers = 2;
1376 spec->mixers[0] = ad1986a_automute_master_mixers;
1377 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1378 spec->num_init_verbs = 4;
1379 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1380 spec->init_verbs[2] = ad1986a_automic_verbs;
1381 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1382 spec->multiout.max_channels = 2;
1383 spec->multiout.num_dacs = 1;
1384 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1385 if (!is_jack_available(codec, 0x25))
1386 spec->multiout.dig_out_nid = 0;
1387 spec->input_mux = &ad1986a_automic_capture_source;
1388 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1389 codec->patch_ops.init = ad1986a_samsung_p50_init;
1390 break;
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001391 case AD1986A_LAPTOP_AUTOMUTE:
Takashi Iwai16d11a82009-06-24 14:07:53 +02001392 spec->num_mixers = 3;
1393 spec->mixers[0] = ad1986a_automute_master_mixers;
1394 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1395 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001396 spec->num_init_verbs = 3;
1397 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1398 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1399 spec->multiout.max_channels = 2;
1400 spec->multiout.num_dacs = 1;
1401 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
Takashi Iwai8c0d9642008-01-28 12:30:17 +01001402 if (!is_jack_available(codec, 0x25))
1403 spec->multiout.dig_out_nid = 0;
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001404 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1405 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1406 codec->patch_ops.init = ad1986a_hp_init;
Takashi Iwai03c405a2009-06-24 14:10:15 +02001407 /* Lenovo N100 seems to report the reversed bit
1408 * for HP jack-sensing
1409 */
1410 spec->inv_jack_detect = 1;
Takashi Iwai8ab78c72007-09-06 14:29:53 +02001411 break;
Tobin Davisf36090f2007-01-08 11:07:12 +01001412 case AD1986A_ULTRA:
1413 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1414 spec->num_init_verbs = 2;
1415 spec->init_verbs[1] = ad1986a_ultra_init;
1416 spec->multiout.max_channels = 2;
1417 spec->multiout.num_dacs = 1;
1418 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1419 spec->multiout.dig_out_nid = 0;
1420 break;
Takashi Iwai9230d212006-03-13 13:49:49 +01001421 }
1422
Takashi Iwaid29240c2007-10-26 12:35:56 +02001423 /* AD1986A has a hardware problem that it can't share a stream
1424 * with multiple output pins. The copy of front to surrounds
1425 * causes noisy or silent outputs at a certain timing, e.g.
1426 * changing the volume.
1427 * So, let's disable the shared stream.
1428 */
1429 spec->multiout.no_share_stream = 1;
1430
Takashi Iwai729d55b2009-12-25 22:49:01 +01001431 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02001432 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01001433
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 return 0;
1435}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001436#else /* ENABLE_AD_STATIC_QUIRKS */
1437#define patch_ad1986a ad1986a_parse_auto_config
1438#endif /* ENABLE_AD_STATIC_QUIRKS */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439
1440/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001441 * AD1983 specific
1442 */
1443
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001444#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001445#define AD1983_SPDIF_OUT 0x02
1446#define AD1983_DAC 0x03
1447#define AD1983_ADC 0x04
1448
Takashi Iwai498f5b12011-05-02 11:33:15 +02001449static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
1450static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
1451static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001452
Takashi Iwai498f5b12011-05-02 11:33:15 +02001453static const struct hda_input_mux ad1983_capture_source = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001454 .num_items = 4,
1455 .items = {
1456 { "Mic", 0x0 },
1457 { "Line", 0x1 },
1458 { "Mix", 0x2 },
1459 { "Mix Mono", 0x3 },
1460 },
1461};
1462
1463/*
1464 * SPDIF playback route
1465 */
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001466static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001467{
Takashi Iwai498f5b12011-05-02 11:33:15 +02001468 static const char * const texts[] = { "PCM", "ADC" };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001469
1470 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1471 uinfo->count = 1;
1472 uinfo->value.enumerated.items = 2;
1473 if (uinfo->value.enumerated.item > 1)
1474 uinfo->value.enumerated.item = 1;
1475 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1476 return 0;
1477}
1478
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001479static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001480{
1481 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1482 struct ad198x_spec *spec = codec->spec;
1483
1484 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1485 return 0;
1486}
1487
Takashi Iwaic8b6bf92005-11-17 14:57:47 +01001488static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001489{
1490 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1491 struct ad198x_spec *spec = codec->spec;
1492
Takashi Iwai68ea7b22007-11-15 15:54:38 +01001493 if (ucontrol->value.enumerated.item[0] > 1)
1494 return -EINVAL;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001495 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1496 spec->spdif_route = ucontrol->value.enumerated.item[0];
Takashi Iwai82beb8f2007-08-10 17:09:26 +02001497 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1498 AC_VERB_SET_CONNECT_SEL,
1499 spec->spdif_route);
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001500 return 1;
1501 }
1502 return 0;
1503}
1504
Takashi Iwai498f5b12011-05-02 11:33:15 +02001505static const struct snd_kcontrol_new ad1983_mixers[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001506 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1507 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1508 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1509 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1510 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1511 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1512 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1513 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1514 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1515 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1516 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1517 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01001518 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001519 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1520 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1521 {
1522 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1523 .name = "Capture Source",
1524 .info = ad198x_mux_enum_info,
1525 .get = ad198x_mux_enum_get,
1526 .put = ad198x_mux_enum_put,
1527 },
1528 {
1529 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwai6540dff2006-06-13 11:57:22 +02001530 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001531 .info = ad1983_spdif_route_info,
1532 .get = ad1983_spdif_route_get,
1533 .put = ad1983_spdif_route_put,
1534 },
1535 { } /* end */
1536};
1537
Takashi Iwai498f5b12011-05-02 11:33:15 +02001538static const struct hda_verb ad1983_init_verbs[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001539 /* Front, HP, Mono; mute as default */
1540 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1541 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1542 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1543 /* Beep, PCM, Mic, Line-In: mute */
1544 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1545 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1546 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1547 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1548 /* Front, HP selectors; from Mix */
1549 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1550 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1551 /* Mono selector; from Mix */
1552 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1553 /* Mic selector; Mic */
1554 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1555 /* Line-in selector: Line-in */
1556 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1557 /* Mic boost: 0dB */
1558 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1559 /* Record selector: mic */
1560 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1561 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1562 /* SPDIF route: PCM */
1563 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1564 /* Front Pin */
1565 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1566 /* HP Pin */
1567 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1568 /* Mono Pin */
1569 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1570 /* Mic Pin */
1571 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1572 /* Line Pin */
1573 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1574 { } /* end */
1575};
1576
Takashi Iwai83012a72012-08-24 18:38:08 +02001577#ifdef CONFIG_PM
Takashi Iwai498f5b12011-05-02 11:33:15 +02001578static const struct hda_amp_list ad1983_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02001579 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
1580 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1581 { } /* end */
1582};
1583#endif
Takashi Iwai985be542005-11-02 18:26:49 +01001584
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001585/* models */
1586enum {
1587 AD1983_AUTO,
1588 AD1983_BASIC,
1589 AD1983_MODELS
1590};
1591
1592static const char * const ad1983_models[AD1983_MODELS] = {
1593 [AD1983_AUTO] = "auto",
1594 [AD1983_BASIC] = "basic",
1595};
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001596#endif /* ENABLE_AD_STATIC_QUIRKS */
1597
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001598
Takashi Iwai272f3ea2013-01-22 15:31:33 +01001599/*
1600 * SPDIF mux control for AD1983 auto-parser
1601 */
1602static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
1603 struct snd_ctl_elem_info *uinfo)
1604{
1605 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1606 struct ad198x_spec *spec = codec->spec;
1607 static const char * const texts2[] = { "PCM", "ADC" };
1608 static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
1609 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1610 int num_conns = snd_hda_get_num_conns(codec, dig_out);
1611
1612 if (num_conns == 2)
1613 return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
1614 else if (num_conns == 3)
1615 return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
1616 else
1617 return -EINVAL;
1618}
1619
1620static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
1621 struct snd_ctl_elem_value *ucontrol)
1622{
1623 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1624 struct ad198x_spec *spec = codec->spec;
1625
1626 ucontrol->value.enumerated.item[0] = spec->cur_smux;
1627 return 0;
1628}
1629
1630static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
1631 struct snd_ctl_elem_value *ucontrol)
1632{
1633 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1634 struct ad198x_spec *spec = codec->spec;
1635 unsigned int val = ucontrol->value.enumerated.item[0];
1636 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1637 int num_conns = snd_hda_get_num_conns(codec, dig_out);
1638
1639 if (val >= num_conns)
1640 return -EINVAL;
1641 if (spec->cur_smux == val)
1642 return 0;
1643 spec->cur_smux = val;
1644 snd_hda_codec_write_cache(codec, dig_out, 0,
1645 AC_VERB_SET_CONNECT_SEL, val);
1646 return 1;
1647}
1648
1649static struct snd_kcontrol_new ad1983_auto_smux_mixer = {
1650 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1651 .name = "IEC958 Playback Source",
1652 .info = ad1983_auto_smux_enum_info,
1653 .get = ad1983_auto_smux_enum_get,
1654 .put = ad1983_auto_smux_enum_put,
1655};
1656
1657static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
1658{
1659 struct ad198x_spec *spec = codec->spec;
1660 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1661 int num_conns;
1662
1663 if (!dig_out)
1664 return 0;
1665 num_conns = snd_hda_get_num_conns(codec, dig_out);
1666 if (num_conns != 2 && num_conns != 3)
1667 return 0;
1668 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
1669 return -ENOMEM;
1670 return 0;
1671}
1672
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001673static int ad1983_parse_auto_config(struct hda_codec *codec)
1674{
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001675 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001676 int err;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001677
Takashi Iwai361dab32012-05-09 14:35:27 +02001678 err = alloc_ad_spec(codec);
1679 if (err < 0)
1680 return err;
1681 spec = codec->spec;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001682
Takashi Iwai99d35c42014-02-05 07:28:10 +01001683 spec->gen.mixer_nid = 0x0e;
Takashi Iwai7504b6c2013-03-18 11:25:51 +01001684 spec->gen.beep_nid = 0x10;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001685 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1686 err = ad198x_parse_auto_config(codec);
1687 if (err < 0)
1688 goto error;
1689 err = ad1983_add_spdif_mux_ctl(codec);
1690 if (err < 0)
1691 goto error;
1692 return 0;
1693
1694 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +01001695 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001696 return err;
1697}
1698
1699#ifdef ENABLE_AD_STATIC_QUIRKS
1700static int patch_ad1983(struct hda_codec *codec)
1701{
1702 struct ad198x_spec *spec;
1703 int board_config;
1704 int err;
1705
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001706 board_config = snd_hda_check_board_config(codec, AD1983_MODELS,
1707 ad1983_models, NULL);
Takashi Iwai657e1b92013-01-22 18:42:39 +01001708 if (board_config < 0) {
1709 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
1710 codec->chip_name);
1711 board_config = AD1983_AUTO;
1712 }
1713
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001714 if (board_config == AD1983_AUTO)
1715 return ad1983_parse_auto_config(codec);
1716
1717 err = alloc_ad_spec(codec);
1718 if (err < 0)
1719 return err;
1720 spec = codec->spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001721
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01001722 err = snd_hda_attach_beep_device(codec, 0x10);
1723 if (err < 0) {
1724 ad198x_free(codec);
1725 return err;
1726 }
1727 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1728
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001729 spec->multiout.max_channels = 2;
1730 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1731 spec->multiout.dac_nids = ad1983_dac_nids;
1732 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +01001733 spec->num_adc_nids = 1;
1734 spec->adc_nids = ad1983_adc_nids;
Takashi Iwai18a815d2006-03-01 19:54:39 +01001735 spec->capsrc_nids = ad1983_capsrc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001736 spec->input_mux = &ad1983_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +01001737 spec->num_mixers = 1;
1738 spec->mixers[0] = ad1983_mixers;
1739 spec->num_init_verbs = 1;
1740 spec->init_verbs[0] = ad1983_init_verbs;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001741 spec->spdif_route = 0;
Takashi Iwai83012a72012-08-24 18:38:08 +02001742#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +02001743 spec->loopback.amplist = ad1983_loopbacks;
1744#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01001745 spec->vmaster_nid = 0x05;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001746
1747 codec->patch_ops = ad198x_patch_ops;
1748
Takashi Iwai729d55b2009-12-25 22:49:01 +01001749 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02001750 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01001751
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001752 return 0;
1753}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001754#else /* ENABLE_AD_STATIC_QUIRKS */
1755#define patch_ad1983 ad1983_parse_auto_config
1756#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001757
1758
1759/*
1760 * AD1981 HD specific
1761 */
1762
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001763#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001764#define AD1981_SPDIF_OUT 0x02
1765#define AD1981_DAC 0x03
1766#define AD1981_ADC 0x04
1767
Takashi Iwai498f5b12011-05-02 11:33:15 +02001768static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
1769static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
1770static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001771
1772/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02001773static const struct hda_input_mux ad1981_capture_source = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001774 .num_items = 7,
1775 .items = {
1776 { "Front Mic", 0x0 },
1777 { "Line", 0x1 },
1778 { "Mix", 0x2 },
1779 { "Mix Mono", 0x3 },
1780 { "CD", 0x4 },
1781 { "Mic", 0x6 },
1782 { "Aux", 0x7 },
1783 },
1784};
1785
Takashi Iwai498f5b12011-05-02 11:33:15 +02001786static const struct snd_kcontrol_new ad1981_mixers[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001787 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1788 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1789 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1790 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1791 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1792 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1793 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1794 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1795 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1796 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1797 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1798 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1799 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1800 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1801 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1802 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1803 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1804 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01001805 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1806 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001807 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1808 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1809 {
1810 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1811 .name = "Capture Source",
1812 .info = ad198x_mux_enum_info,
1813 .get = ad198x_mux_enum_get,
1814 .put = ad198x_mux_enum_put,
1815 },
1816 /* identical with AD1983 */
1817 {
1818 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Takashi Iwai6540dff2006-06-13 11:57:22 +02001819 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001820 .info = ad1983_spdif_route_info,
1821 .get = ad1983_spdif_route_get,
1822 .put = ad1983_spdif_route_put,
1823 },
1824 { } /* end */
1825};
1826
Takashi Iwai498f5b12011-05-02 11:33:15 +02001827static const struct hda_verb ad1981_init_verbs[] = {
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001828 /* Front, HP, Mono; mute as default */
1829 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1830 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1831 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1832 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1833 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1834 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1835 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1836 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1837 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1838 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1839 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1840 /* Front, HP selectors; from Mix */
1841 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1842 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1843 /* Mono selector; from Mix */
1844 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1845 /* Mic Mixer; select Front Mic */
1846 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1847 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1848 /* Mic boost: 0dB */
Takashi Iwai6d6e17d2009-01-23 12:33:54 +01001849 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1850 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02001851 /* Record selector: Front mic */
1852 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1853 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1854 /* SPDIF route: PCM */
1855 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1856 /* Front Pin */
1857 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1858 /* HP Pin */
1859 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1860 /* Mono Pin */
1861 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1862 /* Front & Rear Mic Pins */
1863 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1864 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1865 /* Line Pin */
1866 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1867 /* Digital Beep */
1868 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1869 /* Line-Out as Input: disabled */
1870 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1871 { } /* end */
1872};
1873
Takashi Iwai83012a72012-08-24 18:38:08 +02001874#ifdef CONFIG_PM
Takashi Iwai498f5b12011-05-02 11:33:15 +02001875static const struct hda_amp_list ad1981_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02001876 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1877 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1878 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1879 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1880 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1881 { } /* end */
1882};
1883#endif
1884
Takashi Iwai18a815d2006-03-01 19:54:39 +01001885/*
1886 * Patch for HP nx6320
1887 *
Tobin Davis18768992007-03-12 22:20:51 +01001888 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
Takashi Iwai18a815d2006-03-01 19:54:39 +01001889 * speaker output enabled _and_ mute-LED off.
1890 */
1891
1892#define AD1981_HP_EVENT 0x37
1893#define AD1981_MIC_EVENT 0x38
1894
Takashi Iwai498f5b12011-05-02 11:33:15 +02001895static const struct hda_verb ad1981_hp_init_verbs[] = {
Takashi Iwai18a815d2006-03-01 19:54:39 +01001896 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1897 /* pin sensing on HP and Mic jacks */
1898 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1899 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1900 {}
1901};
1902
1903/* turn on/off EAPD (+ mute HP) as a master switch */
1904static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1905 struct snd_ctl_elem_value *ucontrol)
1906{
1907 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1908 struct ad198x_spec *spec = codec->spec;
1909
1910 if (! ad198x_eapd_put(kcontrol, ucontrol))
1911 return 0;
Takashi Iwaif0824812008-02-11 15:54:34 +01001912 /* change speaker pin appropriately */
Takashi Iwaicdd03ce2012-04-20 12:34:50 +02001913 snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001914 /* toggle HP mute appropriately */
Takashi Iwai47fd8302007-08-10 17:11:07 +02001915 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1916 HDA_AMP_MUTE,
1917 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001918 return 1;
1919}
1920
1921/* bind volumes of both NID 0x05 and 0x06 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02001922static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02001923 .ops = &snd_hda_bind_vol,
1924 .values = {
1925 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1926 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1927 0
1928 },
1929};
Takashi Iwai18a815d2006-03-01 19:54:39 +01001930
1931/* mute internal speaker if HP is plugged */
1932static void ad1981_hp_automute(struct hda_codec *codec)
1933{
1934 unsigned int present;
1935
Takashi Iwaid56757a2009-11-18 08:00:14 +01001936 present = snd_hda_jack_detect(codec, 0x06);
Takashi Iwai47fd8302007-08-10 17:11:07 +02001937 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1938 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001939}
1940
1941/* toggle input of built-in and mic jack appropriately */
1942static void ad1981_hp_automic(struct hda_codec *codec)
1943{
Takashi Iwai498f5b12011-05-02 11:33:15 +02001944 static const struct hda_verb mic_jack_on[] = {
Takashi Iwai18a815d2006-03-01 19:54:39 +01001945 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1946 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1947 {}
1948 };
Takashi Iwai498f5b12011-05-02 11:33:15 +02001949 static const struct hda_verb mic_jack_off[] = {
Takashi Iwai18a815d2006-03-01 19:54:39 +01001950 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1951 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1952 {}
1953 };
1954 unsigned int present;
1955
Takashi Iwaid56757a2009-11-18 08:00:14 +01001956 present = snd_hda_jack_detect(codec, 0x08);
Takashi Iwai18a815d2006-03-01 19:54:39 +01001957 if (present)
1958 snd_hda_sequence_write(codec, mic_jack_on);
1959 else
1960 snd_hda_sequence_write(codec, mic_jack_off);
1961}
1962
1963/* unsolicited event for HP jack sensing */
1964static void ad1981_hp_unsol_event(struct hda_codec *codec,
1965 unsigned int res)
1966{
1967 res >>= 26;
1968 switch (res) {
1969 case AD1981_HP_EVENT:
1970 ad1981_hp_automute(codec);
1971 break;
1972 case AD1981_MIC_EVENT:
1973 ad1981_hp_automic(codec);
1974 break;
1975 }
1976}
1977
Takashi Iwai498f5b12011-05-02 11:33:15 +02001978static const struct hda_input_mux ad1981_hp_capture_source = {
Takashi Iwai18a815d2006-03-01 19:54:39 +01001979 .num_items = 3,
1980 .items = {
1981 { "Mic", 0x0 },
David Henningssonc40bd912012-09-19 12:19:47 +02001982 { "Dock Mic", 0x1 },
Takashi Iwai18a815d2006-03-01 19:54:39 +01001983 { "Mix", 0x2 },
1984 },
1985};
1986
Takashi Iwai498f5b12011-05-02 11:33:15 +02001987static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
Takashi Iwaicca3b372007-08-10 17:12:15 +02001988 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
Takashi Iwai18a815d2006-03-01 19:54:39 +01001989 {
1990 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01001991 .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
Takashi Iwai18a815d2006-03-01 19:54:39 +01001992 .name = "Master Playback Switch",
1993 .info = ad198x_eapd_info,
1994 .get = ad198x_eapd_get,
1995 .put = ad1981_hp_master_sw_put,
1996 .private_value = 0x05,
1997 },
1998 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1999 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
2000#if 0
2001 /* FIXME: analog mic/line loopback doesn't work with my tests...
2002 * (although recording is OK)
2003 */
2004 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
2005 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
David Henningssonc40bd912012-09-19 12:19:47 +02002006 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
2007 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
Takashi Iwai18a815d2006-03-01 19:54:39 +01002008 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
2009 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
2010 /* FIXME: does this laptop have analog CD connection? */
2011 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2012 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
2013#endif
David Henningsson5f99f862011-01-04 15:24:24 +01002014 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
2015 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
Takashi Iwai18a815d2006-03-01 19:54:39 +01002016 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
2017 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
2018 {
2019 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2020 .name = "Capture Source",
2021 .info = ad198x_mux_enum_info,
2022 .get = ad198x_mux_enum_get,
2023 .put = ad198x_mux_enum_put,
2024 },
2025 { } /* end */
2026};
2027
2028/* initialize jack-sensing, too */
2029static int ad1981_hp_init(struct hda_codec *codec)
2030{
2031 ad198x_init(codec);
2032 ad1981_hp_automute(codec);
2033 ad1981_hp_automic(codec);
2034 return 0;
2035}
2036
Tobin Davis18768992007-03-12 22:20:51 +01002037/* configuration for Toshiba Laptops */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002038static const struct hda_verb ad1981_toshiba_init_verbs[] = {
Tobin Davis18768992007-03-12 22:20:51 +01002039 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
2040 /* pin sensing on HP and Mic jacks */
2041 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
2042 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
2043 {}
2044};
2045
Takashi Iwai498f5b12011-05-02 11:33:15 +02002046static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
Tobin Davis18768992007-03-12 22:20:51 +01002047 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
2048 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
2049 { }
2050};
2051
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002052/* configuration for Lenovo Thinkpad T60 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002053static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002054 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2055 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
2056 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
2057 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
2058 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
2059 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
2060 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2061 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01002062 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002063 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
2064 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
2065 {
2066 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2067 .name = "Capture Source",
2068 .info = ad198x_mux_enum_info,
2069 .get = ad198x_mux_enum_get,
2070 .put = ad198x_mux_enum_put,
2071 },
Takashi Iwai6540dff2006-06-13 11:57:22 +02002072 /* identical with AD1983 */
2073 {
2074 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2075 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
2076 .info = ad1983_spdif_route_info,
2077 .get = ad1983_spdif_route_get,
2078 .put = ad1983_spdif_route_put,
2079 },
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002080 { } /* end */
2081};
2082
Takashi Iwai498f5b12011-05-02 11:33:15 +02002083static const struct hda_input_mux ad1981_thinkpad_capture_source = {
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002084 .num_items = 3,
2085 .items = {
2086 { "Mic", 0x0 },
2087 { "Mix", 0x2 },
2088 { "CD", 0x4 },
2089 },
2090};
2091
Takashi Iwai18a815d2006-03-01 19:54:39 +01002092/* models */
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002093enum {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01002094 AD1981_AUTO,
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002095 AD1981_BASIC,
2096 AD1981_HP,
2097 AD1981_THINKPAD,
Tobin Davis18768992007-03-12 22:20:51 +01002098 AD1981_TOSHIBA,
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002099 AD1981_MODELS
2100};
Takashi Iwai18a815d2006-03-01 19:54:39 +01002101
Takashi Iwaiea734962011-01-17 11:29:34 +01002102static const char * const ad1981_models[AD1981_MODELS] = {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01002103 [AD1981_AUTO] = "auto",
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002104 [AD1981_HP] = "hp",
2105 [AD1981_THINKPAD] = "thinkpad",
2106 [AD1981_BASIC] = "basic",
Tobin Davis18768992007-03-12 22:20:51 +01002107 [AD1981_TOSHIBA] = "toshiba"
Takashi Iwaif5fcc132006-11-24 17:07:44 +01002108};
2109
Takashi Iwai498f5b12011-05-02 11:33:15 +02002110static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002111 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
Takashi Iwai470eaf62008-06-30 16:40:10 +02002112 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
Takashi Iwai8970ccd2006-04-18 12:50:40 +02002113 /* All HP models */
Takashi Iwaidea0a502009-02-09 17:14:52 +01002114 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002115 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002116 /* Lenovo Thinkpad T60/X60/Z6xx */
Takashi Iwaidea0a502009-02-09 17:14:52 +01002117 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01002118 /* HP nx6320 (reversed SSID, H/W bug) */
2119 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
Takashi Iwai18a815d2006-03-01 19:54:39 +01002120 {}
2121};
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002122#endif /* ENABLE_AD_STATIC_QUIRKS */
2123
Takashi Iwai18a815d2006-03-01 19:54:39 +01002124
Takashi Iwaia928bd22013-01-22 18:18:42 +01002125/* follow EAPD via vmaster hook */
2126static void ad_vmaster_eapd_hook(void *private_data, int enabled)
2127{
2128 struct hda_codec *codec = private_data;
2129 struct ad198x_spec *spec = codec->spec;
Takashi Iwaic38217e2013-07-04 12:54:22 +02002130
2131 if (!spec->eapd_nid)
2132 return;
Takashi Iwaia928bd22013-01-22 18:18:42 +01002133 snd_hda_codec_update_cache(codec, spec->eapd_nid, 0,
2134 AC_VERB_SET_EAPD_BTLENABLE,
2135 enabled ? 0x02 : 0x00);
2136}
2137
2138static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
2139 const struct hda_fixup *fix, int action)
2140{
2141 struct ad198x_spec *spec = codec->spec;
2142
2143 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
2144 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
2145 spec->eapd_nid = 0x05;
2146 }
2147}
2148
2149/* set the upper-limit for mixer amp to 0dB for avoiding the possible
2150 * damage by overloading
2151 */
2152static void ad1981_fixup_amp_override(struct hda_codec *codec,
2153 const struct hda_fixup *fix, int action)
2154{
2155 if (action == HDA_FIXUP_ACT_PRE_PROBE)
2156 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2157 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2158 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2159 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2160 (1 << AC_AMPCAP_MUTE_SHIFT));
2161}
2162
2163enum {
2164 AD1981_FIXUP_AMP_OVERRIDE,
2165 AD1981_FIXUP_HP_EAPD,
2166};
2167
2168static const struct hda_fixup ad1981_fixups[] = {
2169 [AD1981_FIXUP_AMP_OVERRIDE] = {
2170 .type = HDA_FIXUP_FUNC,
2171 .v.func = ad1981_fixup_amp_override,
2172 },
2173 [AD1981_FIXUP_HP_EAPD] = {
2174 .type = HDA_FIXUP_FUNC,
2175 .v.func = ad1981_fixup_hp_eapd,
2176 .chained = true,
2177 .chain_id = AD1981_FIXUP_AMP_OVERRIDE,
2178 },
2179};
2180
2181static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
2182 SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
2183 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
2184 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
2185 /* HP nx6320 (reversed SSID, H/W bug) */
2186 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
2187 {}
2188};
2189
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01002190static int ad1981_parse_auto_config(struct hda_codec *codec)
2191{
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002192 struct ad198x_spec *spec;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002193 int err;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002194
Takashi Iwai361dab32012-05-09 14:35:27 +02002195 err = alloc_ad_spec(codec);
2196 if (err < 0)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002197 return -ENOMEM;
Takashi Iwai361dab32012-05-09 14:35:27 +02002198 spec = codec->spec;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002199
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002200 spec->gen.mixer_nid = 0x0e;
Takashi Iwai7504b6c2013-03-18 11:25:51 +01002201 spec->gen.beep_nid = 0x10;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002202 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
Takashi Iwaia928bd22013-01-22 18:18:42 +01002203
2204 snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
2205 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
2206
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002207 err = ad198x_parse_auto_config(codec);
2208 if (err < 0)
2209 goto error;
2210 err = ad1983_add_spdif_mux_ctl(codec);
2211 if (err < 0)
2212 goto error;
Takashi Iwaia928bd22013-01-22 18:18:42 +01002213
2214 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
2215
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002216 return 0;
2217
2218 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +01002219 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002220 return err;
2221}
2222
2223#ifdef ENABLE_AD_STATIC_QUIRKS
2224static int patch_ad1981(struct hda_codec *codec)
2225{
2226 struct ad198x_spec *spec;
2227 int err, board_config;
2228
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01002229 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
2230 ad1981_models,
2231 ad1981_cfg_tbl);
Takashi Iwai657e1b92013-01-22 18:42:39 +01002232 if (board_config < 0) {
2233 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
2234 codec->chip_name);
2235 board_config = AD1981_AUTO;
2236 }
2237
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002238 if (board_config == AD1981_AUTO)
2239 return ad1981_parse_auto_config(codec);
2240
2241 err = alloc_ad_spec(codec);
2242 if (err < 0)
2243 return -ENOMEM;
2244 spec = codec->spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01002245
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01002246 err = snd_hda_attach_beep_device(codec, 0x10);
2247 if (err < 0) {
2248 ad198x_free(codec);
2249 return err;
2250 }
2251 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
2252
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002253 spec->multiout.max_channels = 2;
2254 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
2255 spec->multiout.dac_nids = ad1981_dac_nids;
2256 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
Takashi Iwai985be542005-11-02 18:26:49 +01002257 spec->num_adc_nids = 1;
2258 spec->adc_nids = ad1981_adc_nids;
Takashi Iwai18a815d2006-03-01 19:54:39 +01002259 spec->capsrc_nids = ad1981_capsrc_nids;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002260 spec->input_mux = &ad1981_capture_source;
Takashi Iwai985be542005-11-02 18:26:49 +01002261 spec->num_mixers = 1;
2262 spec->mixers[0] = ad1981_mixers;
2263 spec->num_init_verbs = 1;
2264 spec->init_verbs[0] = ad1981_init_verbs;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002265 spec->spdif_route = 0;
Takashi Iwai83012a72012-08-24 18:38:08 +02002266#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +02002267 spec->loopback.amplist = ad1981_loopbacks;
2268#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01002269 spec->vmaster_nid = 0x05;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002270
2271 codec->patch_ops = ad198x_patch_ops;
2272
Takashi Iwai18a815d2006-03-01 19:54:39 +01002273 /* override some parameters */
Takashi Iwai18a815d2006-03-01 19:54:39 +01002274 switch (board_config) {
2275 case AD1981_HP:
2276 spec->mixers[0] = ad1981_hp_mixers;
2277 spec->num_init_verbs = 2;
2278 spec->init_verbs[1] = ad1981_hp_init_verbs;
Takashi Iwai695cd4a2011-06-10 14:37:04 +02002279 if (!is_jack_available(codec, 0x0a))
2280 spec->multiout.dig_out_nid = 0;
Takashi Iwai18a815d2006-03-01 19:54:39 +01002281 spec->input_mux = &ad1981_hp_capture_source;
2282
2283 codec->patch_ops.init = ad1981_hp_init;
2284 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
Daniel T Chen01f59662009-12-13 16:22:58 -05002285 /* set the upper-limit for mixer amp to 0dB for avoiding the
2286 * possible damage by overloading
2287 */
2288 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2289 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2290 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2291 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2292 (1 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai18a815d2006-03-01 19:54:39 +01002293 break;
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002294 case AD1981_THINKPAD:
2295 spec->mixers[0] = ad1981_thinkpad_mixers;
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002296 spec->input_mux = &ad1981_thinkpad_capture_source;
Daniel T Chenb8e80cf2010-03-30 13:29:28 -04002297 /* set the upper-limit for mixer amp to 0dB for avoiding the
2298 * possible damage by overloading
2299 */
2300 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2301 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2302 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2303 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2304 (1 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwai01686c5f2006-04-18 12:54:11 +02002305 break;
Tobin Davis18768992007-03-12 22:20:51 +01002306 case AD1981_TOSHIBA:
2307 spec->mixers[0] = ad1981_hp_mixers;
2308 spec->mixers[1] = ad1981_toshiba_mixers;
2309 spec->num_init_verbs = 2;
2310 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
2311 spec->multiout.dig_out_nid = 0;
2312 spec->input_mux = &ad1981_hp_capture_source;
2313 codec->patch_ops.init = ad1981_hp_init;
2314 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
2315 break;
Takashi Iwai18a815d2006-03-01 19:54:39 +01002316 }
Takashi Iwai729d55b2009-12-25 22:49:01 +01002317
2318 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02002319 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01002320
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002321 return 0;
2322}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002323#else /* ENABLE_AD_STATIC_QUIRKS */
2324#define patch_ad1981 ad1981_parse_auto_config
2325#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02002326
2327
2328/*
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002329 * AD1988
2330 *
2331 * Output pins and routes
2332 *
Takashi Iwaid32410b12005-11-24 16:06:23 +01002333 * Pin Mix Sel DAC (*)
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002334 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
2335 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
2336 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
2337 * port-D 0x12 (mute/hp) <- 0x29 <- 04
2338 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
2339 * port-F 0x16 (mute) <- 0x2a <- 06
2340 * port-G 0x24 (mute) <- 0x27 <- 05
2341 * port-H 0x25 (mute) <- 0x28 <- 0a
2342 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
2343 *
Takashi Iwaid32410b12005-11-24 16:06:23 +01002344 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
2345 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002346 *
2347 * Input pins and routes
2348 *
2349 * pin boost mix input # / adc input #
2350 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
2351 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
2352 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
2353 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
2354 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
2355 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
2356 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
2357 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
2358 *
2359 *
2360 * DAC assignment
Takashi Iwaid32410b12005-11-24 16:06:23 +01002361 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002362 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002363 *
2364 * Inputs of Analog Mix (0x20)
2365 * 0:Port-B (front mic)
2366 * 1:Port-C/G/H (line-in)
2367 * 2:Port-A
2368 * 3:Port-D (line-in/2)
2369 * 4:Port-E/G/H (mic-in)
2370 * 5:Port-F (mic2-in)
2371 * 6:CD
2372 * 7:Beep
2373 *
2374 * ADC selection
2375 * 0:Port-A
2376 * 1:Port-B (front mic-in)
2377 * 2:Port-C (line-in)
2378 * 3:Port-F (mic2-in)
2379 * 4:Port-E (mic-in)
2380 * 5:CD
2381 * 6:Port-G
2382 * 7:Port-H
2383 * 8:Port-D (line-in/2)
2384 * 9:Mix
2385 *
2386 * Proposed pin assignments by the datasheet
2387 *
2388 * 6-stack
2389 * Port-A front headphone
2390 * B front mic-in
2391 * C rear line-in
2392 * D rear front-out
2393 * E rear mic-in
2394 * F rear surround
2395 * G rear CLFE
2396 * H rear side
2397 *
2398 * 3-stack
2399 * Port-A front headphone
2400 * B front mic
2401 * C rear line-in/surround
2402 * D rear front-out
2403 * E rear mic-in/CLFE
2404 *
2405 * laptop
2406 * Port-A headphone
2407 * B mic-in
2408 * C docking station
2409 * D internal speaker (with EAPD)
2410 * E/F quad mic array
2411 */
2412
2413
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01002414#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002415/* models */
2416enum {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01002417 AD1988_AUTO,
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002418 AD1988_6STACK,
2419 AD1988_6STACK_DIG,
2420 AD1988_3STACK,
2421 AD1988_3STACK_DIG,
2422 AD1988_LAPTOP,
2423 AD1988_LAPTOP_DIG,
2424 AD1988_MODEL_LAST,
2425};
2426
Takashi Iwaid32410b12005-11-24 16:06:23 +01002427/* reivision id to check workarounds */
2428#define AD1988A_REV2 0x100200
2429
Takashi Iwai1a806f42006-07-03 15:58:16 +02002430#define is_rev2(codec) \
2431 ((codec)->vendor_id == 0x11d41988 && \
2432 (codec)->revision_id == AD1988A_REV2)
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002433
2434/*
2435 * mixers
2436 */
2437
Takashi Iwai498f5b12011-05-02 11:33:15 +02002438static const hda_nid_t ad1988_6stack_dac_nids[4] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002439 0x04, 0x06, 0x05, 0x0a
2440};
2441
Takashi Iwai498f5b12011-05-02 11:33:15 +02002442static const hda_nid_t ad1988_3stack_dac_nids[3] = {
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002443 0x04, 0x05, 0x0a
Takashi Iwaid32410b12005-11-24 16:06:23 +01002444};
2445
2446/* for AD1988A revision-2, DAC2-4 are swapped */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002447static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
Takashi Iwaid32410b12005-11-24 16:06:23 +01002448 0x04, 0x05, 0x0a, 0x06
2449};
2450
Takashi Iwai498f5b12011-05-02 11:33:15 +02002451static const hda_nid_t ad1988_alt_dac_nid[1] = {
Raymond Yauc66ddf32011-01-17 11:19:03 +01002452 0x03
2453};
2454
Takashi Iwai498f5b12011-05-02 11:33:15 +02002455static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002456 0x04, 0x0a, 0x06
Takashi Iwaid32410b12005-11-24 16:06:23 +01002457};
2458
Takashi Iwai498f5b12011-05-02 11:33:15 +02002459static const hda_nid_t ad1988_adc_nids[3] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002460 0x08, 0x09, 0x0f
2461};
2462
Takashi Iwai498f5b12011-05-02 11:33:15 +02002463static const hda_nid_t ad1988_capsrc_nids[3] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002464 0x0c, 0x0d, 0x0e
2465};
2466
Robin H. Johnson9cae0c62008-09-13 16:54:58 -07002467#define AD1988_SPDIF_OUT 0x02
2468#define AD1988_SPDIF_OUT_HDMI 0x0b
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002469#define AD1988_SPDIF_IN 0x07
2470
Takashi Iwai498f5b12011-05-02 11:33:15 +02002471static const hda_nid_t ad1989b_slave_dig_outs[] = {
Takashi Iwai3a08e302009-02-13 11:37:08 +01002472 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
Robin H. Johnson9cae0c62008-09-13 16:54:58 -07002473};
2474
Takashi Iwai498f5b12011-05-02 11:33:15 +02002475static const struct hda_input_mux ad1988_6stack_capture_source = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002476 .num_items = 5,
2477 .items = {
Takashi Iwaifb304ce2008-02-25 15:32:01 +01002478 { "Front Mic", 0x1 }, /* port-B */
2479 { "Line", 0x2 }, /* port-C */
2480 { "Mic", 0x4 }, /* port-E */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002481 { "CD", 0x5 },
2482 { "Mix", 0x9 },
2483 },
2484};
2485
Takashi Iwai498f5b12011-05-02 11:33:15 +02002486static const struct hda_input_mux ad1988_laptop_capture_source = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002487 .num_items = 3,
2488 .items = {
Takashi Iwaifb304ce2008-02-25 15:32:01 +01002489 { "Mic/Line", 0x1 }, /* port-B */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002490 { "CD", 0x5 },
2491 { "Mix", 0x9 },
2492 },
2493};
2494
2495/*
2496 */
2497static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
2498 struct snd_ctl_elem_info *uinfo)
2499{
2500 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2501 struct ad198x_spec *spec = codec->spec;
2502 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
2503 spec->num_channel_mode);
2504}
2505
2506static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
2507 struct snd_ctl_elem_value *ucontrol)
2508{
2509 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2510 struct ad198x_spec *spec = codec->spec;
2511 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
2512 spec->num_channel_mode, spec->multiout.max_channels);
2513}
2514
2515static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
2516 struct snd_ctl_elem_value *ucontrol)
2517{
2518 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2519 struct ad198x_spec *spec = codec->spec;
Takashi Iwai4e195a72006-07-28 14:47:34 +02002520 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
2521 spec->num_channel_mode,
2522 &spec->multiout.max_channels);
Takashi Iwaibd2033f2006-10-10 19:49:31 +02002523 if (err >= 0 && spec->need_dac_fix)
Takashi Iwai2125cad2006-03-27 12:52:22 +02002524 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
Takashi Iwai4e195a72006-07-28 14:47:34 +02002525 return err;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002526}
2527
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002528/* 6-stack mode */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002529static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002530 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2531 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2532 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2533 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2534 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
Takashi Iwai2ece5f422006-07-06 19:16:40 +02002535 { } /* end */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002536};
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002537
Takashi Iwai498f5b12011-05-02 11:33:15 +02002538static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
Takashi Iwaid32410b12005-11-24 16:06:23 +01002539 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2540 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2541 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2542 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2543 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
Takashi Iwai2ece5f422006-07-06 19:16:40 +02002544 { } /* end */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002545};
2546
Takashi Iwai498f5b12011-05-02 11:33:15 +02002547static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
Raymond Yau356aab72011-08-31 10:30:59 +08002548 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002549 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2550 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2551 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2552 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2553 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2554 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2555 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2556
2557 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2558 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2559 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2560 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2561 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2562 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2563 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2564 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2565
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002566 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002567 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2568
David Henningsson5f99f862011-01-04 15:24:24 +01002569 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2570 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002571 { } /* end */
2572};
2573
2574/* 3-stack mode */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002575static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002576 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
Takashi Iwaid32410b12005-11-24 16:06:23 +01002577 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002578 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2579 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
Takashi Iwai2ece5f422006-07-06 19:16:40 +02002580 { } /* end */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002581};
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002582
Takashi Iwai498f5b12011-05-02 11:33:15 +02002583static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
Takashi Iwaid32410b12005-11-24 16:06:23 +01002584 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002585 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2586 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2587 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
Takashi Iwai2ece5f422006-07-06 19:16:40 +02002588 { } /* end */
Takashi Iwaid32410b12005-11-24 16:06:23 +01002589};
2590
Takashi Iwai498f5b12011-05-02 11:33:15 +02002591static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
Raymond Yau356aab72011-08-31 10:30:59 +08002592 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002593 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
Takashi Iwaid32410b12005-11-24 16:06:23 +01002594 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2595 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2596 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002597 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2598 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2599
2600 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2601 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2602 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2603 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2604 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2605 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2606 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2607 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2608
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002609 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002610 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2611
David Henningsson5f99f862011-01-04 15:24:24 +01002612 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2613 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002614 {
2615 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2616 .name = "Channel Mode",
2617 .info = ad198x_ch_mode_info,
2618 .get = ad198x_ch_mode_get,
2619 .put = ad198x_ch_mode_put,
2620 },
2621
2622 { } /* end */
2623};
2624
2625/* laptop mode */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002626static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
Raymond Yau356aab72011-08-31 10:30:59 +08002627 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002628 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2629 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2630 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2631
2632 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2633 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2634 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2635 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2636 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2637 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2638
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002639 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002640 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2641
David Henningsson5f99f862011-01-04 15:24:24 +01002642 HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002643
2644 {
2645 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2646 .name = "External Amplifier",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002647 .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
Takashi Iwai18a815d2006-03-01 19:54:39 +01002648 .info = ad198x_eapd_info,
2649 .get = ad198x_eapd_get,
2650 .put = ad198x_eapd_put,
Takashi Iwaiee6e3652009-12-08 17:23:33 +01002651 .private_value = 0x12, /* port-D */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002652 },
2653
2654 { } /* end */
2655};
2656
2657/* capture */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002658static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002659 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2660 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2661 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2662 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2663 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2664 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2665 {
2666 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2667 /* The multiple "Capture Source" controls confuse alsamixer
2668 * So call somewhat different..
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002669 */
2670 /* .name = "Capture Source", */
2671 .name = "Input Source",
2672 .count = 3,
2673 .info = ad198x_mux_enum_info,
2674 .get = ad198x_mux_enum_get,
2675 .put = ad198x_mux_enum_put,
2676 },
2677 { } /* end */
2678};
2679
2680static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2681 struct snd_ctl_elem_info *uinfo)
2682{
Takashi Iwai498f5b12011-05-02 11:33:15 +02002683 static const char * const texts[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002684 "PCM", "ADC1", "ADC2", "ADC3"
2685 };
2686 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2687 uinfo->count = 1;
2688 uinfo->value.enumerated.items = 4;
2689 if (uinfo->value.enumerated.item >= 4)
2690 uinfo->value.enumerated.item = 3;
2691 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2692 return 0;
2693}
2694
2695static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2696 struct snd_ctl_elem_value *ucontrol)
2697{
2698 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2699 unsigned int sel;
2700
Takashi Iwaibddcf542007-07-24 18:04:05 +02002701 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2702 AC_AMP_GET_INPUT);
2703 if (!(sel & 0x80))
2704 ucontrol->value.enumerated.item[0] = 0;
2705 else {
Takashi Iwai35b26722007-05-05 12:17:17 +02002706 sel = snd_hda_codec_read(codec, 0x0b, 0,
2707 AC_VERB_GET_CONNECT_SEL, 0);
2708 if (sel < 3)
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002709 sel++;
2710 else
2711 sel = 0;
Takashi Iwaibddcf542007-07-24 18:04:05 +02002712 ucontrol->value.enumerated.item[0] = sel;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002713 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002714 return 0;
2715}
2716
2717static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2718 struct snd_ctl_elem_value *ucontrol)
2719{
2720 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
Takashi Iwai35b26722007-05-05 12:17:17 +02002721 unsigned int val, sel;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002722 int change;
2723
Takashi Iwai35b26722007-05-05 12:17:17 +02002724 val = ucontrol->value.enumerated.item[0];
Takashi Iwai68ea7b22007-11-15 15:54:38 +01002725 if (val > 3)
2726 return -EINVAL;
Takashi Iwai35b26722007-05-05 12:17:17 +02002727 if (!val) {
Takashi Iwaibddcf542007-07-24 18:04:05 +02002728 sel = snd_hda_codec_read(codec, 0x1d, 0,
2729 AC_VERB_GET_AMP_GAIN_MUTE,
2730 AC_AMP_GET_INPUT);
2731 change = sel & 0x80;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002732 if (change) {
2733 snd_hda_codec_write_cache(codec, 0x1d, 0,
2734 AC_VERB_SET_AMP_GAIN_MUTE,
2735 AMP_IN_UNMUTE(0));
2736 snd_hda_codec_write_cache(codec, 0x1d, 0,
2737 AC_VERB_SET_AMP_GAIN_MUTE,
2738 AMP_IN_MUTE(1));
Takashi Iwaibddcf542007-07-24 18:04:05 +02002739 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002740 } else {
Takashi Iwaibddcf542007-07-24 18:04:05 +02002741 sel = snd_hda_codec_read(codec, 0x1d, 0,
2742 AC_VERB_GET_AMP_GAIN_MUTE,
2743 AC_AMP_GET_INPUT | 0x01);
2744 change = sel & 0x80;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002745 if (change) {
2746 snd_hda_codec_write_cache(codec, 0x1d, 0,
2747 AC_VERB_SET_AMP_GAIN_MUTE,
2748 AMP_IN_MUTE(0));
2749 snd_hda_codec_write_cache(codec, 0x1d, 0,
2750 AC_VERB_SET_AMP_GAIN_MUTE,
2751 AMP_IN_UNMUTE(1));
Takashi Iwaibddcf542007-07-24 18:04:05 +02002752 }
Takashi Iwai35b26722007-05-05 12:17:17 +02002753 sel = snd_hda_codec_read(codec, 0x0b, 0,
2754 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2755 change |= sel != val;
Takashi Iwai82beb8f2007-08-10 17:09:26 +02002756 if (change)
2757 snd_hda_codec_write_cache(codec, 0x0b, 0,
2758 AC_VERB_SET_CONNECT_SEL,
2759 val - 1);
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002760 }
2761 return change;
2762}
2763
Takashi Iwai498f5b12011-05-02 11:33:15 +02002764static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002765 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2766 {
2767 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2768 .name = "IEC958 Playback Source",
Jaroslav Kysela5b0cb1d2009-12-08 16:13:32 +01002769 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002770 .info = ad1988_spdif_playback_source_info,
2771 .get = ad1988_spdif_playback_source_get,
2772 .put = ad1988_spdif_playback_source_put,
2773 },
2774 { } /* end */
2775};
2776
Takashi Iwai498f5b12011-05-02 11:33:15 +02002777static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002778 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2779 { } /* end */
2780};
2781
Takashi Iwai498f5b12011-05-02 11:33:15 +02002782static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002783 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
Robin H. Johnson9cae0c62008-09-13 16:54:58 -07002784 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002785 { } /* end */
2786};
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002787
2788/*
2789 * initialization verbs
2790 */
2791
2792/*
2793 * for 6-stack (+dig)
2794 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002795static const struct hda_verb ad1988_6stack_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002796 /* Front, Surround, CLFE, side DAC; unmute as default */
2797 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2798 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2799 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2800 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002801 /* Port-A front headphon path */
Raymond Yau356aab72011-08-31 10:30:59 +08002802 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002803 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2804 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2805 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2806 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2807 /* Port-D line-out path */
2808 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2809 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2810 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2811 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2812 /* Port-F surround path */
2813 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2814 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2815 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2816 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2817 /* Port-G CLFE path */
2818 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2819 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2820 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2821 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2822 /* Port-H side path */
2823 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2824 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2825 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2826 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2827 /* Mono out path */
2828 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2829 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2830 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2831 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2832 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2833 /* Port-B front mic-in path */
2834 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2835 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2836 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2837 /* Port-C line-in path */
2838 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2839 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2840 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2841 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2842 /* Port-E mic-in path */
2843 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2844 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2845 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2846 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
Johannes Stezenbach695005c2007-12-13 17:51:00 +01002847 /* Analog CD Input */
2848 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwaidb3da6c2008-08-11 18:08:54 +02002849 /* Analog Mix output amp */
2850 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002851
2852 { }
2853};
2854
Takashi Iwai498f5b12011-05-02 11:33:15 +02002855static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
Raymond Yauc66ddf32011-01-17 11:19:03 +01002856 /* Headphone; unmute as default */
2857 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2858 /* Port-A front headphon path */
2859 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2860 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2861 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2862 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2863 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
Raymond Yauc66ddf32011-01-17 11:19:03 +01002864
2865 { }
2866};
2867
Takashi Iwai498f5b12011-05-02 11:33:15 +02002868static const struct hda_verb ad1988_capture_init_verbs[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002869 /* mute analog mix */
2870 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2871 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2872 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2873 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2874 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2875 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2876 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2877 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2878 /* select ADCs - front-mic */
2879 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2880 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2881 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002882
2883 { }
2884};
2885
Takashi Iwai498f5b12011-05-02 11:33:15 +02002886static const struct hda_verb ad1988_spdif_init_verbs[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002887 /* SPDIF out sel */
2888 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2889 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2890 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaibddcf542007-07-24 18:04:05 +02002891 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002892 /* SPDIF out pin */
2893 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002894
2895 { }
2896};
2897
Takashi Iwai498f5b12011-05-02 11:33:15 +02002898static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
Jaroslav Kyselafd0b0922010-01-21 14:54:38 +01002899 /* unmute SPDIF input pin */
2900 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2901 { }
2902};
2903
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002904/* AD1989 has no ADC -> SPDIF route */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002905static const struct hda_verb ad1989_spdif_init_verbs[] = {
Robin H. Johnsone8bfc6c2008-09-13 16:55:00 -07002906 /* SPDIF-1 out pin */
2907 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002908 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
Robin H. Johnsone8bfc6c2008-09-13 16:55:00 -07002909 /* SPDIF-2/HDMI out pin */
2910 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2911 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02002912 { }
2913};
2914
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002915/*
2916 * verbs for 3stack (+dig)
2917 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02002918static const struct hda_verb ad1988_3stack_ch2_init[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002919 /* set port-C to line-in */
2920 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2921 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2922 /* set port-E to mic-in */
2923 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2924 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2925 { } /* end */
2926};
2927
Takashi Iwai498f5b12011-05-02 11:33:15 +02002928static const struct hda_verb ad1988_3stack_ch6_init[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002929 /* set port-C to surround out */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002930 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Takashi Iwaid32410b12005-11-24 16:06:23 +01002931 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002932 /* set port-E to CLFE out */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002933 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
Takashi Iwaid32410b12005-11-24 16:06:23 +01002934 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002935 { } /* end */
2936};
2937
Takashi Iwai498f5b12011-05-02 11:33:15 +02002938static const struct hda_channel_mode ad1988_3stack_modes[2] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002939 { 2, ad1988_3stack_ch2_init },
2940 { 6, ad1988_3stack_ch6_init },
2941};
2942
Takashi Iwai498f5b12011-05-02 11:33:15 +02002943static const struct hda_verb ad1988_3stack_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01002944 /* Front, Surround, CLFE, side DAC; unmute as default */
2945 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2946 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2947 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2948 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002949 /* Port-A front headphon path */
Raymond Yau356aab72011-08-31 10:30:59 +08002950 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002951 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2952 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2953 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2954 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2955 /* Port-D line-out path */
2956 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2957 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2958 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2959 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2960 /* Mono out path */
2961 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2962 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2963 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2964 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2965 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2966 /* Port-B front mic-in path */
2967 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2968 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2969 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwaid32410b12005-11-24 16:06:23 +01002970 /* Port-C line-in/surround path - 6ch mode as default */
2971 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2972 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002973 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwaid32410b12005-11-24 16:06:23 +01002974 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002975 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
Takashi Iwaid32410b12005-11-24 16:06:23 +01002976 /* Port-E mic-in/CLFE path - 6ch mode as default */
2977 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2978 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002979 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +01002980 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002981 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2982 /* mute analog mix */
2983 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2984 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2985 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2986 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2987 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2988 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2989 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2990 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2991 /* select ADCs - front-mic */
2992 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2993 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2994 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
Takashi Iwaidb3da6c2008-08-11 18:08:54 +02002995 /* Analog Mix output amp */
2996 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01002997 { }
2998};
2999
3000/*
3001 * verbs for laptop mode (+dig)
3002 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02003003static const struct hda_verb ad1988_laptop_hp_on[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003004 /* unmute port-A and mute port-D */
3005 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
3006 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
3007 { } /* end */
3008};
Takashi Iwai498f5b12011-05-02 11:33:15 +02003009static const struct hda_verb ad1988_laptop_hp_off[] = {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003010 /* mute port-A and unmute port-D */
3011 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
3012 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
3013 { } /* end */
3014};
3015
3016#define AD1988_HP_EVENT 0x01
3017
Takashi Iwai498f5b12011-05-02 11:33:15 +02003018static const struct hda_verb ad1988_laptop_init_verbs[] = {
Takashi Iwai2e5b9562005-11-21 16:36:15 +01003019 /* Front, Surround, CLFE, side DAC; unmute as default */
3020 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3021 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3022 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3023 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003024 /* Port-A front headphon path */
Raymond Yau356aab72011-08-31 10:30:59 +08003025 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003026 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3027 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3028 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3029 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3030 /* unsolicited event for pin-sense */
3031 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
3032 /* Port-D line-out path + EAPD */
3033 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3034 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3035 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3036 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3037 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
3038 /* Mono out path */
3039 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
3040 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3041 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3042 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3043 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
3044 /* Port-B mic-in path */
3045 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3046 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3047 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3048 /* Port-C docking station - try to output */
3049 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3050 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
3051 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3052 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
3053 /* mute analog mix */
3054 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3055 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3056 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3057 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3058 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3059 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3060 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
3061 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
3062 /* select ADCs - mic */
3063 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
3064 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
3065 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
Takashi Iwaidb3da6c2008-08-11 18:08:54 +02003066 /* Analog Mix output amp */
3067 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003068 { }
3069};
3070
3071static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
3072{
3073 if ((res >> 26) != AD1988_HP_EVENT)
3074 return;
Takashi Iwaid56757a2009-11-18 08:00:14 +01003075 if (snd_hda_jack_detect(codec, 0x11))
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003076 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
3077 else
3078 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
3079}
3080
Takashi Iwai83012a72012-08-24 18:38:08 +02003081#ifdef CONFIG_PM
Takashi Iwai498f5b12011-05-02 11:33:15 +02003082static const struct hda_amp_list ad1988_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02003083 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3084 { 0x20, HDA_INPUT, 1 }, /* Line */
3085 { 0x20, HDA_INPUT, 4 }, /* Mic */
3086 { 0x20, HDA_INPUT, 6 }, /* CD */
3087 { } /* end */
3088};
3089#endif
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003090#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003091
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003092static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
3093 struct snd_ctl_elem_info *uinfo)
3094{
3095 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3096 static const char * const texts[] = {
3097 "PCM", "ADC1", "ADC2", "ADC3",
3098 };
3099 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
3100 if (num_conns > 4)
3101 num_conns = 4;
3102 return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
3103}
3104
3105static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
3106 struct snd_ctl_elem_value *ucontrol)
3107{
3108 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3109 struct ad198x_spec *spec = codec->spec;
3110
3111 ucontrol->value.enumerated.item[0] = spec->cur_smux;
3112 return 0;
3113}
3114
3115static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
3116 struct snd_ctl_elem_value *ucontrol)
3117{
3118 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3119 struct ad198x_spec *spec = codec->spec;
3120 unsigned int val = ucontrol->value.enumerated.item[0];
3121 struct nid_path *path;
3122 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
3123
3124 if (val >= num_conns)
3125 return -EINVAL;
3126 if (spec->cur_smux == val)
3127 return 0;
3128
3129 mutex_lock(&codec->control_mutex);
3130 codec->cached_write = 1;
3131 path = snd_hda_get_path_from_idx(codec,
3132 spec->smux_paths[spec->cur_smux]);
3133 if (path)
3134 snd_hda_activate_path(codec, path, false, true);
3135 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
3136 if (path)
3137 snd_hda_activate_path(codec, path, true, true);
3138 spec->cur_smux = val;
3139 codec->cached_write = 0;
3140 mutex_unlock(&codec->control_mutex);
3141 snd_hda_codec_flush_cache(codec); /* flush the updates */
3142 return 1;
3143}
3144
3145static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
3146 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3147 .name = "IEC958 Playback Source",
3148 .info = ad1988_auto_smux_enum_info,
3149 .get = ad1988_auto_smux_enum_get,
3150 .put = ad1988_auto_smux_enum_put,
3151};
3152
3153static int ad1988_auto_init(struct hda_codec *codec)
3154{
3155 struct ad198x_spec *spec = codec->spec;
3156 int i, err;
3157
3158 err = snd_hda_gen_init(codec);
3159 if (err < 0)
3160 return err;
3161 if (!spec->gen.autocfg.dig_outs)
3162 return 0;
3163
3164 for (i = 0; i < 4; i++) {
3165 struct nid_path *path;
3166 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
3167 if (path)
3168 snd_hda_activate_path(codec, path, path->active, false);
3169 }
3170
3171 return 0;
3172}
3173
3174static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
3175{
3176 struct ad198x_spec *spec = codec->spec;
3177 int i, num_conns;
3178 /* we create four static faked paths, since AD codecs have odd
3179 * widget connections regarding the SPDIF out source
3180 */
3181 static struct nid_path fake_paths[4] = {
3182 {
3183 .depth = 3,
3184 .path = { 0x02, 0x1d, 0x1b },
3185 .idx = { 0, 0, 0 },
3186 .multi = { 0, 0, 0 },
3187 },
3188 {
3189 .depth = 4,
3190 .path = { 0x08, 0x0b, 0x1d, 0x1b },
3191 .idx = { 0, 0, 1, 0 },
3192 .multi = { 0, 1, 0, 0 },
3193 },
3194 {
3195 .depth = 4,
3196 .path = { 0x09, 0x0b, 0x1d, 0x1b },
3197 .idx = { 0, 1, 1, 0 },
3198 .multi = { 0, 1, 0, 0 },
3199 },
3200 {
3201 .depth = 4,
3202 .path = { 0x0f, 0x0b, 0x1d, 0x1b },
3203 .idx = { 0, 2, 1, 0 },
3204 .multi = { 0, 1, 0, 0 },
3205 },
3206 };
3207
3208 /* SPDIF source mux appears to be present only on AD1988A */
3209 if (!spec->gen.autocfg.dig_outs ||
3210 get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
3211 return 0;
3212
3213 num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
3214 if (num_conns != 3 && num_conns != 4)
3215 return 0;
3216
3217 for (i = 0; i < num_conns; i++) {
3218 struct nid_path *path = snd_array_new(&spec->gen.paths);
3219 if (!path)
3220 return -ENOMEM;
3221 *path = fake_paths[i];
3222 if (!i)
3223 path->active = 1;
3224 spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
3225 }
3226
3227 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
3228 return -ENOMEM;
3229
3230 codec->patch_ops.init = ad1988_auto_init;
3231
3232 return 0;
3233}
3234
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003235/*
Takashi Iwaid32410b12005-11-24 16:06:23 +01003236 */
3237
Takashi Iwaid32410b12005-11-24 16:06:23 +01003238static int ad1988_parse_auto_config(struct hda_codec *codec)
3239{
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003240 struct ad198x_spec *spec;
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003241 int err;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003242
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003243 err = alloc_ad_spec(codec);
3244 if (err < 0)
3245 return err;
3246 spec = codec->spec;
3247
Takashi Iwaif2f8be42013-01-21 16:40:16 +01003248 spec->gen.mixer_nid = 0x20;
Takashi Iwaie4a395e2013-01-23 17:00:31 +01003249 spec->gen.mixer_merge_nid = 0x21;
Takashi Iwai7504b6c2013-03-18 11:25:51 +01003250 spec->gen.beep_nid = 0x10;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003251 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003252 err = ad198x_parse_auto_config(codec);
3253 if (err < 0)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003254 goto error;
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003255 err = ad1988_add_spdif_mux_ctl(codec);
3256 if (err < 0)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003257 goto error;
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003258 return 0;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003259
3260 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +01003261 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003262 return err;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003263}
3264
Takashi Iwaid32410b12005-11-24 16:06:23 +01003265/*
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003266 */
3267
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003268#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwaiea734962011-01-17 11:29:34 +01003269static const char * const ad1988_models[AD1988_MODEL_LAST] = {
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003270 [AD1988_6STACK] = "6stack",
3271 [AD1988_6STACK_DIG] = "6stack-dig",
3272 [AD1988_3STACK] = "3stack",
3273 [AD1988_3STACK_DIG] = "3stack-dig",
3274 [AD1988_LAPTOP] = "laptop",
3275 [AD1988_LAPTOP_DIG] = "laptop-dig",
3276 [AD1988_AUTO] = "auto",
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003277};
3278
Takashi Iwai498f5b12011-05-02 11:33:15 +02003279static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
Tobin Davis18768992007-03-12 22:20:51 +01003280 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
Takashi Iwaiac3e3742007-12-17 17:14:18 +01003281 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
Travis Placeb9e16bc2008-05-21 16:57:20 +02003282 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
Tony Vroon4e60b4f2011-05-24 22:16:15 +01003283 SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
Robin H. Johnsonf51ff992008-09-13 16:55:01 -07003284 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
Tobin Davisa64c8cd2007-03-12 11:36:00 +01003285 {}
3286};
3287
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003288static int patch_ad1988(struct hda_codec *codec)
3289{
3290 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003291 int err, board_config;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003292
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003293 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
Tobin Davisa64c8cd2007-03-12 11:36:00 +01003294 ad1988_models, ad1988_cfg_tbl);
Takashi Iwaif5fcc132006-11-24 17:07:44 +01003295 if (board_config < 0) {
Takashi Iwai9a11f1a2009-07-28 16:01:20 +02003296 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3297 codec->chip_name);
Takashi Iwaid32410b12005-11-24 16:06:23 +01003298 board_config = AD1988_AUTO;
3299 }
3300
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003301 if (board_config == AD1988_AUTO)
3302 return ad1988_parse_auto_config(codec);
3303
3304 err = alloc_ad_spec(codec);
3305 if (err < 0)
3306 return err;
3307 spec = codec->spec;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003308
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003309 if (is_rev2(codec))
3310 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
3311
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003312 err = snd_hda_attach_beep_device(codec, 0x10);
3313 if (err < 0) {
3314 ad198x_free(codec);
3315 return err;
3316 }
3317 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3318
Raymond Yau356aab72011-08-31 10:30:59 +08003319 if (!spec->multiout.hp_nid)
Raymond Yau34588702011-09-23 19:03:25 +08003320 spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003321 switch (board_config) {
3322 case AD1988_6STACK:
3323 case AD1988_6STACK_DIG:
3324 spec->multiout.max_channels = 8;
3325 spec->multiout.num_dacs = 4;
Takashi Iwai1a806f42006-07-03 15:58:16 +02003326 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01003327 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3328 else
3329 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003330 spec->input_mux = &ad1988_6stack_capture_source;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003331 spec->num_mixers = 2;
Takashi Iwai1a806f42006-07-03 15:58:16 +02003332 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01003333 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3334 else
3335 spec->mixers[0] = ad1988_6stack_mixers1;
Raymond Yau28220842011-02-08 19:58:25 +08003336 spec->mixers[1] = ad1988_6stack_mixers2;
3337 spec->num_init_verbs = 1;
3338 spec->init_verbs[0] = ad1988_6stack_init_verbs;
Raymond Yau34588702011-09-23 19:03:25 +08003339 if (board_config == AD1988_6STACK_DIG) {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003340 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3341 spec->dig_in_nid = AD1988_SPDIF_IN;
3342 }
3343 break;
3344 case AD1988_3STACK:
3345 case AD1988_3STACK_DIG:
3346 spec->multiout.max_channels = 6;
3347 spec->multiout.num_dacs = 3;
Takashi Iwai1a806f42006-07-03 15:58:16 +02003348 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01003349 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3350 else
3351 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003352 spec->input_mux = &ad1988_6stack_capture_source;
3353 spec->channel_mode = ad1988_3stack_modes;
3354 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
Takashi Iwaid32410b12005-11-24 16:06:23 +01003355 spec->num_mixers = 2;
Takashi Iwai1a806f42006-07-03 15:58:16 +02003356 if (is_rev2(codec))
Takashi Iwaid32410b12005-11-24 16:06:23 +01003357 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3358 else
3359 spec->mixers[0] = ad1988_3stack_mixers1;
3360 spec->mixers[1] = ad1988_3stack_mixers2;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003361 spec->num_init_verbs = 1;
3362 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3363 if (board_config == AD1988_3STACK_DIG)
3364 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3365 break;
3366 case AD1988_LAPTOP:
3367 case AD1988_LAPTOP_DIG:
3368 spec->multiout.max_channels = 2;
3369 spec->multiout.num_dacs = 1;
Takashi Iwaid32410b12005-11-24 16:06:23 +01003370 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003371 spec->input_mux = &ad1988_laptop_capture_source;
3372 spec->num_mixers = 1;
3373 spec->mixers[0] = ad1988_laptop_mixers;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003374 codec->inv_eapd = 1; /* inverted EAPD */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003375 spec->num_init_verbs = 1;
3376 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3377 if (board_config == AD1988_LAPTOP_DIG)
3378 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3379 break;
3380 }
3381
Takashi Iwaid32410b12005-11-24 16:06:23 +01003382 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3383 spec->adc_nids = ad1988_adc_nids;
3384 spec->capsrc_nids = ad1988_capsrc_nids;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003385 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3386 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3387 if (spec->multiout.dig_out_nid) {
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02003388 if (codec->vendor_id >= 0x11d4989a) {
3389 spec->mixers[spec->num_mixers++] =
3390 ad1989_spdif_out_mixers;
3391 spec->init_verbs[spec->num_init_verbs++] =
3392 ad1989_spdif_init_verbs;
Robin H. Johnson9cae0c62008-09-13 16:54:58 -07003393 codec->slave_dig_outs = ad1989b_slave_dig_outs;
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02003394 } else {
3395 spec->mixers[spec->num_mixers++] =
3396 ad1988_spdif_out_mixers;
3397 spec->init_verbs[spec->num_init_verbs++] =
3398 ad1988_spdif_init_verbs;
3399 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003400 }
Jaroslav Kyselafd0b0922010-01-21 14:54:38 +01003401 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003402 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
Jaroslav Kyselafd0b0922010-01-21 14:54:38 +01003403 spec->init_verbs[spec->num_init_verbs++] =
3404 ad1988_spdif_in_init_verbs;
3405 }
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003406
3407 codec->patch_ops = ad198x_patch_ops;
3408 switch (board_config) {
3409 case AD1988_LAPTOP:
3410 case AD1988_LAPTOP_DIG:
3411 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3412 break;
3413 }
Takashi Iwai83012a72012-08-24 18:38:08 +02003414#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +02003415 spec->loopback.amplist = ad1988_loopbacks;
3416#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01003417 spec->vmaster_nid = 0x04;
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003418
Takashi Iwai729d55b2009-12-25 22:49:01 +01003419 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02003420 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01003421
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003422 return 0;
3423}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003424#else /* ENABLE_AD_STATIC_QUIRKS */
3425#define patch_ad1988 ad1988_parse_auto_config
3426#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01003427
3428
3429/*
Takashi Iwai2bac6472007-05-18 18:21:41 +02003430 * AD1884 / AD1984
3431 *
3432 * port-B - front line/mic-in
3433 * port-E - aux in/out
3434 * port-F - aux in/out
3435 * port-C - rear line/mic-in
3436 * port-D - rear line/hp-out
3437 * port-A - front line/hp-out
3438 *
3439 * AD1984 = AD1884 + two digital mic-ins
3440 *
3441 * FIXME:
3442 * For simplicity, we share the single DAC for both HP and line-outs
3443 * right now. The inidividual playbacks could be easily implemented,
3444 * but no build-up framework is given, so far.
3445 */
3446
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003447#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai498f5b12011-05-02 11:33:15 +02003448static const hda_nid_t ad1884_dac_nids[1] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003449 0x04,
3450};
3451
Takashi Iwai498f5b12011-05-02 11:33:15 +02003452static const hda_nid_t ad1884_adc_nids[2] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003453 0x08, 0x09,
3454};
3455
Takashi Iwai498f5b12011-05-02 11:33:15 +02003456static const hda_nid_t ad1884_capsrc_nids[2] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003457 0x0c, 0x0d,
3458};
3459
3460#define AD1884_SPDIF_OUT 0x02
3461
Takashi Iwai498f5b12011-05-02 11:33:15 +02003462static const struct hda_input_mux ad1884_capture_source = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003463 .num_items = 4,
3464 .items = {
3465 { "Front Mic", 0x0 },
3466 { "Mic", 0x1 },
3467 { "CD", 0x2 },
3468 { "Mix", 0x3 },
3469 },
3470};
3471
Takashi Iwai498f5b12011-05-02 11:33:15 +02003472static const struct snd_kcontrol_new ad1884_base_mixers[] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003473 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3474 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3475 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3476 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3477 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3478 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3479 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3480 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3481 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3482 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3483 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3484 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01003485 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3486 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003487 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3488 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3489 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3490 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3491 {
3492 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3493 /* The multiple "Capture Source" controls confuse alsamixer
3494 * So call somewhat different..
Takashi Iwai2bac6472007-05-18 18:21:41 +02003495 */
3496 /* .name = "Capture Source", */
3497 .name = "Input Source",
3498 .count = 2,
3499 .info = ad198x_mux_enum_info,
3500 .get = ad198x_mux_enum_get,
3501 .put = ad198x_mux_enum_put,
3502 },
3503 /* SPDIF controls */
3504 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3505 {
3506 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3507 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3508 /* identical with ad1983 */
3509 .info = ad1983_spdif_route_info,
3510 .get = ad1983_spdif_route_get,
3511 .put = ad1983_spdif_route_put,
3512 },
3513 { } /* end */
3514};
3515
Takashi Iwai498f5b12011-05-02 11:33:15 +02003516static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003517 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3518 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3519 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
Takashi Iwai538c49c2007-06-05 12:13:34 +02003520 HDA_INPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003521 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
Takashi Iwai538c49c2007-06-05 12:13:34 +02003522 HDA_INPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003523 { } /* end */
3524};
3525
3526/*
3527 * initialization verbs
3528 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02003529static const struct hda_verb ad1884_init_verbs[] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003530 /* DACs; mute as default */
Takashi Iwai3b194402007-06-04 18:32:23 +02003531 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3532 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003533 /* Port-A (HP) mixer */
3534 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3535 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3536 /* Port-A pin */
3537 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3538 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3539 /* HP selector - select DAC2 */
3540 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3541 /* Port-D (Line-out) mixer */
3542 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3543 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3544 /* Port-D pin */
3545 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3546 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3547 /* Mono-out mixer */
3548 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3549 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3550 /* Mono-out pin */
3551 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3552 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3553 /* Mono selector */
3554 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3555 /* Port-B (front mic) pin */
3556 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai60e388e2009-01-23 12:37:09 +01003557 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003558 /* Port-C (rear mic) pin */
3559 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai60e388e2009-01-23 12:37:09 +01003560 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003561 /* Analog mixer; mute as default */
3562 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3563 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3564 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3565 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3566 /* Analog Mix output amp */
3567 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3568 /* SPDIF output selector */
3569 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3570 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3571 { } /* end */
3572};
3573
Takashi Iwai83012a72012-08-24 18:38:08 +02003574#ifdef CONFIG_PM
Takashi Iwai498f5b12011-05-02 11:33:15 +02003575static const struct hda_amp_list ad1884_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02003576 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3577 { 0x20, HDA_INPUT, 1 }, /* Mic */
3578 { 0x20, HDA_INPUT, 2 }, /* CD */
3579 { 0x20, HDA_INPUT, 4 }, /* Docking */
3580 { } /* end */
3581};
3582#endif
3583
Takashi Iwaiea734962011-01-17 11:29:34 +01003584static const char * const ad1884_slave_vols[] = {
Takashi Iwai9322ca52012-02-03 14:28:01 +01003585 "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
David Henningssonc40bd912012-09-19 12:19:47 +02003586 "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",
Takashi Iwai2134ea42008-01-10 16:53:55 +01003587 NULL
3588};
3589
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003590enum {
3591 AD1884_AUTO,
3592 AD1884_BASIC,
3593 AD1884_MODELS
3594};
3595
3596static const char * const ad1884_models[AD1884_MODELS] = {
3597 [AD1884_AUTO] = "auto",
3598 [AD1884_BASIC] = "basic",
3599};
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003600#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003601
Takashi Iwaia928bd22013-01-22 18:18:42 +01003602
3603/* set the upper-limit for mixer amp to 0dB for avoiding the possible
3604 * damage by overloading
3605 */
3606static void ad1884_fixup_amp_override(struct hda_codec *codec,
3607 const struct hda_fixup *fix, int action)
3608{
3609 if (action == HDA_FIXUP_ACT_PRE_PROBE)
3610 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
3611 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
3612 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
3613 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
3614 (1 << AC_AMPCAP_MUTE_SHIFT));
3615}
3616
3617static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
3618 const struct hda_fixup *fix, int action)
3619{
3620 struct ad198x_spec *spec = codec->spec;
3621
Takashi Iwaic38217e2013-07-04 12:54:22 +02003622 switch (action) {
3623 case HDA_FIXUP_ACT_PRE_PROBE:
3624 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
3625 break;
3626 case HDA_FIXUP_ACT_PROBE:
Takashi Iwaia928bd22013-01-22 18:18:42 +01003627 if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
3628 spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
3629 else
3630 spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
Takashi Iwaic38217e2013-07-04 12:54:22 +02003631 break;
Takashi Iwaia928bd22013-01-22 18:18:42 +01003632 }
3633}
3634
3635enum {
3636 AD1884_FIXUP_AMP_OVERRIDE,
3637 AD1884_FIXUP_HP_EAPD,
3638};
3639
3640static const struct hda_fixup ad1884_fixups[] = {
3641 [AD1884_FIXUP_AMP_OVERRIDE] = {
3642 .type = HDA_FIXUP_FUNC,
3643 .v.func = ad1884_fixup_amp_override,
3644 },
3645 [AD1884_FIXUP_HP_EAPD] = {
3646 .type = HDA_FIXUP_FUNC,
3647 .v.func = ad1884_fixup_hp_eapd,
3648 .chained = true,
3649 .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
3650 },
3651};
3652
3653static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
3654 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
3655 {}
3656};
3657
3658
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003659static int ad1884_parse_auto_config(struct hda_codec *codec)
3660{
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003661 struct ad198x_spec *spec;
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003662 int err;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003663
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003664 err = alloc_ad_spec(codec);
3665 if (err < 0)
3666 return err;
3667 spec = codec->spec;
3668
Takashi Iwaif2f8be42013-01-21 16:40:16 +01003669 spec->gen.mixer_nid = 0x20;
Takashi Iwai6f063302014-03-05 11:52:24 +01003670 spec->gen.mixer_merge_nid = 0x21;
Takashi Iwai7504b6c2013-03-18 11:25:51 +01003671 spec->gen.beep_nid = 0x10;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003672 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
Takashi Iwaia928bd22013-01-22 18:18:42 +01003673
3674 snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
3675 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
3676
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003677 err = ad198x_parse_auto_config(codec);
3678 if (err < 0)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003679 goto error;
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003680 err = ad1983_add_spdif_mux_ctl(codec);
3681 if (err < 0)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003682 goto error;
Takashi Iwaia928bd22013-01-22 18:18:42 +01003683
3684 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
3685
Takashi Iwai272f3ea2013-01-22 15:31:33 +01003686 return 0;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003687
3688 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +01003689 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003690 return err;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003691}
3692
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003693#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003694static int patch_ad1884_basic(struct hda_codec *codec)
Takashi Iwai2bac6472007-05-18 18:21:41 +02003695{
3696 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003697 int err;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003698
Takashi Iwai361dab32012-05-09 14:35:27 +02003699 err = alloc_ad_spec(codec);
3700 if (err < 0)
3701 return err;
3702 spec = codec->spec;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003703
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01003704 err = snd_hda_attach_beep_device(codec, 0x10);
3705 if (err < 0) {
3706 ad198x_free(codec);
3707 return err;
3708 }
3709 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3710
Takashi Iwai2bac6472007-05-18 18:21:41 +02003711 spec->multiout.max_channels = 2;
3712 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3713 spec->multiout.dac_nids = ad1884_dac_nids;
3714 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3715 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3716 spec->adc_nids = ad1884_adc_nids;
3717 spec->capsrc_nids = ad1884_capsrc_nids;
3718 spec->input_mux = &ad1884_capture_source;
3719 spec->num_mixers = 1;
3720 spec->mixers[0] = ad1884_base_mixers;
3721 spec->num_init_verbs = 1;
3722 spec->init_verbs[0] = ad1884_init_verbs;
3723 spec->spdif_route = 0;
Takashi Iwai83012a72012-08-24 18:38:08 +02003724#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +02003725 spec->loopback.amplist = ad1884_loopbacks;
3726#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01003727 spec->vmaster_nid = 0x04;
3728 /* we need to cover all playback volumes */
3729 spec->slave_vols = ad1884_slave_vols;
Takashi Iwai18478e82012-03-09 17:51:10 +01003730 /* slaves may contain input volumes, so we can't raise to 0dB blindly */
3731 spec->avoid_init_slave_vol = 1;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003732
3733 codec->patch_ops = ad198x_patch_ops;
3734
Takashi Iwai729d55b2009-12-25 22:49:01 +01003735 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02003736 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01003737
Takashi Iwai2bac6472007-05-18 18:21:41 +02003738 return 0;
3739}
3740
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003741static int patch_ad1884(struct hda_codec *codec)
3742{
3743 int board_config;
3744
3745 board_config = snd_hda_check_board_config(codec, AD1884_MODELS,
3746 ad1884_models, NULL);
Takashi Iwai657e1b92013-01-22 18:42:39 +01003747 if (board_config < 0) {
3748 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3749 codec->chip_name);
3750 board_config = AD1884_AUTO;
3751 }
3752
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003753 if (board_config == AD1884_AUTO)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003754 return ad1884_parse_auto_config(codec);
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003755 else
3756 return patch_ad1884_basic(codec);
3757}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003758#else /* ENABLE_AD_STATIC_QUIRKS */
3759#define patch_ad1884 ad1884_parse_auto_config
3760#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003761
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003762
3763#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai2bac6472007-05-18 18:21:41 +02003764/*
3765 * Lenovo Thinkpad T61/X61
3766 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02003767static const struct hda_input_mux ad1984_thinkpad_capture_source = {
Takashi Iwaib26451c2008-02-26 11:56:35 +01003768 .num_items = 4,
Takashi Iwai2bac6472007-05-18 18:21:41 +02003769 .items = {
3770 { "Mic", 0x0 },
3771 { "Internal Mic", 0x1 },
3772 { "Mix", 0x3 },
David Henningssonc40bd912012-09-19 12:19:47 +02003773 { "Dock Mic", 0x4 },
Takashi Iwai2bac6472007-05-18 18:21:41 +02003774 },
3775};
3776
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003777
3778/*
3779 * Dell Precision T3400
3780 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02003781static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003782 .num_items = 3,
3783 .items = {
3784 { "Front Mic", 0x0 },
3785 { "Line-In", 0x1 },
3786 { "Mix", 0x3 },
3787 },
3788};
3789
3790
Takashi Iwai498f5b12011-05-02 11:33:15 +02003791static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003792 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3793 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3794 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3795 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3796 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3797 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3798 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3799 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +01003800 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3801 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
David Henningssonc40bd912012-09-19 12:19:47 +02003802 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3803 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01003804 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3805 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3806 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003807 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3808 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3809 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3810 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3811 {
3812 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3813 /* The multiple "Capture Source" controls confuse alsamixer
3814 * So call somewhat different..
Takashi Iwai2bac6472007-05-18 18:21:41 +02003815 */
3816 /* .name = "Capture Source", */
3817 .name = "Input Source",
3818 .count = 2,
3819 .info = ad198x_mux_enum_info,
3820 .get = ad198x_mux_enum_get,
3821 .put = ad198x_mux_enum_put,
3822 },
Jerone Youngebf00c52008-01-07 12:22:18 +01003823 /* SPDIF controls */
3824 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3825 {
3826 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3827 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3828 /* identical with ad1983 */
3829 .info = ad1983_spdif_route_info,
3830 .get = ad1983_spdif_route_get,
3831 .put = ad1983_spdif_route_put,
3832 },
Takashi Iwai2bac6472007-05-18 18:21:41 +02003833 { } /* end */
3834};
3835
3836/* additional verbs */
Takashi Iwai498f5b12011-05-02 11:33:15 +02003837static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003838 /* Port-E (docking station mic) pin */
3839 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3840 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3841 /* docking mic boost */
Takashi Iwai70040c02009-01-23 14:18:11 +01003842 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +01003843 /* Analog PC Beeper - allow firmware/ACPI beeps */
3844 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003845 /* Analog mixer - docking mic; mute as default */
3846 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
Takashi Iwaib959d1f2007-06-08 12:25:25 +02003847 /* enable EAPD bit */
3848 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
Takashi Iwai2bac6472007-05-18 18:21:41 +02003849 { } /* end */
3850};
3851
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003852/*
3853 * Dell Precision T3400
3854 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02003855static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003856 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3857 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3858 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3859 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3860 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3861 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3862 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3863 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3864 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01003865 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
3866 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003867 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3868 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3869 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3870 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3871 {
3872 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3873 /* The multiple "Capture Source" controls confuse alsamixer
3874 * So call somewhat different..
3875 */
3876 /* .name = "Capture Source", */
3877 .name = "Input Source",
3878 .count = 2,
3879 .info = ad198x_mux_enum_info,
3880 .get = ad198x_mux_enum_get,
3881 .put = ad198x_mux_enum_put,
3882 },
3883 { } /* end */
3884};
3885
Takashi Iwai2bac6472007-05-18 18:21:41 +02003886/* Digial MIC ADC NID 0x05 + 0x06 */
3887static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3888 struct hda_codec *codec,
3889 unsigned int stream_tag,
3890 unsigned int format,
3891 struct snd_pcm_substream *substream)
3892{
3893 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3894 stream_tag, 0, format);
3895 return 0;
3896}
3897
3898static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3899 struct hda_codec *codec,
3900 struct snd_pcm_substream *substream)
3901{
Takashi Iwai888afa12008-03-18 09:57:50 +01003902 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
Takashi Iwai2bac6472007-05-18 18:21:41 +02003903 return 0;
3904}
3905
Takashi Iwai498f5b12011-05-02 11:33:15 +02003906static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003907 .substreams = 2,
3908 .channels_min = 2,
3909 .channels_max = 2,
3910 .nid = 0x05,
3911 .ops = {
3912 .prepare = ad1984_pcm_dmic_prepare,
3913 .cleanup = ad1984_pcm_dmic_cleanup
3914 },
3915};
3916
3917static int ad1984_build_pcms(struct hda_codec *codec)
3918{
3919 struct ad198x_spec *spec = codec->spec;
3920 struct hda_pcm *info;
3921 int err;
3922
3923 err = ad198x_build_pcms(codec);
3924 if (err < 0)
3925 return err;
3926
3927 info = spec->pcm_rec + codec->num_pcms;
3928 codec->num_pcms++;
3929 info->name = "AD1984 Digital Mic";
3930 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3931 return 0;
3932}
3933
3934/* models */
3935enum {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003936 AD1984_AUTO,
Takashi Iwai2bac6472007-05-18 18:21:41 +02003937 AD1984_BASIC,
3938 AD1984_THINKPAD,
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003939 AD1984_DELL_DESKTOP,
Takashi Iwai2bac6472007-05-18 18:21:41 +02003940 AD1984_MODELS
3941};
3942
Takashi Iwaiea734962011-01-17 11:29:34 +01003943static const char * const ad1984_models[AD1984_MODELS] = {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003944 [AD1984_AUTO] = "auto",
Takashi Iwai2bac6472007-05-18 18:21:41 +02003945 [AD1984_BASIC] = "basic",
3946 [AD1984_THINKPAD] = "thinkpad",
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003947 [AD1984_DELL_DESKTOP] = "dell_desktop",
Takashi Iwai2bac6472007-05-18 18:21:41 +02003948};
3949
Takashi Iwai498f5b12011-05-02 11:33:15 +02003950static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
Takashi Iwai2bac6472007-05-18 18:21:41 +02003951 /* Lenovo Thinkpad T61/X61 */
Takashi Iwaidea0a502009-02-09 17:14:52 +01003952 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003953 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
Luke Yelavich0f9f1ee92010-09-21 17:05:46 +10003954 SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
Takashi Iwai2bac6472007-05-18 18:21:41 +02003955 {}
3956};
3957
3958static int patch_ad1984(struct hda_codec *codec)
3959{
3960 struct ad198x_spec *spec;
3961 int board_config, err;
3962
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003963 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3964 ad1984_models, ad1984_cfg_tbl);
Takashi Iwai657e1b92013-01-22 18:42:39 +01003965 if (board_config < 0) {
3966 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3967 codec->chip_name);
3968 board_config = AD1984_AUTO;
3969 }
3970
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003971 if (board_config == AD1984_AUTO)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01003972 return ad1884_parse_auto_config(codec);
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003973
3974 err = patch_ad1884_basic(codec);
Takashi Iwai2bac6472007-05-18 18:21:41 +02003975 if (err < 0)
3976 return err;
3977 spec = codec->spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01003978
Takashi Iwai2bac6472007-05-18 18:21:41 +02003979 switch (board_config) {
3980 case AD1984_BASIC:
3981 /* additional digital mics */
3982 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3983 codec->patch_ops.build_pcms = ad1984_build_pcms;
3984 break;
3985 case AD1984_THINKPAD:
Jerone Young68c18692010-08-03 01:46:44 -05003986 if (codec->subsystem_id == 0x17aa20fb) {
3987 /* Thinpad X300 does not have the ability to do SPDIF,
3988 or attach to docking station to use SPDIF */
3989 spec->multiout.dig_out_nid = 0;
3990 } else
3991 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003992 spec->input_mux = &ad1984_thinkpad_capture_source;
3993 spec->mixers[0] = ad1984_thinkpad_mixers;
3994 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
Jaroslav Kysela0bf0e5a2010-03-26 10:33:18 +01003995 spec->analog_beep = 1;
Takashi Iwai2bac6472007-05-18 18:21:41 +02003996 break;
Douglas Kosovic0aaa22e2008-01-29 15:02:50 +01003997 case AD1984_DELL_DESKTOP:
3998 spec->multiout.dig_out_nid = 0;
3999 spec->input_mux = &ad1984_dell_desktop_capture_source;
4000 spec->mixers[0] = ad1984_dell_desktop_mixers;
4001 break;
Takashi Iwai2bac6472007-05-18 18:21:41 +02004002 }
4003 return 0;
4004}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01004005#else /* ENABLE_AD_STATIC_QUIRKS */
4006#define patch_ad1984 ad1884_parse_auto_config
4007#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai2bac6472007-05-18 18:21:41 +02004008
4009
4010/*
Takashi Iwaic5059252008-02-16 09:43:56 +01004011 * AD1883 / AD1884A / AD1984A / AD1984B
4012 *
4013 * port-B (0x14) - front mic-in
4014 * port-E (0x1c) - rear mic-in
4015 * port-F (0x16) - CD / ext out
4016 * port-C (0x15) - rear line-in
4017 * port-D (0x12) - rear line-out
4018 * port-A (0x11) - front hp-out
4019 *
4020 * AD1984A = AD1884A + digital-mic
4021 * AD1883 = equivalent with AD1984A
4022 * AD1984B = AD1984A + extra SPDIF-out
4023 *
4024 * FIXME:
4025 * We share the single DAC for both HP and line-outs (see AD1884/1984).
4026 */
4027
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01004028#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai498f5b12011-05-02 11:33:15 +02004029static const hda_nid_t ad1884a_dac_nids[1] = {
Takashi Iwaic5059252008-02-16 09:43:56 +01004030 0x03,
4031};
4032
4033#define ad1884a_adc_nids ad1884_adc_nids
4034#define ad1884a_capsrc_nids ad1884_capsrc_nids
4035
4036#define AD1884A_SPDIF_OUT 0x02
4037
Takashi Iwai498f5b12011-05-02 11:33:15 +02004038static const struct hda_input_mux ad1884a_capture_source = {
Takashi Iwaic5059252008-02-16 09:43:56 +01004039 .num_items = 5,
4040 .items = {
4041 { "Front Mic", 0x0 },
4042 { "Mic", 0x4 },
4043 { "Line", 0x1 },
4044 { "CD", 0x2 },
4045 { "Mix", 0x3 },
4046 },
4047};
4048
Takashi Iwai498f5b12011-05-02 11:33:15 +02004049static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
Takashi Iwaic5059252008-02-16 09:43:56 +01004050 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4051 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4052 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4053 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4054 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4055 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
4056 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4057 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4058 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4059 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4060 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4061 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4062 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4063 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4064 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
4065 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01004066 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4067 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
4068 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
Takashi Iwaic5059252008-02-16 09:43:56 +01004069 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4070 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4071 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4072 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4073 {
4074 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4075 /* The multiple "Capture Source" controls confuse alsamixer
4076 * So call somewhat different..
4077 */
4078 /* .name = "Capture Source", */
4079 .name = "Input Source",
4080 .count = 2,
4081 .info = ad198x_mux_enum_info,
4082 .get = ad198x_mux_enum_get,
4083 .put = ad198x_mux_enum_put,
4084 },
4085 /* SPDIF controls */
4086 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4087 {
4088 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4089 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4090 /* identical with ad1983 */
4091 .info = ad1983_spdif_route_info,
4092 .get = ad1983_spdif_route_get,
4093 .put = ad1983_spdif_route_put,
4094 },
4095 { } /* end */
4096};
4097
4098/*
4099 * initialization verbs
4100 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02004101static const struct hda_verb ad1884a_init_verbs[] = {
Takashi Iwaic5059252008-02-16 09:43:56 +01004102 /* DACs; unmute as default */
4103 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4104 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4105 /* Port-A (HP) mixer - route only from analog mixer */
4106 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4107 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4108 /* Port-A pin */
4109 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4110 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4111 /* Port-D (Line-out) mixer - route only from analog mixer */
4112 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4113 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4114 /* Port-D pin */
4115 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4116 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4117 /* Mono-out mixer - route only from analog mixer */
4118 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4119 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4120 /* Mono-out pin */
4121 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4122 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4123 /* Port-B (front mic) pin */
4124 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
Takashi Iwai60e388e2009-01-23 12:37:09 +01004125 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaic5059252008-02-16 09:43:56 +01004126 /* Port-C (rear line-in) pin */
4127 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai60e388e2009-01-23 12:37:09 +01004128 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
Takashi Iwaic5059252008-02-16 09:43:56 +01004129 /* Port-E (rear mic) pin */
4130 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4131 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4132 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
4133 /* Port-F (CD) pin */
4134 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4135 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4136 /* Analog mixer; mute as default */
4137 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4138 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4139 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4140 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4141 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
4142 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4143 /* Analog Mix output amp */
4144 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4145 /* capture sources */
4146 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
4147 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4148 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4149 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4150 /* SPDIF output amp */
4151 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4152 { } /* end */
4153};
4154
Takashi Iwai83012a72012-08-24 18:38:08 +02004155#ifdef CONFIG_PM
Takashi Iwai498f5b12011-05-02 11:33:15 +02004156static const struct hda_amp_list ad1884a_loopbacks[] = {
Takashi Iwaic5059252008-02-16 09:43:56 +01004157 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4158 { 0x20, HDA_INPUT, 1 }, /* Mic */
4159 { 0x20, HDA_INPUT, 2 }, /* CD */
4160 { 0x20, HDA_INPUT, 4 }, /* Docking */
4161 { } /* end */
4162};
4163#endif
4164
4165/*
4166 * Laptop model
4167 *
4168 * Port A: Headphone jack
4169 * Port B: MIC jack
4170 * Port C: Internal MIC
4171 * Port D: Dock Line Out (if enabled)
4172 * Port E: Dock Line In (if enabled)
4173 * Port F: Internal speakers
4174 */
4175
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004176static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
4177 struct snd_ctl_elem_value *ucontrol)
4178{
4179 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4180 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
4181 int mute = (!ucontrol->value.integer.value[0] &&
4182 !ucontrol->value.integer.value[1]);
4183 /* toggle GPIO1 according to the mute state */
4184 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
4185 mute ? 0x02 : 0x0);
4186 return ret;
4187}
Takashi Iwaic5059252008-02-16 09:43:56 +01004188
Takashi Iwai498f5b12011-05-02 11:33:15 +02004189static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
Takashi Iwaic5059252008-02-16 09:43:56 +01004190 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004191 {
4192 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4193 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004194 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004195 .info = snd_hda_mixer_amp_switch_info,
4196 .get = snd_hda_mixer_amp_switch_get,
4197 .put = ad1884a_mobile_master_sw_put,
4198 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4199 },
Takashi Iwaic5059252008-02-16 09:43:56 +01004200 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4201 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4202 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4203 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4204 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4205 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4206 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4207 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4208 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01004209 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4210 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
4211 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
Takashi Iwaic5059252008-02-16 09:43:56 +01004212 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4213 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaic5059252008-02-16 09:43:56 +01004214 { } /* end */
4215};
4216
Takashi Iwai498f5b12011-05-02 11:33:15 +02004217static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004218 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
Takashi Iwai099db17e2009-07-02 16:10:23 +02004219 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4220 {
4221 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4222 .name = "Master Playback Switch",
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004223 .subdevice = HDA_SUBDEV_AMP_FLAG,
Takashi Iwai099db17e2009-07-02 16:10:23 +02004224 .info = snd_hda_mixer_amp_switch_info,
4225 .get = snd_hda_mixer_amp_switch_get,
4226 .put = ad1884a_mobile_master_sw_put,
4227 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4228 },
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004229 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4230 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
Takashi Iwai269ef192008-05-30 15:32:15 +02004231 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
4232 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004233 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4234 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004235 { } /* end */
4236};
4237
Takashi Iwaic5059252008-02-16 09:43:56 +01004238/* mute internal speaker if HP is plugged */
4239static void ad1884a_hp_automute(struct hda_codec *codec)
4240{
4241 unsigned int present;
4242
Takashi Iwaid56757a2009-11-18 08:00:14 +01004243 present = snd_hda_jack_detect(codec, 0x11);
Takashi Iwaic5059252008-02-16 09:43:56 +01004244 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4245 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4246 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4247 present ? 0x00 : 0x02);
4248}
4249
Takashi Iwai269ef192008-05-30 15:32:15 +02004250/* switch to external mic if plugged */
4251static void ad1884a_hp_automic(struct hda_codec *codec)
4252{
4253 unsigned int present;
4254
Takashi Iwaid56757a2009-11-18 08:00:14 +01004255 present = snd_hda_jack_detect(codec, 0x14);
Takashi Iwai269ef192008-05-30 15:32:15 +02004256 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
4257 present ? 0 : 1);
4258}
4259
Takashi Iwaic5059252008-02-16 09:43:56 +01004260#define AD1884A_HP_EVENT 0x37
Takashi Iwai269ef192008-05-30 15:32:15 +02004261#define AD1884A_MIC_EVENT 0x36
Takashi Iwaic5059252008-02-16 09:43:56 +01004262
4263/* unsolicited event for HP jack sensing */
4264static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4265{
Takashi Iwai269ef192008-05-30 15:32:15 +02004266 switch (res >> 26) {
4267 case AD1884A_HP_EVENT:
4268 ad1884a_hp_automute(codec);
4269 break;
4270 case AD1884A_MIC_EVENT:
4271 ad1884a_hp_automic(codec);
4272 break;
4273 }
Takashi Iwaic5059252008-02-16 09:43:56 +01004274}
4275
4276/* initialize jack-sensing, too */
4277static int ad1884a_hp_init(struct hda_codec *codec)
4278{
4279 ad198x_init(codec);
4280 ad1884a_hp_automute(codec);
Takashi Iwai269ef192008-05-30 15:32:15 +02004281 ad1884a_hp_automic(codec);
Takashi Iwaic5059252008-02-16 09:43:56 +01004282 return 0;
4283}
4284
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004285/* mute internal speaker if HP or docking HP is plugged */
4286static void ad1884a_laptop_automute(struct hda_codec *codec)
4287{
4288 unsigned int present;
4289
Takashi Iwaid56757a2009-11-18 08:00:14 +01004290 present = snd_hda_jack_detect(codec, 0x11);
4291 if (!present)
4292 present = snd_hda_jack_detect(codec, 0x12);
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004293 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4294 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4295 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4296 present ? 0x00 : 0x02);
4297}
4298
4299/* switch to external mic if plugged */
4300static void ad1884a_laptop_automic(struct hda_codec *codec)
4301{
4302 unsigned int idx;
4303
Takashi Iwaid56757a2009-11-18 08:00:14 +01004304 if (snd_hda_jack_detect(codec, 0x14))
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004305 idx = 0;
Takashi Iwaid56757a2009-11-18 08:00:14 +01004306 else if (snd_hda_jack_detect(codec, 0x1c))
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004307 idx = 4;
4308 else
4309 idx = 1;
4310 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
4311}
4312
4313/* unsolicited event for HP jack sensing */
4314static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
4315 unsigned int res)
4316{
4317 switch (res >> 26) {
4318 case AD1884A_HP_EVENT:
4319 ad1884a_laptop_automute(codec);
4320 break;
4321 case AD1884A_MIC_EVENT:
4322 ad1884a_laptop_automic(codec);
4323 break;
4324 }
4325}
4326
4327/* initialize jack-sensing, too */
4328static int ad1884a_laptop_init(struct hda_codec *codec)
4329{
4330 ad198x_init(codec);
4331 ad1884a_laptop_automute(codec);
4332 ad1884a_laptop_automic(codec);
4333 return 0;
4334}
4335
Takashi Iwaic5059252008-02-16 09:43:56 +01004336/* additional verbs for laptop model */
Takashi Iwai498f5b12011-05-02 11:33:15 +02004337static const struct hda_verb ad1884a_laptop_verbs[] = {
Takashi Iwaic5059252008-02-16 09:43:56 +01004338 /* Port-A (HP) pin - always unmuted */
4339 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4340 /* Port-F (int speaker) mixer - route only from analog mixer */
4341 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4342 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
Wu Fengguang150fe142009-08-19 16:58:59 +08004343 /* Port-F (int speaker) pin */
4344 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwaic5059252008-02-16 09:43:56 +01004345 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
Wu Fengguang150fe142009-08-19 16:58:59 +08004346 /* required for compaq 6530s/6531s speaker output */
4347 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
Takashi Iwai269ef192008-05-30 15:32:15 +02004348 /* Port-C pin - internal mic-in */
4349 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4350 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4351 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
Takashi Iwai2ad81ba2009-09-01 09:09:26 +02004352 /* Port-D (docking line-out) pin - default unmuted */
4353 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
Takashi Iwaic5059252008-02-16 09:43:56 +01004354 /* analog mix */
4355 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4356 /* unsolicited event for pin-sense */
4357 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004358 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
Takashi Iwai269ef192008-05-30 15:32:15 +02004359 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004360 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
Takashi Iwaife7e5682009-08-31 08:37:46 +02004361 /* allow to touch GPIO1 (for mute control) */
4362 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4363 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4364 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
Takashi Iwaic5059252008-02-16 09:43:56 +01004365 { } /* end */
4366};
4367
Takashi Iwai498f5b12011-05-02 11:33:15 +02004368static const struct hda_verb ad1884a_mobile_verbs[] = {
Takashi Iwai73156132009-04-23 08:24:48 +02004369 /* DACs; unmute as default */
4370 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4371 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4372 /* Port-A (HP) mixer - route only from analog mixer */
4373 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4374 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4375 /* Port-A pin */
4376 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4377 /* Port-A (HP) pin - always unmuted */
4378 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4379 /* Port-B (mic jack) pin */
4380 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4381 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4382 /* Port-C (int mic) pin */
4383 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4384 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4385 /* Port-F (int speaker) mixer - route only from analog mixer */
4386 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4387 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4388 /* Port-F pin */
4389 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4390 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4391 /* Analog mixer; mute as default */
4392 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4393 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4394 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4395 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4396 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4397 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4398 /* Analog Mix output amp */
4399 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4400 /* capture sources */
4401 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4402 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4403 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4404 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4405 /* unsolicited event for pin-sense */
4406 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4407 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
Takashi Iwai099db17e2009-07-02 16:10:23 +02004408 /* allow to touch GPIO1 (for mute control) */
4409 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4410 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4411 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
Takashi Iwai73156132009-04-23 08:24:48 +02004412 { } /* end */
4413};
4414
Takashi Iwaic5059252008-02-16 09:43:56 +01004415/*
Takashi Iwaif0813742008-03-18 12:13:03 +01004416 * Thinkpad X300
4417 * 0x11 - HP
4418 * 0x12 - speaker
4419 * 0x14 - mic-in
4420 * 0x17 - built-in mic
4421 */
4422
Takashi Iwai498f5b12011-05-02 11:33:15 +02004423static const struct hda_verb ad1984a_thinkpad_verbs[] = {
Takashi Iwaif0813742008-03-18 12:13:03 +01004424 /* HP unmute */
4425 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4426 /* analog mix */
4427 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4428 /* turn on EAPD */
4429 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4430 /* unsolicited event for pin-sense */
4431 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4432 /* internal mic - dmic */
4433 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
Takashi Iwai05808ec2008-04-23 13:50:08 +02004434 /* set magic COEFs for dmic */
4435 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4436 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
Takashi Iwaif0813742008-03-18 12:13:03 +01004437 { } /* end */
4438};
4439
Takashi Iwai498f5b12011-05-02 11:33:15 +02004440static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
Takashi Iwaif0813742008-03-18 12:13:03 +01004441 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4442 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4443 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4444 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4445 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4446 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01004447 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4448 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
Takashi Iwaif0813742008-03-18 12:13:03 +01004449 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4450 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4451 {
4452 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4453 .name = "Capture Source",
4454 .info = ad198x_mux_enum_info,
4455 .get = ad198x_mux_enum_get,
4456 .put = ad198x_mux_enum_put,
4457 },
4458 { } /* end */
4459};
4460
Takashi Iwai498f5b12011-05-02 11:33:15 +02004461static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
Takashi Iwaif0813742008-03-18 12:13:03 +01004462 .num_items = 3,
4463 .items = {
4464 { "Mic", 0x0 },
4465 { "Internal Mic", 0x5 },
4466 { "Mix", 0x3 },
4467 },
4468};
4469
4470/* mute internal speaker if HP is plugged */
4471static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4472{
4473 unsigned int present;
4474
Takashi Iwaid56757a2009-11-18 08:00:14 +01004475 present = snd_hda_jack_detect(codec, 0x11);
Takashi Iwaif0813742008-03-18 12:13:03 +01004476 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4477 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4478}
4479
4480/* unsolicited event for HP jack sensing */
4481static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4482 unsigned int res)
4483{
4484 if ((res >> 26) != AD1884A_HP_EVENT)
4485 return;
4486 ad1984a_thinkpad_automute(codec);
4487}
4488
4489/* initialize jack-sensing, too */
4490static int ad1984a_thinkpad_init(struct hda_codec *codec)
4491{
4492 ad198x_init(codec);
4493 ad1984a_thinkpad_automute(codec);
4494 return 0;
4495}
4496
4497/*
David Henningsson677cd902011-02-07 15:19:34 +01004498 * Precision R5500
4499 * 0x12 - HP/line-out
4500 * 0x13 - speaker (mono)
4501 * 0x15 - mic-in
4502 */
4503
Takashi Iwai498f5b12011-05-02 11:33:15 +02004504static const struct hda_verb ad1984a_precision_verbs[] = {
David Henningsson677cd902011-02-07 15:19:34 +01004505 /* Unmute main output path */
4506 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4507 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
4508 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */
4509 /* Analog mixer; mute as default */
4510 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4511 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4512 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4513 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4514 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4515 /* Select mic as input */
4516 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
4517 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */
4518 /* Configure as mic */
4519 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4520 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4521 /* HP unmute */
4522 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4523 /* turn on EAPD */
4524 {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4525 /* unsolicited event for pin-sense */
4526 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4527 { } /* end */
4528};
4529
Takashi Iwai498f5b12011-05-02 11:33:15 +02004530static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
David Henningsson677cd902011-02-07 15:19:34 +01004531 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4532 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4533 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4534 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4535 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4536 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4537 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
4538 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4539 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT),
4540 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4541 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4542 { } /* end */
4543};
4544
4545
4546/* mute internal speaker if HP is plugged */
4547static void ad1984a_precision_automute(struct hda_codec *codec)
4548{
4549 unsigned int present;
4550
4551 present = snd_hda_jack_detect(codec, 0x12);
4552 snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
4553 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4554}
4555
4556
4557/* unsolicited event for HP jack sensing */
4558static void ad1984a_precision_unsol_event(struct hda_codec *codec,
4559 unsigned int res)
4560{
4561 if ((res >> 26) != AD1884A_HP_EVENT)
4562 return;
4563 ad1984a_precision_automute(codec);
4564}
4565
4566/* initialize jack-sensing, too */
4567static int ad1984a_precision_init(struct hda_codec *codec)
4568{
4569 ad198x_init(codec);
4570 ad1984a_precision_automute(codec);
4571 return 0;
4572}
4573
4574
4575/*
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004576 * HP Touchsmart
4577 * port-A (0x11) - front hp-out
4578 * port-B (0x14) - unused
4579 * port-C (0x15) - unused
4580 * port-D (0x12) - rear line out
4581 * port-E (0x1c) - front mic-in
4582 * port-F (0x16) - Internal speakers
4583 * digital-mic (0x17) - Internal mic
4584 */
4585
Takashi Iwai498f5b12011-05-02 11:33:15 +02004586static const struct hda_verb ad1984a_touchsmart_verbs[] = {
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004587 /* DACs; unmute as default */
4588 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4589 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4590 /* Port-A (HP) mixer - route only from analog mixer */
4591 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4592 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4593 /* Port-A pin */
4594 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4595 /* Port-A (HP) pin - always unmuted */
4596 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4597 /* Port-E (int speaker) mixer - route only from analog mixer */
4598 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4599 /* Port-E pin */
4600 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4601 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4602 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4603 /* Port-F (int speaker) mixer - route only from analog mixer */
4604 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4605 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4606 /* Port-F pin */
4607 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4608 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4609 /* Analog mixer; mute as default */
4610 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4611 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4612 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4613 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4614 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4615 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4616 /* Analog Mix output amp */
4617 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4618 /* capture sources */
4619 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4620 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4621 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4622 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4623 /* unsolicited event for pin-sense */
4624 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4625 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4626 /* allow to touch GPIO1 (for mute control) */
4627 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4628 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4629 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4630 /* internal mic - dmic */
4631 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4632 /* set magic COEFs for dmic */
4633 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4634 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4635 { } /* end */
4636};
4637
Takashi Iwai498f5b12011-05-02 11:33:15 +02004638static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004639 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4640/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4641 {
4642 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
Jaroslav Kysela5e26dfd2009-12-10 13:57:01 +01004643 .subdevice = HDA_SUBDEV_AMP_FLAG,
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004644 .name = "Master Playback Switch",
4645 .info = snd_hda_mixer_amp_switch_info,
4646 .get = snd_hda_mixer_amp_switch_get,
4647 .put = ad1884a_mobile_master_sw_put,
4648 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4649 },
4650 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4651 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4652 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4653 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01004654 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
4655 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004656 { } /* end */
4657};
4658
4659/* switch to external mic if plugged */
4660static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4661{
Takashi Iwaid56757a2009-11-18 08:00:14 +01004662 if (snd_hda_jack_detect(codec, 0x1c))
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004663 snd_hda_codec_write(codec, 0x0c, 0,
4664 AC_VERB_SET_CONNECT_SEL, 0x4);
Takashi Iwaid56757a2009-11-18 08:00:14 +01004665 else
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004666 snd_hda_codec_write(codec, 0x0c, 0,
4667 AC_VERB_SET_CONNECT_SEL, 0x5);
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004668}
4669
4670
4671/* unsolicited event for HP jack sensing */
4672static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4673 unsigned int res)
4674{
4675 switch (res >> 26) {
4676 case AD1884A_HP_EVENT:
4677 ad1884a_hp_automute(codec);
4678 break;
4679 case AD1884A_MIC_EVENT:
4680 ad1984a_touchsmart_automic(codec);
4681 break;
4682 }
4683}
4684
4685/* initialize jack-sensing, too */
4686static int ad1984a_touchsmart_init(struct hda_codec *codec)
4687{
4688 ad198x_init(codec);
4689 ad1884a_hp_automute(codec);
4690 ad1984a_touchsmart_automic(codec);
4691 return 0;
4692}
4693
4694
4695/*
Takashi Iwaic5059252008-02-16 09:43:56 +01004696 */
4697
4698enum {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01004699 AD1884A_AUTO,
Takashi Iwaic5059252008-02-16 09:43:56 +01004700 AD1884A_DESKTOP,
4701 AD1884A_LAPTOP,
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004702 AD1884A_MOBILE,
Takashi Iwaif0813742008-03-18 12:13:03 +01004703 AD1884A_THINKPAD,
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004704 AD1984A_TOUCHSMART,
David Henningsson677cd902011-02-07 15:19:34 +01004705 AD1984A_PRECISION,
Takashi Iwaic5059252008-02-16 09:43:56 +01004706 AD1884A_MODELS
4707};
4708
Takashi Iwaiea734962011-01-17 11:29:34 +01004709static const char * const ad1884a_models[AD1884A_MODELS] = {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01004710 [AD1884A_AUTO] = "auto",
Takashi Iwaic5059252008-02-16 09:43:56 +01004711 [AD1884A_DESKTOP] = "desktop",
4712 [AD1884A_LAPTOP] = "laptop",
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004713 [AD1884A_MOBILE] = "mobile",
Takashi Iwaif0813742008-03-18 12:13:03 +01004714 [AD1884A_THINKPAD] = "thinkpad",
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004715 [AD1984A_TOUCHSMART] = "touchsmart",
David Henningsson677cd902011-02-07 15:19:34 +01004716 [AD1984A_PRECISION] = "precision",
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004717};
4718
Takashi Iwai498f5b12011-05-02 11:33:15 +02004719static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
David Henningsson677cd902011-02-07 15:19:34 +01004720 SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004721 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
Takashi Iwaid5337de2009-01-07 11:41:57 +01004722 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
Takashi Iwai5695ff42008-10-28 15:39:26 +01004723 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
Takashi Iwaic2312752009-02-16 15:20:41 +01004724 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
Takashi Iwaiff848472009-07-01 18:08:01 +02004725 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
Takashi Iwai873dc782009-02-25 18:12:13 +01004726 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4727 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
Takashi Iwai286f5872009-08-27 14:37:51 +02004728 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
Takashi Iwaif0813742008-03-18 12:13:03 +01004729 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004730 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004731 {}
Takashi Iwaic5059252008-02-16 09:43:56 +01004732};
4733
4734static int patch_ad1884a(struct hda_codec *codec)
4735{
4736 struct ad198x_spec *spec;
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01004737 int err, board_config;
Takashi Iwaic5059252008-02-16 09:43:56 +01004738
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01004739 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
4740 ad1884a_models,
4741 ad1884a_cfg_tbl);
Takashi Iwai657e1b92013-01-22 18:42:39 +01004742 if (board_config < 0) {
4743 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
4744 codec->chip_name);
4745 board_config = AD1884A_AUTO;
4746 }
4747
4748 if (board_config == AD1884A_AUTO)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01004749 return ad1884_parse_auto_config(codec);
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01004750
Takashi Iwai361dab32012-05-09 14:35:27 +02004751 err = alloc_ad_spec(codec);
4752 if (err < 0)
4753 return err;
4754 spec = codec->spec;
Takashi Iwaic5059252008-02-16 09:43:56 +01004755
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01004756 err = snd_hda_attach_beep_device(codec, 0x10);
4757 if (err < 0) {
4758 ad198x_free(codec);
4759 return err;
4760 }
4761 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4762
Takashi Iwaic5059252008-02-16 09:43:56 +01004763 spec->multiout.max_channels = 2;
4764 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4765 spec->multiout.dac_nids = ad1884a_dac_nids;
4766 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4767 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4768 spec->adc_nids = ad1884a_adc_nids;
4769 spec->capsrc_nids = ad1884a_capsrc_nids;
4770 spec->input_mux = &ad1884a_capture_source;
4771 spec->num_mixers = 1;
4772 spec->mixers[0] = ad1884a_base_mixers;
4773 spec->num_init_verbs = 1;
4774 spec->init_verbs[0] = ad1884a_init_verbs;
4775 spec->spdif_route = 0;
Takashi Iwai83012a72012-08-24 18:38:08 +02004776#ifdef CONFIG_PM
Takashi Iwaic5059252008-02-16 09:43:56 +01004777 spec->loopback.amplist = ad1884a_loopbacks;
4778#endif
4779 codec->patch_ops = ad198x_patch_ops;
4780
4781 /* override some parameters */
Takashi Iwaic5059252008-02-16 09:43:56 +01004782 switch (board_config) {
4783 case AD1884A_LAPTOP:
4784 spec->mixers[0] = ad1884a_laptop_mixers;
4785 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4786 spec->multiout.dig_out_nid = 0;
Takashi Iwai17bbaa62009-08-30 12:15:59 +02004787 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4788 codec->patch_ops.init = ad1884a_laptop_init;
Takashi Iwai4dc1f872009-04-16 14:19:19 +02004789 /* set the upper-limit for mixer amp to 0dB for avoiding the
4790 * possible damage by overloading
4791 */
4792 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4793 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4794 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4795 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4796 (1 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwaic5059252008-02-16 09:43:56 +01004797 break;
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004798 case AD1884A_MOBILE:
4799 spec->mixers[0] = ad1884a_mobile_mixers;
Takashi Iwai73156132009-04-23 08:24:48 +02004800 spec->init_verbs[0] = ad1884a_mobile_verbs;
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004801 spec->multiout.dig_out_nid = 0;
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004802 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4803 codec->patch_ops.init = ad1884a_hp_init;
Takashi Iwai13c989b2009-02-23 11:33:34 +01004804 /* set the upper-limit for mixer amp to 0dB for avoiding the
4805 * possible damage by overloading
4806 */
4807 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4808 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4809 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4810 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4811 (1 << AC_AMPCAP_MUTE_SHIFT));
Takashi Iwaib40b04a2008-02-16 09:44:56 +01004812 break;
Takashi Iwaif0813742008-03-18 12:13:03 +01004813 case AD1884A_THINKPAD:
4814 spec->mixers[0] = ad1984a_thinkpad_mixers;
4815 spec->init_verbs[spec->num_init_verbs++] =
4816 ad1984a_thinkpad_verbs;
4817 spec->multiout.dig_out_nid = 0;
4818 spec->input_mux = &ad1984a_thinkpad_capture_source;
4819 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4820 codec->patch_ops.init = ad1984a_thinkpad_init;
4821 break;
David Henningsson677cd902011-02-07 15:19:34 +01004822 case AD1984A_PRECISION:
4823 spec->mixers[0] = ad1984a_precision_mixers;
4824 spec->init_verbs[spec->num_init_verbs++] =
4825 ad1984a_precision_verbs;
4826 spec->multiout.dig_out_nid = 0;
4827 codec->patch_ops.unsol_event = ad1984a_precision_unsol_event;
4828 codec->patch_ops.init = ad1984a_precision_init;
4829 break;
Miguel de Barrosa72cb4b2009-09-27 22:11:21 +02004830 case AD1984A_TOUCHSMART:
4831 spec->mixers[0] = ad1984a_touchsmart_mixers;
4832 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4833 spec->multiout.dig_out_nid = 0;
4834 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4835 codec->patch_ops.init = ad1984a_touchsmart_init;
4836 /* set the upper-limit for mixer amp to 0dB for avoiding the
4837 * possible damage by overloading
4838 */
4839 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4840 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4841 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4842 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4843 (1 << AC_AMPCAP_MUTE_SHIFT));
4844 break;
Takashi Iwaic5059252008-02-16 09:43:56 +01004845 }
4846
Takashi Iwai729d55b2009-12-25 22:49:01 +01004847 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02004848 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01004849
Takashi Iwaic5059252008-02-16 09:43:56 +01004850 return 0;
4851}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01004852#else /* ENABLE_AD_STATIC_QUIRKS */
4853#define patch_ad1884a ad1884_parse_auto_config
4854#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwaic5059252008-02-16 09:43:56 +01004855
4856
4857/*
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004858 * AD1882 / AD1882A
Takashi Iwai0ac85512007-06-20 15:46:13 +02004859 *
4860 * port-A - front hp-out
4861 * port-B - front mic-in
4862 * port-C - rear line-in, shared surr-out (3stack)
4863 * port-D - rear line-out
4864 * port-E - rear mic-in, shared clfe-out (3stack)
4865 * port-F - rear surr-out (6stack)
4866 * port-G - rear clfe-out (6stack)
4867 */
4868
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01004869#ifdef ENABLE_AD_STATIC_QUIRKS
Takashi Iwai498f5b12011-05-02 11:33:15 +02004870static const hda_nid_t ad1882_dac_nids[3] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02004871 0x04, 0x03, 0x05
4872};
4873
Takashi Iwai498f5b12011-05-02 11:33:15 +02004874static const hda_nid_t ad1882_adc_nids[2] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02004875 0x08, 0x09,
4876};
4877
Takashi Iwai498f5b12011-05-02 11:33:15 +02004878static const hda_nid_t ad1882_capsrc_nids[2] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02004879 0x0c, 0x0d,
4880};
4881
4882#define AD1882_SPDIF_OUT 0x02
4883
4884/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02004885static const struct hda_input_mux ad1882_capture_source = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02004886 .num_items = 5,
4887 .items = {
4888 { "Front Mic", 0x1 },
4889 { "Mic", 0x4 },
4890 { "Line", 0x2 },
4891 { "CD", 0x3 },
4892 { "Mix", 0x7 },
4893 },
4894};
4895
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004896/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02004897static const struct hda_input_mux ad1882a_capture_source = {
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004898 .num_items = 5,
4899 .items = {
4900 { "Front Mic", 0x1 },
4901 { "Mic", 0x4},
4902 { "Line", 0x2 },
4903 { "Digital Mic", 0x06 },
4904 { "Mix", 0x7 },
4905 },
4906};
4907
Takashi Iwai498f5b12011-05-02 11:33:15 +02004908static const struct snd_kcontrol_new ad1882_base_mixers[] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02004909 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4910 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4911 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4912 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4913 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4914 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4915 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4916 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004917
David Henningsson5f99f862011-01-04 15:24:24 +01004918 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
4919 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
4920 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
Takashi Iwai0ac85512007-06-20 15:46:13 +02004921 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4922 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4923 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4924 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4925 {
4926 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4927 /* The multiple "Capture Source" controls confuse alsamixer
4928 * So call somewhat different..
Takashi Iwai0ac85512007-06-20 15:46:13 +02004929 */
4930 /* .name = "Capture Source", */
4931 .name = "Input Source",
4932 .count = 2,
4933 .info = ad198x_mux_enum_info,
4934 .get = ad198x_mux_enum_get,
4935 .put = ad198x_mux_enum_put,
4936 },
4937 /* SPDIF controls */
4938 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4939 {
4940 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4941 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4942 /* identical with ad1983 */
4943 .info = ad1983_spdif_route_info,
4944 .get = ad1983_spdif_route_get,
4945 .put = ad1983_spdif_route_put,
4946 },
4947 { } /* end */
4948};
4949
Takashi Iwai498f5b12011-05-02 11:33:15 +02004950static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004951 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4952 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4953 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4954 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4955 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4956 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4957 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4958 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004959 { } /* end */
4960};
4961
Takashi Iwai498f5b12011-05-02 11:33:15 +02004962static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004963 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4964 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4965 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4966 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4967 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4968 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4969 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4970 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
David Henningsson5f99f862011-01-04 15:24:24 +01004971 HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02004972 { } /* end */
4973};
4974
Takashi Iwai498f5b12011-05-02 11:33:15 +02004975static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02004976 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4977 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4978 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4979 {
4980 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4981 .name = "Channel Mode",
4982 .info = ad198x_ch_mode_info,
4983 .get = ad198x_ch_mode_get,
4984 .put = ad198x_ch_mode_put,
4985 },
4986 { } /* end */
4987};
4988
Takashi Iwai1c8684522012-08-13 11:09:35 +02004989/* simple auto-mute control for AD1882 3-stack board */
4990#define AD1882_HP_EVENT 0x01
4991
4992static void ad1882_3stack_automute(struct hda_codec *codec)
4993{
4994 bool mute = snd_hda_jack_detect(codec, 0x11);
4995 snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4996 mute ? 0 : PIN_OUT);
4997}
4998
4999static int ad1882_3stack_automute_init(struct hda_codec *codec)
5000{
5001 ad198x_init(codec);
5002 ad1882_3stack_automute(codec);
5003 return 0;
5004}
5005
5006static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
5007{
5008 switch (res >> 26) {
5009 case AD1882_HP_EVENT:
5010 ad1882_3stack_automute(codec);
5011 break;
5012 }
5013}
5014
Takashi Iwai498f5b12011-05-02 11:33:15 +02005015static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02005016 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
5017 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
5018 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
5019 { } /* end */
5020};
5021
Takashi Iwai498f5b12011-05-02 11:33:15 +02005022static const struct hda_verb ad1882_ch2_init[] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02005023 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5024 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5025 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5026 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5027 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5028 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5029 { } /* end */
5030};
5031
Takashi Iwai498f5b12011-05-02 11:33:15 +02005032static const struct hda_verb ad1882_ch4_init[] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02005033 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5034 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5035 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5036 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5037 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5038 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5039 { } /* end */
5040};
5041
Takashi Iwai498f5b12011-05-02 11:33:15 +02005042static const struct hda_verb ad1882_ch6_init[] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02005043 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5044 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5045 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5046 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5047 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5048 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5049 { } /* end */
5050};
5051
Takashi Iwai498f5b12011-05-02 11:33:15 +02005052static const struct hda_channel_mode ad1882_modes[3] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02005053 { 2, ad1882_ch2_init },
5054 { 4, ad1882_ch4_init },
5055 { 6, ad1882_ch6_init },
5056};
5057
5058/*
5059 * initialization verbs
5060 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02005061static const struct hda_verb ad1882_init_verbs[] = {
Takashi Iwai0ac85512007-06-20 15:46:13 +02005062 /* DACs; mute as default */
5063 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5064 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5065 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
5066 /* Port-A (HP) mixer */
5067 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5068 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5069 /* Port-A pin */
5070 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5071 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5072 /* HP selector - select DAC2 */
5073 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
5074 /* Port-D (Line-out) mixer */
5075 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5076 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5077 /* Port-D pin */
5078 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5079 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5080 /* Mono-out mixer */
5081 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
5082 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
5083 /* Mono-out pin */
5084 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
5085 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5086 /* Port-B (front mic) pin */
5087 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5088 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5089 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
5090 /* Port-C (line-in) pin */
5091 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
5092 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5093 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
5094 /* Port-C mixer - mute as input */
5095 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5096 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5097 /* Port-E (mic-in) pin */
5098 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
5099 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5100 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
5101 /* Port-E mixer - mute as input */
5102 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5103 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5104 /* Port-F (surround) */
5105 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5106 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5107 /* Port-G (CLFE) */
5108 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
5109 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
5110 /* Analog mixer; mute as default */
5111 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
5112 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
5113 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
5114 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
5115 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
5116 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
5117 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
5118 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
5119 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
5120 /* Analog Mix output amp */
5121 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
5122 /* SPDIF output selector */
5123 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
5124 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
5125 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
5126 { } /* end */
5127};
5128
Takashi Iwai1c8684522012-08-13 11:09:35 +02005129static const struct hda_verb ad1882_3stack_automute_verbs[] = {
5130 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
5131 { } /* end */
5132};
5133
Takashi Iwai83012a72012-08-24 18:38:08 +02005134#ifdef CONFIG_PM
Takashi Iwai498f5b12011-05-02 11:33:15 +02005135static const struct hda_amp_list ad1882_loopbacks[] = {
Takashi Iwaicb53c622007-08-10 17:21:45 +02005136 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
5137 { 0x20, HDA_INPUT, 1 }, /* Mic */
5138 { 0x20, HDA_INPUT, 4 }, /* Line */
5139 { 0x20, HDA_INPUT, 6 }, /* CD */
5140 { } /* end */
5141};
5142#endif
5143
Takashi Iwai0ac85512007-06-20 15:46:13 +02005144/* models */
5145enum {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01005146 AD1882_AUTO,
Takashi Iwai0ac85512007-06-20 15:46:13 +02005147 AD1882_3STACK,
5148 AD1882_6STACK,
Takashi Iwai1c8684522012-08-13 11:09:35 +02005149 AD1882_3STACK_AUTOMUTE,
Takashi Iwai0ac85512007-06-20 15:46:13 +02005150 AD1882_MODELS
5151};
5152
Takashi Iwaiea734962011-01-17 11:29:34 +01005153static const char * const ad1882_models[AD1986A_MODELS] = {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01005154 [AD1882_AUTO] = "auto",
Takashi Iwai0ac85512007-06-20 15:46:13 +02005155 [AD1882_3STACK] = "3stack",
5156 [AD1882_6STACK] = "6stack",
Takashi Iwai1c8684522012-08-13 11:09:35 +02005157 [AD1882_3STACK_AUTOMUTE] = "3stack-automute",
Takashi Iwai0ac85512007-06-20 15:46:13 +02005158};
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01005159#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai0ac85512007-06-20 15:46:13 +02005160
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01005161static int ad1882_parse_auto_config(struct hda_codec *codec)
5162{
Takashi Iwai0ac85512007-06-20 15:46:13 +02005163 struct ad198x_spec *spec;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01005164 int err;
Takashi Iwai0ac85512007-06-20 15:46:13 +02005165
Takashi Iwai361dab32012-05-09 14:35:27 +02005166 err = alloc_ad_spec(codec);
5167 if (err < 0)
5168 return err;
5169 spec = codec->spec;
Takashi Iwai0ac85512007-06-20 15:46:13 +02005170
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01005171 spec->gen.mixer_nid = 0x20;
Takashi Iwaie4a395e2013-01-23 17:00:31 +01005172 spec->gen.mixer_merge_nid = 0x21;
Takashi Iwai7504b6c2013-03-18 11:25:51 +01005173 spec->gen.beep_nid = 0x10;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01005174 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
5175 err = ad198x_parse_auto_config(codec);
5176 if (err < 0)
5177 goto error;
5178 err = ad1988_add_spdif_mux_ctl(codec);
5179 if (err < 0)
5180 goto error;
5181 return 0;
5182
5183 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +01005184 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01005185 return err;
5186}
5187
5188#ifdef ENABLE_AD_STATIC_QUIRKS
5189static int patch_ad1882(struct hda_codec *codec)
5190{
5191 struct ad198x_spec *spec;
5192 int err, board_config;
5193
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01005194 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
5195 ad1882_models, NULL);
Takashi Iwai657e1b92013-01-22 18:42:39 +01005196 if (board_config < 0) {
5197 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
5198 codec->chip_name);
5199 board_config = AD1882_AUTO;
5200 }
5201
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01005202 if (board_config == AD1882_AUTO)
5203 return ad1882_parse_auto_config(codec);
5204
5205 err = alloc_ad_spec(codec);
5206 if (err < 0)
5207 return err;
5208 spec = codec->spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01005209
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +01005210 err = snd_hda_attach_beep_device(codec, 0x10);
5211 if (err < 0) {
5212 ad198x_free(codec);
5213 return err;
5214 }
5215 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
5216
Takashi Iwai0ac85512007-06-20 15:46:13 +02005217 spec->multiout.max_channels = 6;
5218 spec->multiout.num_dacs = 3;
5219 spec->multiout.dac_nids = ad1882_dac_nids;
5220 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
5221 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
5222 spec->adc_nids = ad1882_adc_nids;
5223 spec->capsrc_nids = ad1882_capsrc_nids;
Clemens Fruhwirthc247ed62009-01-07 11:43:48 +01005224 if (codec->vendor_id == 0x11d41882)
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02005225 spec->input_mux = &ad1882_capture_source;
5226 else
5227 spec->input_mux = &ad1882a_capture_source;
5228 spec->num_mixers = 2;
Takashi Iwai0ac85512007-06-20 15:46:13 +02005229 spec->mixers[0] = ad1882_base_mixers;
Clemens Fruhwirthc247ed62009-01-07 11:43:48 +01005230 if (codec->vendor_id == 0x11d41882)
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02005231 spec->mixers[1] = ad1882_loopback_mixers;
5232 else
5233 spec->mixers[1] = ad1882a_loopback_mixers;
Takashi Iwai0ac85512007-06-20 15:46:13 +02005234 spec->num_init_verbs = 1;
5235 spec->init_verbs[0] = ad1882_init_verbs;
5236 spec->spdif_route = 0;
Takashi Iwai83012a72012-08-24 18:38:08 +02005237#ifdef CONFIG_PM
Takashi Iwaicb53c622007-08-10 17:21:45 +02005238 spec->loopback.amplist = ad1882_loopbacks;
5239#endif
Takashi Iwai2134ea42008-01-10 16:53:55 +01005240 spec->vmaster_nid = 0x04;
Takashi Iwai0ac85512007-06-20 15:46:13 +02005241
5242 codec->patch_ops = ad198x_patch_ops;
5243
5244 /* override some parameters */
Takashi Iwai0ac85512007-06-20 15:46:13 +02005245 switch (board_config) {
5246 default:
5247 case AD1882_3STACK:
Takashi Iwai1c8684522012-08-13 11:09:35 +02005248 case AD1882_3STACK_AUTOMUTE:
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02005249 spec->num_mixers = 3;
5250 spec->mixers[2] = ad1882_3stack_mixers;
Takashi Iwai0ac85512007-06-20 15:46:13 +02005251 spec->channel_mode = ad1882_modes;
5252 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
5253 spec->need_dac_fix = 1;
5254 spec->multiout.max_channels = 2;
5255 spec->multiout.num_dacs = 1;
Takashi Iwai1c8684522012-08-13 11:09:35 +02005256 if (board_config != AD1882_3STACK) {
5257 spec->init_verbs[spec->num_init_verbs++] =
5258 ad1882_3stack_automute_verbs;
5259 codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
5260 codec->patch_ops.init = ad1882_3stack_automute_init;
5261 }
Takashi Iwai0ac85512007-06-20 15:46:13 +02005262 break;
5263 case AD1882_6STACK:
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02005264 spec->num_mixers = 3;
5265 spec->mixers[2] = ad1882_6stack_mixers;
Takashi Iwai0ac85512007-06-20 15:46:13 +02005266 break;
5267 }
Takashi Iwai729d55b2009-12-25 22:49:01 +01005268
5269 codec->no_trigger_sense = 1;
Takashi Iwai0e7adbe2010-10-25 10:37:11 +02005270 codec->no_sticky_stream = 1;
Takashi Iwai729d55b2009-12-25 22:49:01 +01005271
Takashi Iwai0ac85512007-06-20 15:46:13 +02005272 return 0;
5273}
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01005274#else /* ENABLE_AD_STATIC_QUIRKS */
5275#define patch_ad1882 ad1882_parse_auto_config
5276#endif /* ENABLE_AD_STATIC_QUIRKS */
Takashi Iwai0ac85512007-06-20 15:46:13 +02005277
5278
5279/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07005280 * patch entries
5281 */
Takashi Iwai498f5b12011-05-02 11:33:15 +02005282static const struct hda_codec_preset snd_hda_preset_analog[] = {
Takashi Iwaic5059252008-02-16 09:43:56 +01005283 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
Takashi Iwai0ac85512007-06-20 15:46:13 +02005284 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
Takashi Iwaic5059252008-02-16 09:43:56 +01005285 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
Takashi Iwai2bac6472007-05-18 18:21:41 +02005286 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
Takashi Iwaic5059252008-02-16 09:43:56 +01005287 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
5288 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
Takashi Iwai4a3fdf32005-04-14 13:35:51 +02005289 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
5290 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
Takashi Iwai2bac6472007-05-18 18:21:41 +02005291 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07005292 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
Takashi Iwaifd66e0d2005-11-17 15:31:34 +01005293 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
Takashi Iwai71b2ccc2006-04-21 16:09:31 +02005294 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02005295 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
Takashi Iwai3adb8ab2008-04-15 18:46:42 +02005296 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
5297 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
Linus Torvalds1da177e2005-04-16 15:20:36 -07005298 {} /* terminator */
5299};
Takashi Iwai1289e9e2008-11-27 15:47:11 +01005300
5301MODULE_ALIAS("snd-hda-codec-id:11d4*");
5302
5303MODULE_LICENSE("GPL");
5304MODULE_DESCRIPTION("Analog Devices HD-audio codec");
5305
5306static struct hda_codec_preset_list analog_list = {
5307 .preset = snd_hda_preset_analog,
5308 .owner = THIS_MODULE,
5309};
5310
5311static int __init patch_analog_init(void)
5312{
5313 return snd_hda_add_codec_preset(&analog_list);
5314}
5315
5316static void __exit patch_analog_exit(void)
5317{
5318 snd_hda_delete_codec_preset(&analog_list);
5319}
5320
5321module_init(patch_analog_init)
5322module_exit(patch_analog_exit)