2 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
5 * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
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.
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.
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
22 #include <linux/init.h>
23 #include <linux/slab.h>
24 #include <linux/pci.h>
25 #include <linux/module.h>
27 #include <sound/core.h>
28 #include "hda_codec.h"
29 #include "hda_local.h"
30 #include "hda_auto_parser.h"
33 #include "hda_generic.h"
36 struct hda_gen_spec gen;
40 unsigned int cur_smux;
42 const struct snd_kcontrol_new *mixers[6];
44 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
45 hda_nid_t beep_dev_nid;
46 const struct hda_verb *init_verbs[6]; /* initialization verbs
47 * don't forget NULL termination!
49 unsigned int num_init_verbs;
52 struct hda_multi_out multiout; /* playback set-up
53 * max_channels, dacs must be set
54 * dig_out_nid and hp_nid are optional
56 unsigned int cur_eapd;
57 unsigned int need_dac_fix;
60 unsigned int num_adc_nids;
61 const hda_nid_t *adc_nids;
62 hda_nid_t dig_in_nid; /* digital-in NID; optional */
65 const struct hda_input_mux *input_mux;
66 const hda_nid_t *capsrc_nids;
67 unsigned int cur_mux[3];
70 const struct hda_channel_mode *channel_mode;
74 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
76 unsigned int spdif_route;
78 unsigned int jack_present: 1;
79 unsigned int inv_jack_detect: 1;/* inverted jack-detection */
80 unsigned int analog_beep: 1; /* analog beep input present */
81 unsigned int avoid_init_slave_vol:1;
84 struct hda_loopback_check loopback;
86 /* for virtual master */
87 hda_nid_t vmaster_nid;
88 const char * const *slave_vols;
89 const char * const *slave_sws;
93 * input MUX handling (common part)
95 static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
97 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
98 struct ad198x_spec *spec = codec->spec;
100 return snd_hda_input_mux_info(spec->input_mux, uinfo);
103 static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
105 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
106 struct ad198x_spec *spec = codec->spec;
107 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
109 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
113 static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
115 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
116 struct ad198x_spec *spec = codec->spec;
117 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
119 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
120 spec->capsrc_nids[adc_idx],
121 &spec->cur_mux[adc_idx]);
125 * initialization (common callbacks)
127 static int ad198x_init(struct hda_codec *codec)
129 struct ad198x_spec *spec = codec->spec;
132 for (i = 0; i < spec->num_init_verbs; i++)
133 snd_hda_sequence_write(codec, spec->init_verbs[i]);
137 static const char * const ad_slave_pfxs[] = {
138 "Front", "Surround", "Center", "LFE", "Side",
139 "Headphone", "Mono", "Speaker", "IEC958",
143 static const char * const ad1988_6stack_fp_slave_pfxs[] = {
144 "Front", "Surround", "Center", "LFE", "Side", "IEC958",
148 #ifdef CONFIG_SND_HDA_INPUT_BEEP
149 /* additional beep mixers; the actual parameters are overwritten at build */
150 static const struct snd_kcontrol_new ad_beep_mixer[] = {
151 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
152 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
156 static const struct snd_kcontrol_new ad_beep2_mixer[] = {
157 HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
158 HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
162 #define set_beep_amp(spec, nid, idx, dir) \
163 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
165 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
168 #ifdef CONFIG_SND_HDA_INPUT_BEEP
169 static int create_beep_ctls(struct hda_codec *codec)
171 struct ad198x_spec *spec = codec->spec;
172 const struct snd_kcontrol_new *knew;
177 knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
178 for ( ; knew->name; knew++) {
180 struct snd_kcontrol *kctl;
181 kctl = snd_ctl_new1(knew, codec);
184 kctl->private_value = spec->beep_amp;
185 err = snd_hda_ctl_add(codec, 0, kctl);
192 #define create_beep_ctls(codec) 0
195 static int ad198x_build_controls(struct hda_codec *codec)
197 struct ad198x_spec *spec = codec->spec;
198 struct snd_kcontrol *kctl;
202 for (i = 0; i < spec->num_mixers; i++) {
203 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
207 if (spec->multiout.dig_out_nid) {
208 err = snd_hda_create_spdif_out_ctls(codec,
209 spec->multiout.dig_out_nid,
210 spec->multiout.dig_out_nid);
213 err = snd_hda_create_spdif_share_sw(codec,
217 spec->multiout.share_spdif = 1;
219 if (spec->dig_in_nid) {
220 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
225 /* create beep controls if needed */
226 err = create_beep_ctls(codec);
230 /* if we have no master control, let's create it */
231 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
232 unsigned int vmaster_tlv[4];
233 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
234 HDA_OUTPUT, vmaster_tlv);
235 err = __snd_hda_add_vmaster(codec, "Master Playback Volume",
238 spec->slave_vols : ad_slave_pfxs),
240 !spec->avoid_init_slave_vol, NULL);
244 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
245 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
248 spec->slave_sws : ad_slave_pfxs),
254 /* assign Capture Source enums to NID */
255 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
257 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
258 for (i = 0; kctl && i < kctl->count; i++) {
259 err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
264 /* assign IEC958 enums to NID */
265 kctl = snd_hda_find_mixer_ctl(codec,
266 SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
268 err = snd_hda_add_nid(codec, kctl, 0,
269 spec->multiout.dig_out_nid);
278 static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
280 struct ad198x_spec *spec = codec->spec;
281 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
286 * Analog playback callbacks
288 static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
289 struct hda_codec *codec,
290 struct snd_pcm_substream *substream)
292 struct ad198x_spec *spec = codec->spec;
293 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
297 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
298 struct hda_codec *codec,
299 unsigned int stream_tag,
301 struct snd_pcm_substream *substream)
303 struct ad198x_spec *spec = codec->spec;
304 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
308 static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
309 struct hda_codec *codec,
310 struct snd_pcm_substream *substream)
312 struct ad198x_spec *spec = codec->spec;
313 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
319 static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
320 struct hda_codec *codec,
321 struct snd_pcm_substream *substream)
323 struct ad198x_spec *spec = codec->spec;
324 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
327 static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
328 struct hda_codec *codec,
329 struct snd_pcm_substream *substream)
331 struct ad198x_spec *spec = codec->spec;
332 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
335 static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
336 struct hda_codec *codec,
337 unsigned int stream_tag,
339 struct snd_pcm_substream *substream)
341 struct ad198x_spec *spec = codec->spec;
342 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
346 static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
347 struct hda_codec *codec,
348 struct snd_pcm_substream *substream)
350 struct ad198x_spec *spec = codec->spec;
351 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
357 static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
358 struct hda_codec *codec,
359 unsigned int stream_tag,
361 struct snd_pcm_substream *substream)
363 struct ad198x_spec *spec = codec->spec;
364 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
365 stream_tag, 0, format);
369 static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
370 struct hda_codec *codec,
371 struct snd_pcm_substream *substream)
373 struct ad198x_spec *spec = codec->spec;
374 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
380 static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
383 .channels_max = 6, /* changed later */
384 .nid = 0, /* fill later */
386 .open = ad198x_playback_pcm_open,
387 .prepare = ad198x_playback_pcm_prepare,
388 .cleanup = ad198x_playback_pcm_cleanup,
392 static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
396 .nid = 0, /* fill later */
398 .prepare = ad198x_capture_pcm_prepare,
399 .cleanup = ad198x_capture_pcm_cleanup
403 static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
407 .nid = 0, /* fill later */
409 .open = ad198x_dig_playback_pcm_open,
410 .close = ad198x_dig_playback_pcm_close,
411 .prepare = ad198x_dig_playback_pcm_prepare,
412 .cleanup = ad198x_dig_playback_pcm_cleanup
416 static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
420 /* NID is set in alc_build_pcms */
423 static int ad198x_build_pcms(struct hda_codec *codec)
425 struct ad198x_spec *spec = codec->spec;
426 struct hda_pcm *info = spec->pcm_rec;
429 codec->pcm_info = info;
431 info->name = "AD198x Analog";
432 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
433 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
434 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
435 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
436 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
437 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
439 if (spec->multiout.dig_out_nid) {
442 codec->spdif_status_reset = 1;
443 info->name = "AD198x Digital";
444 info->pcm_type = HDA_PCM_TYPE_SPDIF;
445 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
446 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
447 if (spec->dig_in_nid) {
448 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
449 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
456 static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
459 if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
460 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
461 !codec->inv_eapd ? 0x00 : 0x02);
462 if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
463 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
464 !codec->inv_eapd ? 0x00 : 0x02);
467 static void ad198x_power_eapd(struct hda_codec *codec)
469 /* We currently only handle front, HP */
470 switch (codec->vendor_id) {
483 ad198x_power_eapd_write(codec, 0x12, 0x11);
487 ad198x_power_eapd_write(codec, 0x05, 0x06);
490 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
495 static void ad198x_shutup(struct hda_codec *codec)
497 snd_hda_shutup_pins(codec);
498 ad198x_power_eapd(codec);
501 static void ad198x_free(struct hda_codec *codec)
503 struct ad198x_spec *spec = codec->spec;
508 snd_hda_gen_spec_free(&spec->gen);
510 snd_hda_detach_beep_device(codec);
514 static int ad198x_suspend(struct hda_codec *codec)
516 ad198x_shutup(codec);
521 static const struct hda_codec_ops ad198x_patch_ops = {
522 .build_controls = ad198x_build_controls,
523 .build_pcms = ad198x_build_pcms,
527 .check_power_status = ad198x_check_power_status,
528 .suspend = ad198x_suspend,
530 .reboot_notify = ad198x_shutup,
536 * the private value = nid
538 #define ad198x_eapd_info snd_ctl_boolean_mono_info
540 static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
541 struct snd_ctl_elem_value *ucontrol)
543 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
544 struct ad198x_spec *spec = codec->spec;
546 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
548 ucontrol->value.integer.value[0] = spec->cur_eapd;
552 static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
553 struct snd_ctl_elem_value *ucontrol)
555 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
556 struct ad198x_spec *spec = codec->spec;
557 hda_nid_t nid = kcontrol->private_value & 0xff;
559 eapd = !!ucontrol->value.integer.value[0];
562 if (eapd == spec->cur_eapd)
564 spec->cur_eapd = eapd;
565 snd_hda_codec_write_cache(codec, nid,
566 0, AC_VERB_SET_EAPD_BTLENABLE,
571 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
572 struct snd_ctl_elem_info *uinfo);
573 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
574 struct snd_ctl_elem_value *ucontrol);
575 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
576 struct snd_ctl_elem_value *ucontrol);
580 * Automatic parse of I/O pins from the BIOS configuration
583 static int ad198x_auto_build_controls(struct hda_codec *codec)
587 err = snd_hda_gen_build_controls(codec);
590 err = create_beep_ctls(codec);
596 static const struct hda_codec_ops ad198x_auto_patch_ops = {
597 .build_controls = ad198x_auto_build_controls,
598 .build_pcms = snd_hda_gen_build_pcms,
599 .init = snd_hda_gen_init,
601 .unsol_event = snd_hda_jack_unsol_event,
603 .check_power_status = snd_hda_gen_check_power_status,
604 .suspend = ad198x_suspend,
606 .reboot_notify = ad198x_shutup,
610 static int ad198x_parse_auto_config(struct hda_codec *codec)
612 struct ad198x_spec *spec = codec->spec;
613 struct auto_pin_cfg *cfg = &spec->gen.autocfg;
616 codec->spdif_status_reset = 1;
617 codec->no_trigger_sense = 1;
618 codec->no_sticky_stream = 1;
620 spec->gen.indep_hp = 1;
622 err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
625 err = snd_hda_gen_parse_auto_config(codec, cfg);
629 if (spec->beep_dev_nid) {
630 err = snd_hda_attach_beep_device(codec, spec->beep_dev_nid);
635 codec->patch_ops = ad198x_auto_patch_ops;
644 #define AD1986A_SPDIF_OUT 0x02
645 #define AD1986A_FRONT_DAC 0x03
646 #define AD1986A_SURR_DAC 0x04
647 #define AD1986A_CLFE_DAC 0x05
648 #define AD1986A_ADC 0x06
650 static const hda_nid_t ad1986a_dac_nids[3] = {
651 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
653 static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
654 static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
656 static const struct hda_input_mux ad1986a_capture_source = {
670 static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
671 .ops = &snd_hda_bind_vol,
673 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
674 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
675 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
680 static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
681 .ops = &snd_hda_bind_sw,
683 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
684 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
685 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
693 static const struct snd_kcontrol_new ad1986a_mixers[] = {
695 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
697 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
698 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
699 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
700 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
701 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
702 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
703 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
704 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
705 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
706 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
707 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
708 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
709 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
710 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
711 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
712 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
713 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
714 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
715 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
716 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
717 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
718 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
719 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
720 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
721 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
723 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
724 .name = "Capture Source",
725 .info = ad198x_mux_enum_info,
726 .get = ad198x_mux_enum_get,
727 .put = ad198x_mux_enum_put,
729 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
733 /* additional mixers for 3stack mode */
734 static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
736 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
737 .name = "Channel Mode",
738 .info = ad198x_ch_mode_info,
739 .get = ad198x_ch_mode_get,
740 .put = ad198x_ch_mode_put,
745 /* laptop model - 2ch only */
746 static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
748 /* master controls both pins 0x1a and 0x1b */
749 static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
750 .ops = &snd_hda_bind_vol,
752 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
753 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
758 static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
759 .ops = &snd_hda_bind_sw,
761 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
762 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
767 static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
768 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
769 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
770 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
771 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
772 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
773 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
774 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
775 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
776 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
777 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
778 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
779 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
780 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
782 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
783 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
784 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
785 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
787 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
788 .name = "Capture Source",
789 .info = ad198x_mux_enum_info,
790 .get = ad198x_mux_enum_get,
791 .put = ad198x_mux_enum_put,
796 /* laptop-eapd model - 2ch only */
798 static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
802 { "Internal Mic", 0x4 },
807 static const struct hda_input_mux ad1986a_automic_capture_source = {
815 static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
816 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
817 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
821 static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
822 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
823 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
824 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
825 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
826 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
827 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
828 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
830 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
831 .name = "Capture Source",
832 .info = ad198x_mux_enum_info,
833 .get = ad198x_mux_enum_get,
834 .put = ad198x_mux_enum_put,
837 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
838 .name = "External Amplifier",
839 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
840 .info = ad198x_eapd_info,
841 .get = ad198x_eapd_get,
842 .put = ad198x_eapd_put,
843 .private_value = 0x1b, /* port-D */
848 static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
849 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
850 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
854 /* re-connect the mic boost input according to the jack sensing */
855 static void ad1986a_automic(struct hda_codec *codec)
857 unsigned int present;
858 present = snd_hda_jack_detect(codec, 0x1f);
859 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
860 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
864 #define AD1986A_MIC_EVENT 0x36
866 static void ad1986a_automic_unsol_event(struct hda_codec *codec,
869 if ((res >> 26) != AD1986A_MIC_EVENT)
871 ad1986a_automic(codec);
874 static int ad1986a_automic_init(struct hda_codec *codec)
877 ad1986a_automic(codec);
881 /* laptop-automute - 2ch only */
883 static void ad1986a_update_hp(struct hda_codec *codec)
885 struct ad198x_spec *spec = codec->spec;
888 if (spec->jack_present)
889 mute = HDA_AMP_MUTE; /* mute internal speaker */
891 /* unmute internal speaker if necessary */
892 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
893 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
897 static void ad1986a_hp_automute(struct hda_codec *codec)
899 struct ad198x_spec *spec = codec->spec;
901 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
902 if (spec->inv_jack_detect)
903 spec->jack_present = !spec->jack_present;
904 ad1986a_update_hp(codec);
907 #define AD1986A_HP_EVENT 0x37
909 static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
911 if ((res >> 26) != AD1986A_HP_EVENT)
913 ad1986a_hp_automute(codec);
916 static int ad1986a_hp_init(struct hda_codec *codec)
919 ad1986a_hp_automute(codec);
923 /* bind hp and internal speaker mute (with plug check) */
924 static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
925 struct snd_ctl_elem_value *ucontrol)
927 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
928 int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
930 ad1986a_update_hp(codec);
934 static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
935 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
937 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
938 .name = "Master Playback Switch",
939 .subdevice = HDA_SUBDEV_AMP_FLAG,
940 .info = snd_hda_mixer_amp_switch_info,
941 .get = snd_hda_mixer_amp_switch_get,
942 .put = ad1986a_hp_master_sw_put,
943 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
950 * initialization verbs
952 static const struct hda_verb ad1986a_init_verbs[] = {
953 /* Front, Surround, CLFE DAC; mute as default */
954 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
955 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
956 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
958 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
959 /* HP, Line-Out, Surround, CLFE selectors */
960 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
961 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
962 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
963 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
965 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
966 /* Mic selector: Mic 1/2 pin */
967 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
968 /* Line-in selector: Line-in */
969 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
971 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
972 /* Record selector: mic */
973 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
974 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
975 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
976 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
977 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
978 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
979 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
981 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
982 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
983 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
984 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
985 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
986 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
987 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
989 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
990 /* Front, Surround, CLFE Pins */
991 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
992 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
993 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
995 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
997 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
998 /* Line, Aux, CD, Beep-In Pin */
999 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1000 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1001 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1002 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1003 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1007 static const struct hda_verb ad1986a_ch2_init[] = {
1008 /* Surround out -> Line In */
1009 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1010 /* Line-in selectors */
1011 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
1012 /* CLFE -> Mic in */
1013 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1014 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
1015 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1019 static const struct hda_verb ad1986a_ch4_init[] = {
1020 /* Surround out -> Surround */
1021 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1022 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1023 /* CLFE -> Mic in */
1024 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1025 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1029 static const struct hda_verb ad1986a_ch6_init[] = {
1030 /* Surround out -> Surround out */
1031 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1032 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1034 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1035 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
1039 static const struct hda_channel_mode ad1986a_modes[3] = {
1040 { 2, ad1986a_ch2_init },
1041 { 4, ad1986a_ch4_init },
1042 { 6, ad1986a_ch6_init },
1045 /* eapd initialization */
1046 static const struct hda_verb ad1986a_eapd_init_verbs[] = {
1047 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1051 static const struct hda_verb ad1986a_automic_verbs[] = {
1052 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1053 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1054 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
1055 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1056 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
1060 /* Ultra initialization */
1061 static const struct hda_verb ad1986a_ultra_init[] = {
1062 /* eapd initialization */
1063 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1064 /* CLFE -> Mic in */
1065 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
1066 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1067 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
1071 /* pin sensing on HP jack */
1072 static const struct hda_verb ad1986a_hp_init_verbs[] = {
1073 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1077 static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
1080 switch (res >> 26) {
1081 case AD1986A_HP_EVENT:
1082 ad1986a_hp_automute(codec);
1084 case AD1986A_MIC_EVENT:
1085 ad1986a_automic(codec);
1090 static int ad1986a_samsung_p50_init(struct hda_codec *codec)
1093 ad1986a_hp_automute(codec);
1094 ad1986a_automic(codec);
1105 AD1986A_LAPTOP_EAPD,
1106 AD1986A_LAPTOP_AUTOMUTE,
1109 AD1986A_SAMSUNG_P50,
1113 static const char * const ad1986a_models[AD1986A_MODELS] = {
1114 [AD1986A_AUTO] = "auto",
1115 [AD1986A_6STACK] = "6stack",
1116 [AD1986A_3STACK] = "3stack",
1117 [AD1986A_LAPTOP] = "laptop",
1118 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
1119 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
1120 [AD1986A_ULTRA] = "ultra",
1121 [AD1986A_SAMSUNG] = "samsung",
1122 [AD1986A_SAMSUNG_P50] = "samsung-p50",
1125 static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
1126 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
1127 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
1128 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
1129 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
1130 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
1131 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
1132 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
1133 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
1134 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
1135 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
1136 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1137 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1138 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1139 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1140 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
1141 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
1142 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
1143 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
1144 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
1145 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
1146 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
1147 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
1148 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
1149 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
1150 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
1151 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
1152 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
1157 static const struct hda_amp_list ad1986a_loopbacks[] = {
1158 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1159 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1160 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1161 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1162 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1167 static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1169 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
1170 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1173 static int alloc_ad_spec(struct hda_codec *codec)
1175 struct ad198x_spec *spec;
1177 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1181 snd_hda_gen_spec_init(&spec->gen);
1187 static int ad1986a_parse_auto_config(struct hda_codec *codec)
1189 struct ad198x_spec *spec = codec->spec;
1191 /* AD1986A has the inverted EAPD implementation */
1192 codec->inv_eapd = 1;
1194 spec->gen.mixer_nid = 0x07;
1195 spec->beep_dev_nid = 0x19;
1196 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1198 /* AD1986A has a hardware problem that it can't share a stream
1199 * with multiple output pins. The copy of front to surrounds
1200 * causes noisy or silent outputs at a certain timing, e.g.
1201 * changing the volume.
1202 * So, let's disable the shared stream.
1204 spec->gen.multiout.no_share_stream = 1;
1206 return ad198x_parse_auto_config(codec);
1209 static int patch_ad1986a(struct hda_codec *codec)
1211 struct ad198x_spec *spec;
1212 int err, board_config;
1214 err = alloc_ad_spec(codec);
1219 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1222 if (board_config == AD1986A_AUTO) {
1223 err = ad1986a_parse_auto_config(codec);
1231 err = snd_hda_attach_beep_device(codec, 0x19);
1236 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1238 spec->multiout.max_channels = 6;
1239 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1240 spec->multiout.dac_nids = ad1986a_dac_nids;
1241 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
1242 spec->num_adc_nids = 1;
1243 spec->adc_nids = ad1986a_adc_nids;
1244 spec->capsrc_nids = ad1986a_capsrc_nids;
1245 spec->input_mux = &ad1986a_capture_source;
1246 spec->num_mixers = 1;
1247 spec->mixers[0] = ad1986a_mixers;
1248 spec->num_init_verbs = 1;
1249 spec->init_verbs[0] = ad1986a_init_verbs;
1251 spec->loopback.amplist = ad1986a_loopbacks;
1253 spec->vmaster_nid = 0x1b;
1254 codec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
1256 codec->patch_ops = ad198x_patch_ops;
1258 /* override some parameters */
1259 switch (board_config) {
1260 case AD1986A_3STACK:
1261 spec->num_mixers = 2;
1262 spec->mixers[1] = ad1986a_3st_mixers;
1263 spec->num_init_verbs = 2;
1264 spec->init_verbs[1] = ad1986a_ch2_init;
1265 spec->channel_mode = ad1986a_modes;
1266 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
1267 spec->need_dac_fix = 1;
1268 spec->multiout.max_channels = 2;
1269 spec->multiout.num_dacs = 1;
1271 case AD1986A_LAPTOP:
1272 spec->mixers[0] = ad1986a_laptop_mixers;
1273 spec->multiout.max_channels = 2;
1274 spec->multiout.num_dacs = 1;
1275 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1277 case AD1986A_LAPTOP_EAPD:
1278 spec->num_mixers = 3;
1279 spec->mixers[0] = ad1986a_laptop_master_mixers;
1280 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1281 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1282 spec->num_init_verbs = 2;
1283 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1284 spec->multiout.max_channels = 2;
1285 spec->multiout.num_dacs = 1;
1286 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1287 if (!is_jack_available(codec, 0x25))
1288 spec->multiout.dig_out_nid = 0;
1289 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1291 case AD1986A_SAMSUNG:
1292 spec->num_mixers = 2;
1293 spec->mixers[0] = ad1986a_laptop_master_mixers;
1294 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1295 spec->num_init_verbs = 3;
1296 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1297 spec->init_verbs[2] = ad1986a_automic_verbs;
1298 spec->multiout.max_channels = 2;
1299 spec->multiout.num_dacs = 1;
1300 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1301 if (!is_jack_available(codec, 0x25))
1302 spec->multiout.dig_out_nid = 0;
1303 spec->input_mux = &ad1986a_automic_capture_source;
1304 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1305 codec->patch_ops.init = ad1986a_automic_init;
1307 case AD1986A_SAMSUNG_P50:
1308 spec->num_mixers = 2;
1309 spec->mixers[0] = ad1986a_automute_master_mixers;
1310 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1311 spec->num_init_verbs = 4;
1312 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1313 spec->init_verbs[2] = ad1986a_automic_verbs;
1314 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1315 spec->multiout.max_channels = 2;
1316 spec->multiout.num_dacs = 1;
1317 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1318 if (!is_jack_available(codec, 0x25))
1319 spec->multiout.dig_out_nid = 0;
1320 spec->input_mux = &ad1986a_automic_capture_source;
1321 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1322 codec->patch_ops.init = ad1986a_samsung_p50_init;
1324 case AD1986A_LAPTOP_AUTOMUTE:
1325 spec->num_mixers = 3;
1326 spec->mixers[0] = ad1986a_automute_master_mixers;
1327 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1328 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1329 spec->num_init_verbs = 3;
1330 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1331 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1332 spec->multiout.max_channels = 2;
1333 spec->multiout.num_dacs = 1;
1334 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1335 if (!is_jack_available(codec, 0x25))
1336 spec->multiout.dig_out_nid = 0;
1337 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1338 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1339 codec->patch_ops.init = ad1986a_hp_init;
1340 /* Lenovo N100 seems to report the reversed bit
1341 * for HP jack-sensing
1343 spec->inv_jack_detect = 1;
1346 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1347 spec->num_init_verbs = 2;
1348 spec->init_verbs[1] = ad1986a_ultra_init;
1349 spec->multiout.max_channels = 2;
1350 spec->multiout.num_dacs = 1;
1351 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1352 spec->multiout.dig_out_nid = 0;
1356 /* AD1986A has a hardware problem that it can't share a stream
1357 * with multiple output pins. The copy of front to surrounds
1358 * causes noisy or silent outputs at a certain timing, e.g.
1359 * changing the volume.
1360 * So, let's disable the shared stream.
1362 spec->multiout.no_share_stream = 1;
1364 codec->no_trigger_sense = 1;
1365 codec->no_sticky_stream = 1;
1374 #define AD1983_SPDIF_OUT 0x02
1375 #define AD1983_DAC 0x03
1376 #define AD1983_ADC 0x04
1378 static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
1379 static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
1380 static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
1382 static const struct hda_input_mux ad1983_capture_source = {
1388 { "Mix Mono", 0x3 },
1393 * SPDIF playback route
1395 static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1397 static const char * const texts[] = { "PCM", "ADC" };
1399 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1401 uinfo->value.enumerated.items = 2;
1402 if (uinfo->value.enumerated.item > 1)
1403 uinfo->value.enumerated.item = 1;
1404 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1408 static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1410 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1411 struct ad198x_spec *spec = codec->spec;
1413 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1417 static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1419 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1420 struct ad198x_spec *spec = codec->spec;
1422 if (ucontrol->value.enumerated.item[0] > 1)
1424 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1425 spec->spdif_route = ucontrol->value.enumerated.item[0];
1426 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1427 AC_VERB_SET_CONNECT_SEL,
1434 static const struct snd_kcontrol_new ad1983_mixers[] = {
1435 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1436 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1437 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1438 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1439 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1440 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1441 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1442 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1443 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1444 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1445 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1446 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1447 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
1448 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1449 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1451 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1452 .name = "Capture Source",
1453 .info = ad198x_mux_enum_info,
1454 .get = ad198x_mux_enum_get,
1455 .put = ad198x_mux_enum_put,
1458 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1459 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1460 .info = ad1983_spdif_route_info,
1461 .get = ad1983_spdif_route_get,
1462 .put = ad1983_spdif_route_put,
1467 static const struct hda_verb ad1983_init_verbs[] = {
1468 /* Front, HP, Mono; mute as default */
1469 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1470 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1471 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1472 /* Beep, PCM, Mic, Line-In: mute */
1473 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1474 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1475 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1476 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1477 /* Front, HP selectors; from Mix */
1478 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1479 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1480 /* Mono selector; from Mix */
1481 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1482 /* Mic selector; Mic */
1483 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1484 /* Line-in selector: Line-in */
1485 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1486 /* Mic boost: 0dB */
1487 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1488 /* Record selector: mic */
1489 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1490 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1491 /* SPDIF route: PCM */
1492 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1494 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1496 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1498 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1500 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1502 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1507 static const struct hda_amp_list ad1983_loopbacks[] = {
1508 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
1509 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1521 static const char * const ad1983_models[AD1983_MODELS] = {
1522 [AD1983_AUTO] = "auto",
1523 [AD1983_BASIC] = "basic",
1527 * SPDIF mux control for AD1983 auto-parser
1529 static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
1530 struct snd_ctl_elem_info *uinfo)
1532 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1533 struct ad198x_spec *spec = codec->spec;
1534 static const char * const texts2[] = { "PCM", "ADC" };
1535 static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
1536 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1537 int num_conns = snd_hda_get_num_conns(codec, dig_out);
1540 return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
1541 else if (num_conns == 3)
1542 return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
1547 static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
1548 struct snd_ctl_elem_value *ucontrol)
1550 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1551 struct ad198x_spec *spec = codec->spec;
1553 ucontrol->value.enumerated.item[0] = spec->cur_smux;
1557 static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
1558 struct snd_ctl_elem_value *ucontrol)
1560 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1561 struct ad198x_spec *spec = codec->spec;
1562 unsigned int val = ucontrol->value.enumerated.item[0];
1563 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1564 int num_conns = snd_hda_get_num_conns(codec, dig_out);
1566 if (val >= num_conns)
1568 if (spec->cur_smux == val)
1570 spec->cur_smux = val;
1571 snd_hda_codec_write_cache(codec, dig_out, 0,
1572 AC_VERB_SET_CONNECT_SEL, val);
1576 static struct snd_kcontrol_new ad1983_auto_smux_mixer = {
1577 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1578 .name = "IEC958 Playback Source",
1579 .info = ad1983_auto_smux_enum_info,
1580 .get = ad1983_auto_smux_enum_get,
1581 .put = ad1983_auto_smux_enum_put,
1584 static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
1586 struct ad198x_spec *spec = codec->spec;
1587 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
1592 num_conns = snd_hda_get_num_conns(codec, dig_out);
1593 if (num_conns != 2 && num_conns != 3)
1595 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
1600 static int ad1983_parse_auto_config(struct hda_codec *codec)
1602 struct ad198x_spec *spec = codec->spec;
1605 spec->beep_dev_nid = 0x10;
1606 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1607 err = ad198x_parse_auto_config(codec);
1610 err = ad1983_add_spdif_mux_ctl(codec);
1616 static int patch_ad1983(struct hda_codec *codec)
1618 struct ad198x_spec *spec;
1622 err = alloc_ad_spec(codec);
1627 board_config = snd_hda_check_board_config(codec, AD1983_MODELS,
1628 ad1983_models, NULL);
1629 if (board_config == AD1983_AUTO) {
1630 err = ad1983_parse_auto_config(codec);
1638 err = snd_hda_attach_beep_device(codec, 0x10);
1643 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1645 spec->multiout.max_channels = 2;
1646 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1647 spec->multiout.dac_nids = ad1983_dac_nids;
1648 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
1649 spec->num_adc_nids = 1;
1650 spec->adc_nids = ad1983_adc_nids;
1651 spec->capsrc_nids = ad1983_capsrc_nids;
1652 spec->input_mux = &ad1983_capture_source;
1653 spec->num_mixers = 1;
1654 spec->mixers[0] = ad1983_mixers;
1655 spec->num_init_verbs = 1;
1656 spec->init_verbs[0] = ad1983_init_verbs;
1657 spec->spdif_route = 0;
1659 spec->loopback.amplist = ad1983_loopbacks;
1661 spec->vmaster_nid = 0x05;
1663 codec->patch_ops = ad198x_patch_ops;
1665 codec->no_trigger_sense = 1;
1666 codec->no_sticky_stream = 1;
1673 * AD1981 HD specific
1676 #define AD1981_SPDIF_OUT 0x02
1677 #define AD1981_DAC 0x03
1678 #define AD1981_ADC 0x04
1680 static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
1681 static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
1682 static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
1684 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
1685 static const struct hda_input_mux ad1981_capture_source = {
1688 { "Front Mic", 0x0 },
1691 { "Mix Mono", 0x3 },
1698 static const struct snd_kcontrol_new ad1981_mixers[] = {
1699 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1700 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1701 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1702 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1703 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1704 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1705 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1706 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1707 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1708 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1709 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1710 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1711 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1712 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1713 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1714 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1715 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1716 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1717 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1718 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
1719 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1720 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1722 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1723 .name = "Capture Source",
1724 .info = ad198x_mux_enum_info,
1725 .get = ad198x_mux_enum_get,
1726 .put = ad198x_mux_enum_put,
1728 /* identical with AD1983 */
1730 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1731 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1732 .info = ad1983_spdif_route_info,
1733 .get = ad1983_spdif_route_get,
1734 .put = ad1983_spdif_route_put,
1739 static const struct hda_verb ad1981_init_verbs[] = {
1740 /* Front, HP, Mono; mute as default */
1741 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1742 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1743 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1744 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1745 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1746 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1747 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1748 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1749 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1750 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1751 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1752 /* Front, HP selectors; from Mix */
1753 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1754 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1755 /* Mono selector; from Mix */
1756 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1757 /* Mic Mixer; select Front Mic */
1758 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1759 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1760 /* Mic boost: 0dB */
1761 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1762 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1763 /* Record selector: Front mic */
1764 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1765 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1766 /* SPDIF route: PCM */
1767 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1769 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1771 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1773 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1774 /* Front & Rear Mic Pins */
1775 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1776 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1778 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1780 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1781 /* Line-Out as Input: disabled */
1782 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1787 static const struct hda_amp_list ad1981_loopbacks[] = {
1788 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1789 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1790 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1791 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1792 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1798 * Patch for HP nx6320
1800 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
1801 * speaker output enabled _and_ mute-LED off.
1804 #define AD1981_HP_EVENT 0x37
1805 #define AD1981_MIC_EVENT 0x38
1807 static const struct hda_verb ad1981_hp_init_verbs[] = {
1808 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1809 /* pin sensing on HP and Mic jacks */
1810 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1811 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1815 /* turn on/off EAPD (+ mute HP) as a master switch */
1816 static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1817 struct snd_ctl_elem_value *ucontrol)
1819 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1820 struct ad198x_spec *spec = codec->spec;
1822 if (! ad198x_eapd_put(kcontrol, ucontrol))
1824 /* change speaker pin appropriately */
1825 snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0);
1826 /* toggle HP mute appropriately */
1827 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1829 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
1833 /* bind volumes of both NID 0x05 and 0x06 */
1834 static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1835 .ops = &snd_hda_bind_vol,
1837 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1838 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1843 /* mute internal speaker if HP is plugged */
1844 static void ad1981_hp_automute(struct hda_codec *codec)
1846 unsigned int present;
1848 present = snd_hda_jack_detect(codec, 0x06);
1849 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1850 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1853 /* toggle input of built-in and mic jack appropriately */
1854 static void ad1981_hp_automic(struct hda_codec *codec)
1856 static const struct hda_verb mic_jack_on[] = {
1857 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1858 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1861 static const struct hda_verb mic_jack_off[] = {
1862 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1863 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1866 unsigned int present;
1868 present = snd_hda_jack_detect(codec, 0x08);
1870 snd_hda_sequence_write(codec, mic_jack_on);
1872 snd_hda_sequence_write(codec, mic_jack_off);
1875 /* unsolicited event for HP jack sensing */
1876 static void ad1981_hp_unsol_event(struct hda_codec *codec,
1881 case AD1981_HP_EVENT:
1882 ad1981_hp_automute(codec);
1884 case AD1981_MIC_EVENT:
1885 ad1981_hp_automic(codec);
1890 static const struct hda_input_mux ad1981_hp_capture_source = {
1894 { "Dock Mic", 0x1 },
1899 static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
1900 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
1902 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1903 .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
1904 .name = "Master Playback Switch",
1905 .info = ad198x_eapd_info,
1906 .get = ad198x_eapd_get,
1907 .put = ad1981_hp_master_sw_put,
1908 .private_value = 0x05,
1910 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1911 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1913 /* FIXME: analog mic/line loopback doesn't work with my tests...
1914 * (although recording is OK)
1916 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1917 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1918 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1919 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1920 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1921 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1922 /* FIXME: does this laptop have analog CD connection? */
1923 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1924 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1926 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1927 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
1928 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1929 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1931 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1932 .name = "Capture Source",
1933 .info = ad198x_mux_enum_info,
1934 .get = ad198x_mux_enum_get,
1935 .put = ad198x_mux_enum_put,
1940 /* initialize jack-sensing, too */
1941 static int ad1981_hp_init(struct hda_codec *codec)
1944 ad1981_hp_automute(codec);
1945 ad1981_hp_automic(codec);
1949 /* configuration for Toshiba Laptops */
1950 static const struct hda_verb ad1981_toshiba_init_verbs[] = {
1951 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
1952 /* pin sensing on HP and Mic jacks */
1953 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1954 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1958 static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1959 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1960 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1964 /* configuration for Lenovo Thinkpad T60 */
1965 static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1966 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1967 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1968 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1969 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1970 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1971 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1972 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1973 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1974 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1975 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1976 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1978 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1979 .name = "Capture Source",
1980 .info = ad198x_mux_enum_info,
1981 .get = ad198x_mux_enum_get,
1982 .put = ad198x_mux_enum_put,
1984 /* identical with AD1983 */
1986 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1987 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1988 .info = ad1983_spdif_route_info,
1989 .get = ad1983_spdif_route_get,
1990 .put = ad1983_spdif_route_put,
1995 static const struct hda_input_mux ad1981_thinkpad_capture_source = {
2014 static const char * const ad1981_models[AD1981_MODELS] = {
2015 [AD1981_AUTO] = "auto",
2017 [AD1981_THINKPAD] = "thinkpad",
2018 [AD1981_BASIC] = "basic",
2019 [AD1981_TOSHIBA] = "toshiba"
2022 static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
2023 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
2024 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
2026 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
2027 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
2028 /* Lenovo Thinkpad T60/X60/Z6xx */
2029 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
2030 /* HP nx6320 (reversed SSID, H/W bug) */
2031 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
2035 static int ad1981_parse_auto_config(struct hda_codec *codec)
2037 struct ad198x_spec *spec = codec->spec;
2040 spec->gen.mixer_nid = 0x0e;
2041 spec->beep_dev_nid = 0x10;
2042 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
2043 err = ad198x_parse_auto_config(codec);
2046 err = ad1983_add_spdif_mux_ctl(codec);
2052 static int patch_ad1981(struct hda_codec *codec)
2054 struct ad198x_spec *spec;
2055 int err, board_config;
2057 err = alloc_ad_spec(codec);
2062 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
2065 if (board_config == AD1981_AUTO) {
2066 err = ad1981_parse_auto_config(codec);
2074 err = snd_hda_attach_beep_device(codec, 0x10);
2079 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
2081 spec->multiout.max_channels = 2;
2082 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
2083 spec->multiout.dac_nids = ad1981_dac_nids;
2084 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
2085 spec->num_adc_nids = 1;
2086 spec->adc_nids = ad1981_adc_nids;
2087 spec->capsrc_nids = ad1981_capsrc_nids;
2088 spec->input_mux = &ad1981_capture_source;
2089 spec->num_mixers = 1;
2090 spec->mixers[0] = ad1981_mixers;
2091 spec->num_init_verbs = 1;
2092 spec->init_verbs[0] = ad1981_init_verbs;
2093 spec->spdif_route = 0;
2095 spec->loopback.amplist = ad1981_loopbacks;
2097 spec->vmaster_nid = 0x05;
2099 codec->patch_ops = ad198x_patch_ops;
2101 /* override some parameters */
2102 switch (board_config) {
2104 spec->mixers[0] = ad1981_hp_mixers;
2105 spec->num_init_verbs = 2;
2106 spec->init_verbs[1] = ad1981_hp_init_verbs;
2107 if (!is_jack_available(codec, 0x0a))
2108 spec->multiout.dig_out_nid = 0;
2109 spec->input_mux = &ad1981_hp_capture_source;
2111 codec->patch_ops.init = ad1981_hp_init;
2112 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
2113 /* set the upper-limit for mixer amp to 0dB for avoiding the
2114 * possible damage by overloading
2116 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2117 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2118 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2119 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2120 (1 << AC_AMPCAP_MUTE_SHIFT));
2122 case AD1981_THINKPAD:
2123 spec->mixers[0] = ad1981_thinkpad_mixers;
2124 spec->input_mux = &ad1981_thinkpad_capture_source;
2125 /* set the upper-limit for mixer amp to 0dB for avoiding the
2126 * possible damage by overloading
2128 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2129 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2130 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2131 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2132 (1 << AC_AMPCAP_MUTE_SHIFT));
2134 case AD1981_TOSHIBA:
2135 spec->mixers[0] = ad1981_hp_mixers;
2136 spec->mixers[1] = ad1981_toshiba_mixers;
2137 spec->num_init_verbs = 2;
2138 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
2139 spec->multiout.dig_out_nid = 0;
2140 spec->input_mux = &ad1981_hp_capture_source;
2141 codec->patch_ops.init = ad1981_hp_init;
2142 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
2146 codec->no_trigger_sense = 1;
2147 codec->no_sticky_stream = 1;
2156 * Output pins and routes
2158 * Pin Mix Sel DAC (*)
2159 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
2160 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
2161 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
2162 * port-D 0x12 (mute/hp) <- 0x29 <- 04
2163 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
2164 * port-F 0x16 (mute) <- 0x2a <- 06
2165 * port-G 0x24 (mute) <- 0x27 <- 05
2166 * port-H 0x25 (mute) <- 0x28 <- 0a
2167 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
2169 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
2170 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
2172 * Input pins and routes
2174 * pin boost mix input # / adc input #
2175 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
2176 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
2177 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
2178 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
2179 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
2180 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
2181 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
2182 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
2186 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
2187 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
2189 * Inputs of Analog Mix (0x20)
2190 * 0:Port-B (front mic)
2191 * 1:Port-C/G/H (line-in)
2193 * 3:Port-D (line-in/2)
2194 * 4:Port-E/G/H (mic-in)
2195 * 5:Port-F (mic2-in)
2201 * 1:Port-B (front mic-in)
2202 * 2:Port-C (line-in)
2203 * 3:Port-F (mic2-in)
2208 * 8:Port-D (line-in/2)
2211 * Proposed pin assignments by the datasheet
2214 * Port-A front headphone
2224 * Port-A front headphone
2226 * C rear line-in/surround
2228 * E rear mic-in/CLFE
2234 * D internal speaker (with EAPD)
2235 * E/F quad mic array
2251 /* reivision id to check workarounds */
2252 #define AD1988A_REV2 0x100200
2254 #define is_rev2(codec) \
2255 ((codec)->vendor_id == 0x11d41988 && \
2256 (codec)->revision_id == AD1988A_REV2)
2262 static const hda_nid_t ad1988_6stack_dac_nids[4] = {
2263 0x04, 0x06, 0x05, 0x0a
2266 static const hda_nid_t ad1988_3stack_dac_nids[3] = {
2270 /* for AD1988A revision-2, DAC2-4 are swapped */
2271 static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
2272 0x04, 0x05, 0x0a, 0x06
2275 static const hda_nid_t ad1988_alt_dac_nid[1] = {
2279 static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
2283 static const hda_nid_t ad1988_adc_nids[3] = {
2287 static const hda_nid_t ad1988_capsrc_nids[3] = {
2291 #define AD1988_SPDIF_OUT 0x02
2292 #define AD1988_SPDIF_OUT_HDMI 0x0b
2293 #define AD1988_SPDIF_IN 0x07
2295 static const hda_nid_t ad1989b_slave_dig_outs[] = {
2296 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
2299 static const struct hda_input_mux ad1988_6stack_capture_source = {
2302 { "Front Mic", 0x1 }, /* port-B */
2303 { "Line", 0x2 }, /* port-C */
2304 { "Mic", 0x4 }, /* port-E */
2310 static const struct hda_input_mux ad1988_laptop_capture_source = {
2313 { "Mic/Line", 0x1 }, /* port-B */
2321 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
2322 struct snd_ctl_elem_info *uinfo)
2324 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2325 struct ad198x_spec *spec = codec->spec;
2326 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
2327 spec->num_channel_mode);
2330 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
2331 struct snd_ctl_elem_value *ucontrol)
2333 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2334 struct ad198x_spec *spec = codec->spec;
2335 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
2336 spec->num_channel_mode, spec->multiout.max_channels);
2339 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
2340 struct snd_ctl_elem_value *ucontrol)
2342 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2343 struct ad198x_spec *spec = codec->spec;
2344 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
2345 spec->num_channel_mode,
2346 &spec->multiout.max_channels);
2347 if (err >= 0 && spec->need_dac_fix)
2348 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2353 static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
2354 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2355 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2356 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2357 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2358 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2362 static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
2363 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2364 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2365 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2366 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2367 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2371 static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
2372 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2373 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2374 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2375 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2376 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2377 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2378 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2379 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2381 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2382 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2383 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2384 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2385 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2386 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2387 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2388 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2390 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2391 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2393 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2394 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2399 static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
2400 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2401 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2402 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2403 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2407 static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2408 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2409 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2410 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2411 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
2415 static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
2416 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2417 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2418 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2419 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2420 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
2421 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2422 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2424 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2425 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2426 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2427 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2428 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2429 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2430 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2431 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2433 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2434 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2436 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2437 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2439 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2440 .name = "Channel Mode",
2441 .info = ad198x_ch_mode_info,
2442 .get = ad198x_ch_mode_get,
2443 .put = ad198x_ch_mode_put,
2450 static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2451 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2452 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2453 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2454 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2456 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2457 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2458 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2459 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2460 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2461 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2463 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2464 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2466 HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2469 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2470 .name = "External Amplifier",
2471 .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
2472 .info = ad198x_eapd_info,
2473 .get = ad198x_eapd_get,
2474 .put = ad198x_eapd_put,
2475 .private_value = 0x12, /* port-D */
2482 static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
2483 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2484 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2485 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2486 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2487 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2488 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2490 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2491 /* The multiple "Capture Source" controls confuse alsamixer
2492 * So call somewhat different..
2494 /* .name = "Capture Source", */
2495 .name = "Input Source",
2497 .info = ad198x_mux_enum_info,
2498 .get = ad198x_mux_enum_get,
2499 .put = ad198x_mux_enum_put,
2504 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2505 struct snd_ctl_elem_info *uinfo)
2507 static const char * const texts[] = {
2508 "PCM", "ADC1", "ADC2", "ADC3"
2510 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2512 uinfo->value.enumerated.items = 4;
2513 if (uinfo->value.enumerated.item >= 4)
2514 uinfo->value.enumerated.item = 3;
2515 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2519 static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2520 struct snd_ctl_elem_value *ucontrol)
2522 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2525 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2528 ucontrol->value.enumerated.item[0] = 0;
2530 sel = snd_hda_codec_read(codec, 0x0b, 0,
2531 AC_VERB_GET_CONNECT_SEL, 0);
2536 ucontrol->value.enumerated.item[0] = sel;
2541 static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2542 struct snd_ctl_elem_value *ucontrol)
2544 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2545 unsigned int val, sel;
2548 val = ucontrol->value.enumerated.item[0];
2552 sel = snd_hda_codec_read(codec, 0x1d, 0,
2553 AC_VERB_GET_AMP_GAIN_MUTE,
2555 change = sel & 0x80;
2557 snd_hda_codec_write_cache(codec, 0x1d, 0,
2558 AC_VERB_SET_AMP_GAIN_MUTE,
2560 snd_hda_codec_write_cache(codec, 0x1d, 0,
2561 AC_VERB_SET_AMP_GAIN_MUTE,
2565 sel = snd_hda_codec_read(codec, 0x1d, 0,
2566 AC_VERB_GET_AMP_GAIN_MUTE,
2567 AC_AMP_GET_INPUT | 0x01);
2568 change = sel & 0x80;
2570 snd_hda_codec_write_cache(codec, 0x1d, 0,
2571 AC_VERB_SET_AMP_GAIN_MUTE,
2573 snd_hda_codec_write_cache(codec, 0x1d, 0,
2574 AC_VERB_SET_AMP_GAIN_MUTE,
2577 sel = snd_hda_codec_read(codec, 0x0b, 0,
2578 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2579 change |= sel != val;
2581 snd_hda_codec_write_cache(codec, 0x0b, 0,
2582 AC_VERB_SET_CONNECT_SEL,
2588 static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2589 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2591 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2592 .name = "IEC958 Playback Source",
2593 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
2594 .info = ad1988_spdif_playback_source_info,
2595 .get = ad1988_spdif_playback_source_get,
2596 .put = ad1988_spdif_playback_source_put,
2601 static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2602 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2606 static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2607 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2608 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2613 * initialization verbs
2617 * for 6-stack (+dig)
2619 static const struct hda_verb ad1988_6stack_init_verbs[] = {
2620 /* Front, Surround, CLFE, side DAC; unmute as default */
2621 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2622 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2623 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2624 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2625 /* Port-A front headphon path */
2626 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2627 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2628 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2629 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2630 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2631 /* Port-D line-out path */
2632 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2633 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2634 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2635 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2636 /* Port-F surround path */
2637 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2638 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2639 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2640 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2641 /* Port-G CLFE path */
2642 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2643 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2644 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2645 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2646 /* Port-H side path */
2647 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2648 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2649 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2650 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2652 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2653 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2654 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2655 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2656 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2657 /* Port-B front mic-in path */
2658 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2659 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2660 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2661 /* Port-C line-in path */
2662 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2663 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2664 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2665 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2666 /* Port-E mic-in path */
2667 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2668 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2669 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2670 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2671 /* Analog CD Input */
2672 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2673 /* Analog Mix output amp */
2674 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2679 static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
2680 /* Headphone; unmute as default */
2681 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2682 /* Port-A front headphon path */
2683 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2684 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2685 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2686 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2687 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2692 static const struct hda_verb ad1988_capture_init_verbs[] = {
2693 /* mute analog mix */
2694 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2695 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2696 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2697 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2698 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2699 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2700 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2701 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2702 /* select ADCs - front-mic */
2703 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2704 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2705 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2710 static const struct hda_verb ad1988_spdif_init_verbs[] = {
2712 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2713 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2714 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2715 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2717 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2722 static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
2723 /* unmute SPDIF input pin */
2724 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2728 /* AD1989 has no ADC -> SPDIF route */
2729 static const struct hda_verb ad1989_spdif_init_verbs[] = {
2730 /* SPDIF-1 out pin */
2731 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2732 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2733 /* SPDIF-2/HDMI out pin */
2734 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2735 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2740 * verbs for 3stack (+dig)
2742 static const struct hda_verb ad1988_3stack_ch2_init[] = {
2743 /* set port-C to line-in */
2744 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2745 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2746 /* set port-E to mic-in */
2747 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2748 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2752 static const struct hda_verb ad1988_3stack_ch6_init[] = {
2753 /* set port-C to surround out */
2754 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2755 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2756 /* set port-E to CLFE out */
2757 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2758 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2762 static const struct hda_channel_mode ad1988_3stack_modes[2] = {
2763 { 2, ad1988_3stack_ch2_init },
2764 { 6, ad1988_3stack_ch6_init },
2767 static const struct hda_verb ad1988_3stack_init_verbs[] = {
2768 /* Front, Surround, CLFE, side DAC; unmute as default */
2769 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2770 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2771 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2772 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2773 /* Port-A front headphon path */
2774 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2775 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2776 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2777 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2778 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2779 /* Port-D line-out path */
2780 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2781 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2782 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2783 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2785 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2786 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2787 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2788 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2789 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2790 /* Port-B front mic-in path */
2791 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2792 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2793 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2794 /* Port-C line-in/surround path - 6ch mode as default */
2795 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2796 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2797 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2798 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
2799 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2800 /* Port-E mic-in/CLFE path - 6ch mode as default */
2801 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2802 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2803 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2804 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
2805 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2806 /* mute analog mix */
2807 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2808 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2809 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2810 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2811 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2812 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2813 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2814 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2815 /* select ADCs - front-mic */
2816 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2817 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2818 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2819 /* Analog Mix output amp */
2820 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2825 * verbs for laptop mode (+dig)
2827 static const struct hda_verb ad1988_laptop_hp_on[] = {
2828 /* unmute port-A and mute port-D */
2829 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2830 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2833 static const struct hda_verb ad1988_laptop_hp_off[] = {
2834 /* mute port-A and unmute port-D */
2835 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2836 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2840 #define AD1988_HP_EVENT 0x01
2842 static const struct hda_verb ad1988_laptop_init_verbs[] = {
2843 /* Front, Surround, CLFE, side DAC; unmute as default */
2844 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2845 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2846 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2847 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2848 /* Port-A front headphon path */
2849 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2850 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2851 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2852 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2853 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2854 /* unsolicited event for pin-sense */
2855 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2856 /* Port-D line-out path + EAPD */
2857 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2858 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2859 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2860 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2861 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
2863 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2864 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2865 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2866 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2867 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2868 /* Port-B mic-in path */
2869 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2870 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2871 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2872 /* Port-C docking station - try to output */
2873 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2874 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2875 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2876 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2877 /* mute analog mix */
2878 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2879 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2880 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2881 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2882 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2883 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2884 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2885 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2886 /* select ADCs - mic */
2887 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2888 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2889 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2890 /* Analog Mix output amp */
2891 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2895 static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2897 if ((res >> 26) != AD1988_HP_EVENT)
2899 if (snd_hda_jack_detect(codec, 0x11))
2900 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2902 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2906 static const struct hda_amp_list ad1988_loopbacks[] = {
2907 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2908 { 0x20, HDA_INPUT, 1 }, /* Line */
2909 { 0x20, HDA_INPUT, 4 }, /* Mic */
2910 { 0x20, HDA_INPUT, 6 }, /* CD */
2915 static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
2916 struct snd_ctl_elem_info *uinfo)
2918 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2919 static const char * const texts[] = {
2920 "PCM", "ADC1", "ADC2", "ADC3",
2922 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
2925 return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
2928 static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
2929 struct snd_ctl_elem_value *ucontrol)
2931 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2932 struct ad198x_spec *spec = codec->spec;
2934 ucontrol->value.enumerated.item[0] = spec->cur_smux;
2938 static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
2939 struct snd_ctl_elem_value *ucontrol)
2941 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2942 struct ad198x_spec *spec = codec->spec;
2943 unsigned int val = ucontrol->value.enumerated.item[0];
2944 struct nid_path *path;
2945 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
2947 if (val >= num_conns)
2949 if (spec->cur_smux == val)
2952 mutex_lock(&codec->control_mutex);
2953 codec->cached_write = 1;
2954 path = snd_hda_get_path_from_idx(codec,
2955 spec->smux_paths[spec->cur_smux]);
2957 snd_hda_activate_path(codec, path, false, true);
2958 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
2960 snd_hda_activate_path(codec, path, true, true);
2961 spec->cur_smux = val;
2962 codec->cached_write = 0;
2963 mutex_unlock(&codec->control_mutex);
2964 snd_hda_codec_flush_cache(codec); /* flush the updates */
2968 static struct snd_kcontrol_new ad1988_auto_smux_mixer = {
2969 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2970 .name = "IEC958 Playback Source",
2971 .info = ad1988_auto_smux_enum_info,
2972 .get = ad1988_auto_smux_enum_get,
2973 .put = ad1988_auto_smux_enum_put,
2976 static int ad1988_auto_init(struct hda_codec *codec)
2978 struct ad198x_spec *spec = codec->spec;
2981 err = snd_hda_gen_init(codec);
2984 if (!spec->gen.autocfg.dig_outs)
2987 for (i = 0; i < 4; i++) {
2988 struct nid_path *path;
2989 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
2991 snd_hda_activate_path(codec, path, path->active, false);
2997 static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
2999 struct ad198x_spec *spec = codec->spec;
3001 /* we create four static faked paths, since AD codecs have odd
3002 * widget connections regarding the SPDIF out source
3004 static struct nid_path fake_paths[4] = {
3007 .path = { 0x02, 0x1d, 0x1b },
3009 .multi = { 0, 0, 0 },
3013 .path = { 0x08, 0x0b, 0x1d, 0x1b },
3014 .idx = { 0, 0, 1, 0 },
3015 .multi = { 0, 1, 0, 0 },
3019 .path = { 0x09, 0x0b, 0x1d, 0x1b },
3020 .idx = { 0, 1, 1, 0 },
3021 .multi = { 0, 1, 0, 0 },
3025 .path = { 0x0f, 0x0b, 0x1d, 0x1b },
3026 .idx = { 0, 2, 1, 0 },
3027 .multi = { 0, 1, 0, 0 },
3031 /* SPDIF source mux appears to be present only on AD1988A */
3032 if (!spec->gen.autocfg.dig_outs ||
3033 get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
3036 num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
3037 if (num_conns != 3 && num_conns != 4)
3040 for (i = 0; i < num_conns; i++) {
3041 struct nid_path *path = snd_array_new(&spec->gen.paths);
3044 *path = fake_paths[i];
3047 spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
3050 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
3053 codec->patch_ops.init = ad1988_auto_init;
3061 static int ad1988_parse_auto_config(struct hda_codec *codec)
3063 struct ad198x_spec *spec = codec->spec;
3066 spec->gen.mixer_nid = 0x20;
3067 spec->beep_dev_nid = 0x10;
3068 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3069 err = ad198x_parse_auto_config(codec);
3072 err = ad1988_add_spdif_mux_ctl(codec);
3081 static const char * const ad1988_models[AD1988_MODEL_LAST] = {
3082 [AD1988_6STACK] = "6stack",
3083 [AD1988_6STACK_DIG] = "6stack-dig",
3084 [AD1988_3STACK] = "3stack",
3085 [AD1988_3STACK_DIG] = "3stack-dig",
3086 [AD1988_LAPTOP] = "laptop",
3087 [AD1988_LAPTOP_DIG] = "laptop-dig",
3088 [AD1988_AUTO] = "auto",
3091 static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
3092 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
3093 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
3094 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
3095 SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
3096 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
3100 static int patch_ad1988(struct hda_codec *codec)
3102 struct ad198x_spec *spec;
3103 int err, board_config;
3105 err = alloc_ad_spec(codec);
3110 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
3111 ad1988_models, ad1988_cfg_tbl);
3112 if (board_config < 0) {
3113 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3115 board_config = AD1988_AUTO;
3118 if (board_config == AD1988_AUTO) {
3119 /* automatic parse from the BIOS config */
3120 err = ad1988_parse_auto_config(codec);
3129 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
3131 err = snd_hda_attach_beep_device(codec, 0x10);
3136 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3138 if (!spec->multiout.hp_nid)
3139 spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
3140 switch (board_config) {
3142 case AD1988_6STACK_DIG:
3143 spec->multiout.max_channels = 8;
3144 spec->multiout.num_dacs = 4;
3146 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3148 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
3149 spec->input_mux = &ad1988_6stack_capture_source;
3150 spec->num_mixers = 2;
3152 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3154 spec->mixers[0] = ad1988_6stack_mixers1;
3155 spec->mixers[1] = ad1988_6stack_mixers2;
3156 spec->num_init_verbs = 1;
3157 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3158 if (board_config == AD1988_6STACK_DIG) {
3159 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3160 spec->dig_in_nid = AD1988_SPDIF_IN;
3164 case AD1988_3STACK_DIG:
3165 spec->multiout.max_channels = 6;
3166 spec->multiout.num_dacs = 3;
3168 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3170 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3171 spec->input_mux = &ad1988_6stack_capture_source;
3172 spec->channel_mode = ad1988_3stack_modes;
3173 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
3174 spec->num_mixers = 2;
3176 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3178 spec->mixers[0] = ad1988_3stack_mixers1;
3179 spec->mixers[1] = ad1988_3stack_mixers2;
3180 spec->num_init_verbs = 1;
3181 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3182 if (board_config == AD1988_3STACK_DIG)
3183 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3186 case AD1988_LAPTOP_DIG:
3187 spec->multiout.max_channels = 2;
3188 spec->multiout.num_dacs = 1;
3189 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3190 spec->input_mux = &ad1988_laptop_capture_source;
3191 spec->num_mixers = 1;
3192 spec->mixers[0] = ad1988_laptop_mixers;
3193 codec->inv_eapd = 1; /* inverted EAPD */
3194 spec->num_init_verbs = 1;
3195 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3196 if (board_config == AD1988_LAPTOP_DIG)
3197 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3201 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3202 spec->adc_nids = ad1988_adc_nids;
3203 spec->capsrc_nids = ad1988_capsrc_nids;
3204 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3205 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3206 if (spec->multiout.dig_out_nid) {
3207 if (codec->vendor_id >= 0x11d4989a) {
3208 spec->mixers[spec->num_mixers++] =
3209 ad1989_spdif_out_mixers;
3210 spec->init_verbs[spec->num_init_verbs++] =
3211 ad1989_spdif_init_verbs;
3212 codec->slave_dig_outs = ad1989b_slave_dig_outs;
3214 spec->mixers[spec->num_mixers++] =
3215 ad1988_spdif_out_mixers;
3216 spec->init_verbs[spec->num_init_verbs++] =
3217 ad1988_spdif_init_verbs;
3220 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
3221 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
3222 spec->init_verbs[spec->num_init_verbs++] =
3223 ad1988_spdif_in_init_verbs;
3226 codec->patch_ops = ad198x_patch_ops;
3227 switch (board_config) {
3229 case AD1988_LAPTOP_DIG:
3230 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3234 spec->loopback.amplist = ad1988_loopbacks;
3236 spec->vmaster_nid = 0x04;
3238 codec->no_trigger_sense = 1;
3239 codec->no_sticky_stream = 1;
3248 * port-B - front line/mic-in
3249 * port-E - aux in/out
3250 * port-F - aux in/out
3251 * port-C - rear line/mic-in
3252 * port-D - rear line/hp-out
3253 * port-A - front line/hp-out
3255 * AD1984 = AD1884 + two digital mic-ins
3258 * For simplicity, we share the single DAC for both HP and line-outs
3259 * right now. The inidividual playbacks could be easily implemented,
3260 * but no build-up framework is given, so far.
3263 static const hda_nid_t ad1884_dac_nids[1] = {
3267 static const hda_nid_t ad1884_adc_nids[2] = {
3271 static const hda_nid_t ad1884_capsrc_nids[2] = {
3275 #define AD1884_SPDIF_OUT 0x02
3277 static const struct hda_input_mux ad1884_capture_source = {
3280 { "Front Mic", 0x0 },
3287 static const struct snd_kcontrol_new ad1884_base_mixers[] = {
3288 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3289 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3290 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3291 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3292 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3293 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3294 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3295 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3296 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3297 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3298 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3299 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3300 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3301 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3302 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3303 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3304 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3305 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3307 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3308 /* The multiple "Capture Source" controls confuse alsamixer
3309 * So call somewhat different..
3311 /* .name = "Capture Source", */
3312 .name = "Input Source",
3314 .info = ad198x_mux_enum_info,
3315 .get = ad198x_mux_enum_get,
3316 .put = ad198x_mux_enum_put,
3318 /* SPDIF controls */
3319 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3321 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3322 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3323 /* identical with ad1983 */
3324 .info = ad1983_spdif_route_info,
3325 .get = ad1983_spdif_route_get,
3326 .put = ad1983_spdif_route_put,
3331 static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3332 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3333 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3334 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
3336 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
3342 * initialization verbs
3344 static const struct hda_verb ad1884_init_verbs[] = {
3345 /* DACs; mute as default */
3346 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3347 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3348 /* Port-A (HP) mixer */
3349 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3350 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3352 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3353 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3354 /* HP selector - select DAC2 */
3355 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3356 /* Port-D (Line-out) mixer */
3357 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3358 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3360 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3361 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3362 /* Mono-out mixer */
3363 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3364 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3366 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3367 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3369 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3370 /* Port-B (front mic) pin */
3371 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3372 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3373 /* Port-C (rear mic) pin */
3374 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3375 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3376 /* Analog mixer; mute as default */
3377 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3378 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3379 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3380 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3381 /* Analog Mix output amp */
3382 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3383 /* SPDIF output selector */
3384 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3385 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3390 static const struct hda_amp_list ad1884_loopbacks[] = {
3391 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3392 { 0x20, HDA_INPUT, 1 }, /* Mic */
3393 { 0x20, HDA_INPUT, 2 }, /* CD */
3394 { 0x20, HDA_INPUT, 4 }, /* Docking */
3399 static const char * const ad1884_slave_vols[] = {
3400 "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD",
3401 "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958",
3411 static const char * const ad1884_models[AD1884_MODELS] = {
3412 [AD1884_AUTO] = "auto",
3413 [AD1884_BASIC] = "basic",
3416 static int ad1884_parse_auto_config(struct hda_codec *codec)
3418 struct ad198x_spec *spec = codec->spec;
3421 spec->gen.mixer_nid = 0x20;
3422 spec->beep_dev_nid = 0x10;
3423 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3424 err = ad198x_parse_auto_config(codec);
3427 err = ad1983_add_spdif_mux_ctl(codec);
3433 static int patch_ad1884_auto(struct hda_codec *codec)
3437 err = alloc_ad_spec(codec);
3441 err = ad1884_parse_auto_config(codec);
3449 static int patch_ad1884_basic(struct hda_codec *codec)
3451 struct ad198x_spec *spec;
3454 err = alloc_ad_spec(codec);
3459 err = snd_hda_attach_beep_device(codec, 0x10);
3464 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3466 spec->multiout.max_channels = 2;
3467 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3468 spec->multiout.dac_nids = ad1884_dac_nids;
3469 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3470 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3471 spec->adc_nids = ad1884_adc_nids;
3472 spec->capsrc_nids = ad1884_capsrc_nids;
3473 spec->input_mux = &ad1884_capture_source;
3474 spec->num_mixers = 1;
3475 spec->mixers[0] = ad1884_base_mixers;
3476 spec->num_init_verbs = 1;
3477 spec->init_verbs[0] = ad1884_init_verbs;
3478 spec->spdif_route = 0;
3480 spec->loopback.amplist = ad1884_loopbacks;
3482 spec->vmaster_nid = 0x04;
3483 /* we need to cover all playback volumes */
3484 spec->slave_vols = ad1884_slave_vols;
3485 /* slaves may contain input volumes, so we can't raise to 0dB blindly */
3486 spec->avoid_init_slave_vol = 1;
3488 codec->patch_ops = ad198x_patch_ops;
3490 codec->no_trigger_sense = 1;
3491 codec->no_sticky_stream = 1;
3496 static int patch_ad1884(struct hda_codec *codec)
3500 board_config = snd_hda_check_board_config(codec, AD1884_MODELS,
3501 ad1884_models, NULL);
3502 if (board_config == AD1884_AUTO)
3503 return patch_ad1884_auto(codec);
3505 return patch_ad1884_basic(codec);
3509 * Lenovo Thinkpad T61/X61
3511 static const struct hda_input_mux ad1984_thinkpad_capture_source = {
3515 { "Internal Mic", 0x1 },
3517 { "Dock Mic", 0x4 },
3523 * Dell Precision T3400
3525 static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
3528 { "Front Mic", 0x0 },
3535 static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3536 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3537 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3538 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3539 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3540 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3541 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3542 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3543 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3544 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3545 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3546 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3547 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3548 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3549 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3550 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3551 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3552 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3553 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3554 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3556 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3557 /* The multiple "Capture Source" controls confuse alsamixer
3558 * So call somewhat different..
3560 /* .name = "Capture Source", */
3561 .name = "Input Source",
3563 .info = ad198x_mux_enum_info,
3564 .get = ad198x_mux_enum_get,
3565 .put = ad198x_mux_enum_put,
3567 /* SPDIF controls */
3568 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3570 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3571 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3572 /* identical with ad1983 */
3573 .info = ad1983_spdif_route_info,
3574 .get = ad1983_spdif_route_get,
3575 .put = ad1983_spdif_route_put,
3580 /* additional verbs */
3581 static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
3582 /* Port-E (docking station mic) pin */
3583 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3584 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3585 /* docking mic boost */
3586 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3587 /* Analog PC Beeper - allow firmware/ACPI beeps */
3588 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
3589 /* Analog mixer - docking mic; mute as default */
3590 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3591 /* enable EAPD bit */
3592 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3597 * Dell Precision T3400
3599 static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3600 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3601 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3602 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3603 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3604 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3605 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3606 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3607 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3608 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
3609 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
3610 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3611 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3612 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3613 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3614 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3616 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3617 /* The multiple "Capture Source" controls confuse alsamixer
3618 * So call somewhat different..
3620 /* .name = "Capture Source", */
3621 .name = "Input Source",
3623 .info = ad198x_mux_enum_info,
3624 .get = ad198x_mux_enum_get,
3625 .put = ad198x_mux_enum_put,
3630 /* Digial MIC ADC NID 0x05 + 0x06 */
3631 static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3632 struct hda_codec *codec,
3633 unsigned int stream_tag,
3634 unsigned int format,
3635 struct snd_pcm_substream *substream)
3637 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3638 stream_tag, 0, format);
3642 static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3643 struct hda_codec *codec,
3644 struct snd_pcm_substream *substream)
3646 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
3650 static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3656 .prepare = ad1984_pcm_dmic_prepare,
3657 .cleanup = ad1984_pcm_dmic_cleanup
3661 static int ad1984_build_pcms(struct hda_codec *codec)
3663 struct ad198x_spec *spec = codec->spec;
3664 struct hda_pcm *info;
3667 err = ad198x_build_pcms(codec);
3671 info = spec->pcm_rec + codec->num_pcms;
3673 info->name = "AD1984 Digital Mic";
3674 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3683 AD1984_DELL_DESKTOP,
3687 static const char * const ad1984_models[AD1984_MODELS] = {
3688 [AD1984_AUTO] = "auto",
3689 [AD1984_BASIC] = "basic",
3690 [AD1984_THINKPAD] = "thinkpad",
3691 [AD1984_DELL_DESKTOP] = "dell_desktop",
3694 static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
3695 /* Lenovo Thinkpad T61/X61 */
3696 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
3697 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
3698 SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
3702 static int patch_ad1984(struct hda_codec *codec)
3704 struct ad198x_spec *spec;
3705 int board_config, err;
3707 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3708 ad1984_models, ad1984_cfg_tbl);
3709 if (board_config == AD1984_AUTO)
3710 return patch_ad1884_auto(codec);
3712 err = patch_ad1884_basic(codec);
3717 switch (board_config) {
3719 /* additional digital mics */
3720 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3721 codec->patch_ops.build_pcms = ad1984_build_pcms;
3723 case AD1984_THINKPAD:
3724 if (codec->subsystem_id == 0x17aa20fb) {
3725 /* Thinpad X300 does not have the ability to do SPDIF,
3726 or attach to docking station to use SPDIF */
3727 spec->multiout.dig_out_nid = 0;
3729 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3730 spec->input_mux = &ad1984_thinkpad_capture_source;
3731 spec->mixers[0] = ad1984_thinkpad_mixers;
3732 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
3733 spec->analog_beep = 1;
3735 case AD1984_DELL_DESKTOP:
3736 spec->multiout.dig_out_nid = 0;
3737 spec->input_mux = &ad1984_dell_desktop_capture_source;
3738 spec->mixers[0] = ad1984_dell_desktop_mixers;
3746 * AD1883 / AD1884A / AD1984A / AD1984B
3748 * port-B (0x14) - front mic-in
3749 * port-E (0x1c) - rear mic-in
3750 * port-F (0x16) - CD / ext out
3751 * port-C (0x15) - rear line-in
3752 * port-D (0x12) - rear line-out
3753 * port-A (0x11) - front hp-out
3755 * AD1984A = AD1884A + digital-mic
3756 * AD1883 = equivalent with AD1984A
3757 * AD1984B = AD1984A + extra SPDIF-out
3760 * We share the single DAC for both HP and line-outs (see AD1884/1984).
3763 static const hda_nid_t ad1884a_dac_nids[1] = {
3767 #define ad1884a_adc_nids ad1884_adc_nids
3768 #define ad1884a_capsrc_nids ad1884_capsrc_nids
3770 #define AD1884A_SPDIF_OUT 0x02
3772 static const struct hda_input_mux ad1884a_capture_source = {
3775 { "Front Mic", 0x0 },
3783 static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
3784 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3785 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3786 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3787 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3788 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3789 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3790 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3791 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3792 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3793 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3794 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3795 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3796 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3797 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3798 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3799 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3800 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3801 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
3802 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3803 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3804 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3805 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3806 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3808 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3809 /* The multiple "Capture Source" controls confuse alsamixer
3810 * So call somewhat different..
3812 /* .name = "Capture Source", */
3813 .name = "Input Source",
3815 .info = ad198x_mux_enum_info,
3816 .get = ad198x_mux_enum_get,
3817 .put = ad198x_mux_enum_put,
3819 /* SPDIF controls */
3820 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3822 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3823 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3824 /* identical with ad1983 */
3825 .info = ad1983_spdif_route_info,
3826 .get = ad1983_spdif_route_get,
3827 .put = ad1983_spdif_route_put,
3833 * initialization verbs
3835 static const struct hda_verb ad1884a_init_verbs[] = {
3836 /* DACs; unmute as default */
3837 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3838 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3839 /* Port-A (HP) mixer - route only from analog mixer */
3840 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3841 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3843 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3844 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3845 /* Port-D (Line-out) mixer - route only from analog mixer */
3846 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3847 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3849 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3850 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3851 /* Mono-out mixer - route only from analog mixer */
3852 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3853 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3855 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3856 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3857 /* Port-B (front mic) pin */
3858 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3859 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3860 /* Port-C (rear line-in) pin */
3861 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3862 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3863 /* Port-E (rear mic) pin */
3864 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3865 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3866 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
3867 /* Port-F (CD) pin */
3868 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3869 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3870 /* Analog mixer; mute as default */
3871 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3872 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3873 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3874 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3875 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
3876 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3877 /* Analog Mix output amp */
3878 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3879 /* capture sources */
3880 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
3881 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3882 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
3883 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3884 /* SPDIF output amp */
3885 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3890 static const struct hda_amp_list ad1884a_loopbacks[] = {
3891 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3892 { 0x20, HDA_INPUT, 1 }, /* Mic */
3893 { 0x20, HDA_INPUT, 2 }, /* CD */
3894 { 0x20, HDA_INPUT, 4 }, /* Docking */
3902 * Port A: Headphone jack
3904 * Port C: Internal MIC
3905 * Port D: Dock Line Out (if enabled)
3906 * Port E: Dock Line In (if enabled)
3907 * Port F: Internal speakers
3910 static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
3911 struct snd_ctl_elem_value *ucontrol)
3913 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3914 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3915 int mute = (!ucontrol->value.integer.value[0] &&
3916 !ucontrol->value.integer.value[1]);
3917 /* toggle GPIO1 according to the mute state */
3918 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
3923 static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
3924 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3926 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3927 .name = "Master Playback Switch",
3928 .subdevice = HDA_SUBDEV_AMP_FLAG,
3929 .info = snd_hda_mixer_amp_switch_info,
3930 .get = snd_hda_mixer_amp_switch_get,
3931 .put = ad1884a_mobile_master_sw_put,
3932 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3934 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3935 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3936 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3937 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3938 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3939 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3940 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3941 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3942 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3943 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3944 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3945 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3946 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3947 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3951 static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
3952 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3953 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
3955 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3956 .name = "Master Playback Switch",
3957 .subdevice = HDA_SUBDEV_AMP_FLAG,
3958 .info = snd_hda_mixer_amp_switch_info,
3959 .get = snd_hda_mixer_amp_switch_get,
3960 .put = ad1884a_mobile_master_sw_put,
3961 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3963 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3964 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3965 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
3966 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
3967 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3968 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3972 /* mute internal speaker if HP is plugged */
3973 static void ad1884a_hp_automute(struct hda_codec *codec)
3975 unsigned int present;
3977 present = snd_hda_jack_detect(codec, 0x11);
3978 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3979 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3980 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3981 present ? 0x00 : 0x02);
3984 /* switch to external mic if plugged */
3985 static void ad1884a_hp_automic(struct hda_codec *codec)
3987 unsigned int present;
3989 present = snd_hda_jack_detect(codec, 0x14);
3990 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
3994 #define AD1884A_HP_EVENT 0x37
3995 #define AD1884A_MIC_EVENT 0x36
3997 /* unsolicited event for HP jack sensing */
3998 static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4000 switch (res >> 26) {
4001 case AD1884A_HP_EVENT:
4002 ad1884a_hp_automute(codec);
4004 case AD1884A_MIC_EVENT:
4005 ad1884a_hp_automic(codec);
4010 /* initialize jack-sensing, too */
4011 static int ad1884a_hp_init(struct hda_codec *codec)
4014 ad1884a_hp_automute(codec);
4015 ad1884a_hp_automic(codec);
4019 /* mute internal speaker if HP or docking HP is plugged */
4020 static void ad1884a_laptop_automute(struct hda_codec *codec)
4022 unsigned int present;
4024 present = snd_hda_jack_detect(codec, 0x11);
4026 present = snd_hda_jack_detect(codec, 0x12);
4027 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4028 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4029 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4030 present ? 0x00 : 0x02);
4033 /* switch to external mic if plugged */
4034 static void ad1884a_laptop_automic(struct hda_codec *codec)
4038 if (snd_hda_jack_detect(codec, 0x14))
4040 else if (snd_hda_jack_detect(codec, 0x1c))
4044 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
4047 /* unsolicited event for HP jack sensing */
4048 static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
4051 switch (res >> 26) {
4052 case AD1884A_HP_EVENT:
4053 ad1884a_laptop_automute(codec);
4055 case AD1884A_MIC_EVENT:
4056 ad1884a_laptop_automic(codec);
4061 /* initialize jack-sensing, too */
4062 static int ad1884a_laptop_init(struct hda_codec *codec)
4065 ad1884a_laptop_automute(codec);
4066 ad1884a_laptop_automic(codec);
4070 /* additional verbs for laptop model */
4071 static const struct hda_verb ad1884a_laptop_verbs[] = {
4072 /* Port-A (HP) pin - always unmuted */
4073 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4074 /* Port-F (int speaker) mixer - route only from analog mixer */
4075 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4076 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4077 /* Port-F (int speaker) pin */
4078 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4079 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4080 /* required for compaq 6530s/6531s speaker output */
4081 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4082 /* Port-C pin - internal mic-in */
4083 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4084 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4085 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4086 /* Port-D (docking line-out) pin - default unmuted */
4087 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4089 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4090 /* unsolicited event for pin-sense */
4091 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4092 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4093 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4094 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4095 /* allow to touch GPIO1 (for mute control) */
4096 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4097 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4098 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4102 static const struct hda_verb ad1884a_mobile_verbs[] = {
4103 /* DACs; unmute as default */
4104 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4105 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4106 /* Port-A (HP) mixer - route only from analog mixer */
4107 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4108 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4110 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4111 /* Port-A (HP) pin - always unmuted */
4112 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4113 /* Port-B (mic jack) pin */
4114 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4115 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4116 /* Port-C (int mic) pin */
4117 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4118 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4119 /* Port-F (int speaker) mixer - route only from analog mixer */
4120 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4121 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4123 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4124 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4125 /* Analog mixer; mute as default */
4126 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4127 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4128 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4129 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4130 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4131 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4132 /* Analog Mix output amp */
4133 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4134 /* capture sources */
4135 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4136 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4137 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4138 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4139 /* unsolicited event for pin-sense */
4140 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4141 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4142 /* allow to touch GPIO1 (for mute control) */
4143 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4144 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4145 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4154 * 0x17 - built-in mic
4157 static const struct hda_verb ad1984a_thinkpad_verbs[] = {
4159 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4161 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4163 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4164 /* unsolicited event for pin-sense */
4165 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4166 /* internal mic - dmic */
4167 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4168 /* set magic COEFs for dmic */
4169 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4170 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4174 static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
4175 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4176 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4177 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4178 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4179 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4180 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4181 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4182 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
4183 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4184 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4186 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4187 .name = "Capture Source",
4188 .info = ad198x_mux_enum_info,
4189 .get = ad198x_mux_enum_get,
4190 .put = ad198x_mux_enum_put,
4195 static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
4199 { "Internal Mic", 0x5 },
4204 /* mute internal speaker if HP is plugged */
4205 static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4207 unsigned int present;
4209 present = snd_hda_jack_detect(codec, 0x11);
4210 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4211 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4214 /* unsolicited event for HP jack sensing */
4215 static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4218 if ((res >> 26) != AD1884A_HP_EVENT)
4220 ad1984a_thinkpad_automute(codec);
4223 /* initialize jack-sensing, too */
4224 static int ad1984a_thinkpad_init(struct hda_codec *codec)
4227 ad1984a_thinkpad_automute(codec);
4233 * 0x12 - HP/line-out
4234 * 0x13 - speaker (mono)
4238 static const struct hda_verb ad1984a_precision_verbs[] = {
4239 /* Unmute main output path */
4240 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4241 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
4242 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */
4243 /* Analog mixer; mute as default */
4244 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4245 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4246 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4247 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4248 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4249 /* Select mic as input */
4250 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
4251 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */
4252 /* Configure as mic */
4253 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4254 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4256 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4258 {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4259 /* unsolicited event for pin-sense */
4260 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4264 static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
4265 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4266 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4267 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4268 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4269 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4270 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4271 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
4272 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4273 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT),
4274 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4275 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4280 /* mute internal speaker if HP is plugged */
4281 static void ad1984a_precision_automute(struct hda_codec *codec)
4283 unsigned int present;
4285 present = snd_hda_jack_detect(codec, 0x12);
4286 snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
4287 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4291 /* unsolicited event for HP jack sensing */
4292 static void ad1984a_precision_unsol_event(struct hda_codec *codec,
4295 if ((res >> 26) != AD1884A_HP_EVENT)
4297 ad1984a_precision_automute(codec);
4300 /* initialize jack-sensing, too */
4301 static int ad1984a_precision_init(struct hda_codec *codec)
4304 ad1984a_precision_automute(codec);
4311 * port-A (0x11) - front hp-out
4312 * port-B (0x14) - unused
4313 * port-C (0x15) - unused
4314 * port-D (0x12) - rear line out
4315 * port-E (0x1c) - front mic-in
4316 * port-F (0x16) - Internal speakers
4317 * digital-mic (0x17) - Internal mic
4320 static const struct hda_verb ad1984a_touchsmart_verbs[] = {
4321 /* DACs; unmute as default */
4322 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4323 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4324 /* Port-A (HP) mixer - route only from analog mixer */
4325 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4326 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4328 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4329 /* Port-A (HP) pin - always unmuted */
4330 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4331 /* Port-E (int speaker) mixer - route only from analog mixer */
4332 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4334 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4335 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4336 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4337 /* Port-F (int speaker) mixer - route only from analog mixer */
4338 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4339 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4341 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4342 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4343 /* Analog mixer; mute as default */
4344 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4345 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4346 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4347 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4348 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4349 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4350 /* Analog Mix output amp */
4351 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4352 /* capture sources */
4353 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4354 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4355 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4356 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4357 /* unsolicited event for pin-sense */
4358 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4359 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4360 /* allow to touch GPIO1 (for mute control) */
4361 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4362 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4363 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4364 /* internal mic - dmic */
4365 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4366 /* set magic COEFs for dmic */
4367 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4368 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4372 static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
4373 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4374 /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4376 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4377 .subdevice = HDA_SUBDEV_AMP_FLAG,
4378 .name = "Master Playback Switch",
4379 .info = snd_hda_mixer_amp_switch_info,
4380 .get = snd_hda_mixer_amp_switch_get,
4381 .put = ad1884a_mobile_master_sw_put,
4382 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4384 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4385 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4386 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4387 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4388 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
4389 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
4393 /* switch to external mic if plugged */
4394 static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4396 if (snd_hda_jack_detect(codec, 0x1c))
4397 snd_hda_codec_write(codec, 0x0c, 0,
4398 AC_VERB_SET_CONNECT_SEL, 0x4);
4400 snd_hda_codec_write(codec, 0x0c, 0,
4401 AC_VERB_SET_CONNECT_SEL, 0x5);
4405 /* unsolicited event for HP jack sensing */
4406 static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4409 switch (res >> 26) {
4410 case AD1884A_HP_EVENT:
4411 ad1884a_hp_automute(codec);
4413 case AD1884A_MIC_EVENT:
4414 ad1984a_touchsmart_automic(codec);
4419 /* initialize jack-sensing, too */
4420 static int ad1984a_touchsmart_init(struct hda_codec *codec)
4423 ad1884a_hp_automute(codec);
4424 ad1984a_touchsmart_automic(codec);
4443 static const char * const ad1884a_models[AD1884A_MODELS] = {
4444 [AD1884A_AUTO] = "auto",
4445 [AD1884A_DESKTOP] = "desktop",
4446 [AD1884A_LAPTOP] = "laptop",
4447 [AD1884A_MOBILE] = "mobile",
4448 [AD1884A_THINKPAD] = "thinkpad",
4449 [AD1984A_TOUCHSMART] = "touchsmart",
4450 [AD1984A_PRECISION] = "precision",
4453 static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
4454 SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
4455 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
4456 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
4457 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
4458 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
4459 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
4460 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4461 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
4462 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
4463 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
4464 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
4468 static int patch_ad1884a(struct hda_codec *codec)
4470 struct ad198x_spec *spec;
4471 int err, board_config;
4473 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
4476 if (board_config == AD1884_AUTO)
4477 return patch_ad1884_auto(codec);
4479 err = alloc_ad_spec(codec);
4484 err = snd_hda_attach_beep_device(codec, 0x10);
4489 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4491 spec->multiout.max_channels = 2;
4492 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4493 spec->multiout.dac_nids = ad1884a_dac_nids;
4494 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4495 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4496 spec->adc_nids = ad1884a_adc_nids;
4497 spec->capsrc_nids = ad1884a_capsrc_nids;
4498 spec->input_mux = &ad1884a_capture_source;
4499 spec->num_mixers = 1;
4500 spec->mixers[0] = ad1884a_base_mixers;
4501 spec->num_init_verbs = 1;
4502 spec->init_verbs[0] = ad1884a_init_verbs;
4503 spec->spdif_route = 0;
4505 spec->loopback.amplist = ad1884a_loopbacks;
4507 codec->patch_ops = ad198x_patch_ops;
4509 /* override some parameters */
4510 switch (board_config) {
4511 case AD1884A_LAPTOP:
4512 spec->mixers[0] = ad1884a_laptop_mixers;
4513 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4514 spec->multiout.dig_out_nid = 0;
4515 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4516 codec->patch_ops.init = ad1884a_laptop_init;
4517 /* set the upper-limit for mixer amp to 0dB for avoiding the
4518 * possible damage by overloading
4520 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4521 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4522 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4523 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4524 (1 << AC_AMPCAP_MUTE_SHIFT));
4526 case AD1884A_MOBILE:
4527 spec->mixers[0] = ad1884a_mobile_mixers;
4528 spec->init_verbs[0] = ad1884a_mobile_verbs;
4529 spec->multiout.dig_out_nid = 0;
4530 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4531 codec->patch_ops.init = ad1884a_hp_init;
4532 /* set the upper-limit for mixer amp to 0dB for avoiding the
4533 * possible damage by overloading
4535 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4536 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4537 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4538 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4539 (1 << AC_AMPCAP_MUTE_SHIFT));
4541 case AD1884A_THINKPAD:
4542 spec->mixers[0] = ad1984a_thinkpad_mixers;
4543 spec->init_verbs[spec->num_init_verbs++] =
4544 ad1984a_thinkpad_verbs;
4545 spec->multiout.dig_out_nid = 0;
4546 spec->input_mux = &ad1984a_thinkpad_capture_source;
4547 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4548 codec->patch_ops.init = ad1984a_thinkpad_init;
4550 case AD1984A_PRECISION:
4551 spec->mixers[0] = ad1984a_precision_mixers;
4552 spec->init_verbs[spec->num_init_verbs++] =
4553 ad1984a_precision_verbs;
4554 spec->multiout.dig_out_nid = 0;
4555 codec->patch_ops.unsol_event = ad1984a_precision_unsol_event;
4556 codec->patch_ops.init = ad1984a_precision_init;
4558 case AD1984A_TOUCHSMART:
4559 spec->mixers[0] = ad1984a_touchsmart_mixers;
4560 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4561 spec->multiout.dig_out_nid = 0;
4562 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4563 codec->patch_ops.init = ad1984a_touchsmart_init;
4564 /* set the upper-limit for mixer amp to 0dB for avoiding the
4565 * possible damage by overloading
4567 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4568 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4569 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4570 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4571 (1 << AC_AMPCAP_MUTE_SHIFT));
4575 codec->no_trigger_sense = 1;
4576 codec->no_sticky_stream = 1;
4585 * port-A - front hp-out
4586 * port-B - front mic-in
4587 * port-C - rear line-in, shared surr-out (3stack)
4588 * port-D - rear line-out
4589 * port-E - rear mic-in, shared clfe-out (3stack)
4590 * port-F - rear surr-out (6stack)
4591 * port-G - rear clfe-out (6stack)
4594 static const hda_nid_t ad1882_dac_nids[3] = {
4598 static const hda_nid_t ad1882_adc_nids[2] = {
4602 static const hda_nid_t ad1882_capsrc_nids[2] = {
4606 #define AD1882_SPDIF_OUT 0x02
4608 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
4609 static const struct hda_input_mux ad1882_capture_source = {
4612 { "Front Mic", 0x1 },
4620 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
4621 static const struct hda_input_mux ad1882a_capture_source = {
4624 { "Front Mic", 0x1 },
4627 { "Digital Mic", 0x06 },
4632 static const struct snd_kcontrol_new ad1882_base_mixers[] = {
4633 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4634 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4635 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4636 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4637 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4638 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4639 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4640 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
4642 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
4643 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
4644 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
4645 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4646 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4647 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4648 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4650 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4651 /* The multiple "Capture Source" controls confuse alsamixer
4652 * So call somewhat different..
4654 /* .name = "Capture Source", */
4655 .name = "Input Source",
4657 .info = ad198x_mux_enum_info,
4658 .get = ad198x_mux_enum_get,
4659 .put = ad198x_mux_enum_put,
4661 /* SPDIF controls */
4662 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4664 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4665 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4666 /* identical with ad1983 */
4667 .info = ad1983_spdif_route_info,
4668 .get = ad1983_spdif_route_get,
4669 .put = ad1983_spdif_route_put,
4674 static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4675 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4676 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4677 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4678 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4679 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4680 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4681 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4682 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4686 static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4687 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4688 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4689 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4690 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4691 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4692 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4693 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4694 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4695 HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
4699 static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4700 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4701 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4702 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4704 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4705 .name = "Channel Mode",
4706 .info = ad198x_ch_mode_info,
4707 .get = ad198x_ch_mode_get,
4708 .put = ad198x_ch_mode_put,
4713 /* simple auto-mute control for AD1882 3-stack board */
4714 #define AD1882_HP_EVENT 0x01
4716 static void ad1882_3stack_automute(struct hda_codec *codec)
4718 bool mute = snd_hda_jack_detect(codec, 0x11);
4719 snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
4720 mute ? 0 : PIN_OUT);
4723 static int ad1882_3stack_automute_init(struct hda_codec *codec)
4726 ad1882_3stack_automute(codec);
4730 static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res)
4732 switch (res >> 26) {
4733 case AD1882_HP_EVENT:
4734 ad1882_3stack_automute(codec);
4739 static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4740 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4741 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4742 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4746 static const struct hda_verb ad1882_ch2_init[] = {
4747 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4748 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4749 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4750 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4751 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4752 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4756 static const struct hda_verb ad1882_ch4_init[] = {
4757 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4758 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4759 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4760 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4761 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4762 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4766 static const struct hda_verb ad1882_ch6_init[] = {
4767 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4768 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4769 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4770 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4771 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4772 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4776 static const struct hda_channel_mode ad1882_modes[3] = {
4777 { 2, ad1882_ch2_init },
4778 { 4, ad1882_ch4_init },
4779 { 6, ad1882_ch6_init },
4783 * initialization verbs
4785 static const struct hda_verb ad1882_init_verbs[] = {
4786 /* DACs; mute as default */
4787 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4788 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4789 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4790 /* Port-A (HP) mixer */
4791 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4792 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4794 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4795 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4796 /* HP selector - select DAC2 */
4797 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4798 /* Port-D (Line-out) mixer */
4799 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4800 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4802 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4803 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4804 /* Mono-out mixer */
4805 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4806 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4808 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4809 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4810 /* Port-B (front mic) pin */
4811 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4812 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4813 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4814 /* Port-C (line-in) pin */
4815 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4816 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4817 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4818 /* Port-C mixer - mute as input */
4819 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4820 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4821 /* Port-E (mic-in) pin */
4822 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4823 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4824 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4825 /* Port-E mixer - mute as input */
4826 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4827 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4828 /* Port-F (surround) */
4829 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4830 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4832 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4833 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4834 /* Analog mixer; mute as default */
4835 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
4836 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4837 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4838 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4839 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4840 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4841 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4842 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4843 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4844 /* Analog Mix output amp */
4845 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
4846 /* SPDIF output selector */
4847 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4848 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
4849 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4853 static const struct hda_verb ad1882_3stack_automute_verbs[] = {
4854 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT},
4859 static const struct hda_amp_list ad1882_loopbacks[] = {
4860 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4861 { 0x20, HDA_INPUT, 1 }, /* Mic */
4862 { 0x20, HDA_INPUT, 4 }, /* Line */
4863 { 0x20, HDA_INPUT, 6 }, /* CD */
4873 AD1882_3STACK_AUTOMUTE,
4877 static const char * const ad1882_models[AD1986A_MODELS] = {
4878 [AD1882_AUTO] = "auto",
4879 [AD1882_3STACK] = "3stack",
4880 [AD1882_6STACK] = "6stack",
4881 [AD1882_3STACK_AUTOMUTE] = "3stack-automute",
4884 static int ad1882_parse_auto_config(struct hda_codec *codec)
4886 struct ad198x_spec *spec = codec->spec;
4889 spec->gen.mixer_nid = 0x20;
4890 spec->beep_dev_nid = 0x10;
4891 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4892 err = ad198x_parse_auto_config(codec);
4895 err = ad1988_add_spdif_mux_ctl(codec);
4901 static int patch_ad1882(struct hda_codec *codec)
4903 struct ad198x_spec *spec;
4904 int err, board_config;
4906 err = alloc_ad_spec(codec);
4911 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
4912 ad1882_models, NULL);
4913 if (board_config == AD1882_AUTO) {
4914 err = ad1882_parse_auto_config(codec);
4922 err = snd_hda_attach_beep_device(codec, 0x10);
4927 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4929 spec->multiout.max_channels = 6;
4930 spec->multiout.num_dacs = 3;
4931 spec->multiout.dac_nids = ad1882_dac_nids;
4932 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
4933 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
4934 spec->adc_nids = ad1882_adc_nids;
4935 spec->capsrc_nids = ad1882_capsrc_nids;
4936 if (codec->vendor_id == 0x11d41882)
4937 spec->input_mux = &ad1882_capture_source;
4939 spec->input_mux = &ad1882a_capture_source;
4940 spec->num_mixers = 2;
4941 spec->mixers[0] = ad1882_base_mixers;
4942 if (codec->vendor_id == 0x11d41882)
4943 spec->mixers[1] = ad1882_loopback_mixers;
4945 spec->mixers[1] = ad1882a_loopback_mixers;
4946 spec->num_init_verbs = 1;
4947 spec->init_verbs[0] = ad1882_init_verbs;
4948 spec->spdif_route = 0;
4950 spec->loopback.amplist = ad1882_loopbacks;
4952 spec->vmaster_nid = 0x04;
4954 codec->patch_ops = ad198x_patch_ops;
4956 /* override some parameters */
4957 switch (board_config) {
4960 case AD1882_3STACK_AUTOMUTE:
4961 spec->num_mixers = 3;
4962 spec->mixers[2] = ad1882_3stack_mixers;
4963 spec->channel_mode = ad1882_modes;
4964 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
4965 spec->need_dac_fix = 1;
4966 spec->multiout.max_channels = 2;
4967 spec->multiout.num_dacs = 1;
4968 if (board_config != AD1882_3STACK) {
4969 spec->init_verbs[spec->num_init_verbs++] =
4970 ad1882_3stack_automute_verbs;
4971 codec->patch_ops.unsol_event = ad1882_3stack_unsol_event;
4972 codec->patch_ops.init = ad1882_3stack_automute_init;
4976 spec->num_mixers = 3;
4977 spec->mixers[2] = ad1882_6stack_mixers;
4981 codec->no_trigger_sense = 1;
4982 codec->no_sticky_stream = 1;
4991 static const struct hda_codec_preset snd_hda_preset_analog[] = {
4992 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
4993 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
4994 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
4995 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
4996 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
4997 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
4998 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
4999 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
5000 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
5001 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
5002 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
5003 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
5004 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
5005 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
5006 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
5010 MODULE_ALIAS("snd-hda-codec-id:11d4*");
5012 MODULE_LICENSE("GPL");
5013 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
5015 static struct hda_codec_preset_list analog_list = {
5016 .preset = snd_hda_preset_analog,
5017 .owner = THIS_MODULE,
5020 static int __init patch_analog_init(void)
5022 return snd_hda_add_codec_preset(&analog_list);
5025 static void __exit patch_analog_exit(void)
5027 snd_hda_delete_codec_preset(&analog_list);
5030 module_init(patch_analog_init)
5031 module_exit(patch_analog_exit)