Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-btrfs-devel.git] / sound / pci / hda / patch_analog.c
blob8648917acffb57f3af713ef7e9f57828e04b8ef4
1 /*
2 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
3 * AD1986A, AD1988
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/delay.h>
24 #include <linux/slab.h>
25 #include <linux/pci.h>
27 #include <sound/core.h>
28 #include "hda_codec.h"
29 #include "hda_local.h"
30 #include "hda_beep.h"
32 struct ad198x_spec {
33 const struct snd_kcontrol_new *mixers[6];
34 int num_mixers;
35 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
36 const struct hda_verb *init_verbs[6]; /* initialization verbs
37 * don't forget NULL termination!
39 unsigned int num_init_verbs;
41 /* playback */
42 struct hda_multi_out multiout; /* playback set-up
43 * max_channels, dacs must be set
44 * dig_out_nid and hp_nid are optional
46 unsigned int cur_eapd;
47 unsigned int need_dac_fix;
49 const hda_nid_t *alt_dac_nid;
50 const struct hda_pcm_stream *stream_analog_alt_playback;
52 /* capture */
53 unsigned int num_adc_nids;
54 const hda_nid_t *adc_nids;
55 hda_nid_t dig_in_nid; /* digital-in NID; optional */
57 /* capture source */
58 const struct hda_input_mux *input_mux;
59 const hda_nid_t *capsrc_nids;
60 unsigned int cur_mux[3];
62 /* channel model */
63 const struct hda_channel_mode *channel_mode;
64 int num_channel_mode;
66 /* PCM information */
67 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
69 unsigned int spdif_route;
71 /* dynamic controls, init_verbs and input_mux */
72 struct auto_pin_cfg autocfg;
73 struct snd_array kctls;
74 struct hda_input_mux private_imux;
75 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
77 unsigned int jack_present: 1;
78 unsigned int inv_jack_detect: 1;/* inverted jack-detection */
79 unsigned int inv_eapd: 1; /* inverted EAPD implementation */
80 unsigned int analog_beep: 1; /* analog beep input present */
82 #ifdef CONFIG_SND_HDA_POWER_SAVE
83 struct hda_loopback_check loopback;
84 #endif
85 /* for virtual master */
86 hda_nid_t vmaster_nid;
87 const char * const *slave_vols;
88 const char * const *slave_sws;
92 * input MUX handling (common part)
94 static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
96 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
97 struct ad198x_spec *spec = codec->spec;
99 return snd_hda_input_mux_info(spec->input_mux, uinfo);
102 static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
104 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
105 struct ad198x_spec *spec = codec->spec;
106 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
108 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
109 return 0;
112 static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
114 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
115 struct ad198x_spec *spec = codec->spec;
116 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
118 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
119 spec->capsrc_nids[adc_idx],
120 &spec->cur_mux[adc_idx]);
124 * initialization (common callbacks)
126 static int ad198x_init(struct hda_codec *codec)
128 struct ad198x_spec *spec = codec->spec;
129 int i;
131 for (i = 0; i < spec->num_init_verbs; i++)
132 snd_hda_sequence_write(codec, spec->init_verbs[i]);
133 return 0;
136 static const char * const ad_slave_vols[] = {
137 "Front Playback Volume",
138 "Surround Playback Volume",
139 "Center Playback Volume",
140 "LFE Playback Volume",
141 "Side Playback Volume",
142 "Headphone Playback Volume",
143 "Mono Playback Volume",
144 "Speaker Playback Volume",
145 "IEC958 Playback Volume",
146 NULL
149 static const char * const ad_slave_sws[] = {
150 "Front Playback Switch",
151 "Surround Playback Switch",
152 "Center Playback Switch",
153 "LFE Playback Switch",
154 "Side Playback Switch",
155 "Headphone Playback Switch",
156 "Mono Playback Switch",
157 "Speaker Playback Switch",
158 "IEC958 Playback Switch",
159 NULL
162 static const char * const ad1988_6stack_fp_slave_vols[] = {
163 "Front Playback Volume",
164 "Surround Playback Volume",
165 "Center Playback Volume",
166 "LFE Playback Volume",
167 "Side Playback Volume",
168 "IEC958 Playback Volume",
169 NULL
172 static const char * const ad1988_6stack_fp_slave_sws[] = {
173 "Front Playback Switch",
174 "Surround Playback Switch",
175 "Center Playback Switch",
176 "LFE Playback Switch",
177 "Side Playback Switch",
178 "IEC958 Playback Switch",
179 NULL
181 static void ad198x_free_kctls(struct hda_codec *codec);
183 #ifdef CONFIG_SND_HDA_INPUT_BEEP
184 /* additional beep mixers; the actual parameters are overwritten at build */
185 static const struct snd_kcontrol_new ad_beep_mixer[] = {
186 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
187 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
188 { } /* end */
191 static const struct snd_kcontrol_new ad_beep2_mixer[] = {
192 HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
193 HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
194 { } /* end */
197 #define set_beep_amp(spec, nid, idx, dir) \
198 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
199 #else
200 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
201 #endif
203 static int ad198x_build_controls(struct hda_codec *codec)
205 struct ad198x_spec *spec = codec->spec;
206 struct snd_kcontrol *kctl;
207 unsigned int i;
208 int err;
210 for (i = 0; i < spec->num_mixers; i++) {
211 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
212 if (err < 0)
213 return err;
215 if (spec->multiout.dig_out_nid) {
216 err = snd_hda_create_spdif_out_ctls(codec,
217 spec->multiout.dig_out_nid,
218 spec->multiout.dig_out_nid);
219 if (err < 0)
220 return err;
221 err = snd_hda_create_spdif_share_sw(codec,
222 &spec->multiout);
223 if (err < 0)
224 return err;
225 spec->multiout.share_spdif = 1;
227 if (spec->dig_in_nid) {
228 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
229 if (err < 0)
230 return err;
233 /* create beep controls if needed */
234 #ifdef CONFIG_SND_HDA_INPUT_BEEP
235 if (spec->beep_amp) {
236 const struct snd_kcontrol_new *knew;
237 knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
238 for ( ; knew->name; knew++) {
239 struct snd_kcontrol *kctl;
240 kctl = snd_ctl_new1(knew, codec);
241 if (!kctl)
242 return -ENOMEM;
243 kctl->private_value = spec->beep_amp;
244 err = snd_hda_ctl_add(codec, 0, kctl);
245 if (err < 0)
246 return err;
249 #endif
251 /* if we have no master control, let's create it */
252 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
253 unsigned int vmaster_tlv[4];
254 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
255 HDA_OUTPUT, vmaster_tlv);
256 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
257 vmaster_tlv,
258 (spec->slave_vols ?
259 spec->slave_vols : ad_slave_vols));
260 if (err < 0)
261 return err;
263 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
264 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
265 NULL,
266 (spec->slave_sws ?
267 spec->slave_sws : ad_slave_sws));
268 if (err < 0)
269 return err;
272 ad198x_free_kctls(codec); /* no longer needed */
274 /* assign Capture Source enums to NID */
275 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
276 if (!kctl)
277 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
278 for (i = 0; kctl && i < kctl->count; i++) {
279 err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
280 if (err < 0)
281 return err;
284 /* assign IEC958 enums to NID */
285 kctl = snd_hda_find_mixer_ctl(codec,
286 SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
287 if (kctl) {
288 err = snd_hda_add_nid(codec, kctl, 0,
289 spec->multiout.dig_out_nid);
290 if (err < 0)
291 return err;
294 return 0;
297 #ifdef CONFIG_SND_HDA_POWER_SAVE
298 static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
300 struct ad198x_spec *spec = codec->spec;
301 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
303 #endif
306 * Analog playback callbacks
308 static int ad198x_playback_pcm_open(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_open(codec, &spec->multiout, substream,
314 hinfo);
317 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
318 struct hda_codec *codec,
319 unsigned int stream_tag,
320 unsigned int format,
321 struct snd_pcm_substream *substream)
323 struct ad198x_spec *spec = codec->spec;
324 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
325 format, substream);
328 static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
329 struct hda_codec *codec,
330 struct snd_pcm_substream *substream)
332 struct ad198x_spec *spec = codec->spec;
333 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
336 static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
337 .substreams = 1,
338 .channels_min = 2,
339 .channels_max = 2,
340 /* NID is set in ad198x_build_pcms */
344 * Digital out
346 static int ad198x_dig_playback_pcm_open(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_open(codec, &spec->multiout);
354 static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
355 struct hda_codec *codec,
356 struct snd_pcm_substream *substream)
358 struct ad198x_spec *spec = codec->spec;
359 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
362 static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
363 struct hda_codec *codec,
364 unsigned int stream_tag,
365 unsigned int format,
366 struct snd_pcm_substream *substream)
368 struct ad198x_spec *spec = codec->spec;
369 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
370 format, substream);
373 static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
374 struct hda_codec *codec,
375 struct snd_pcm_substream *substream)
377 struct ad198x_spec *spec = codec->spec;
378 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
382 * Analog capture
384 static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
385 struct hda_codec *codec,
386 unsigned int stream_tag,
387 unsigned int format,
388 struct snd_pcm_substream *substream)
390 struct ad198x_spec *spec = codec->spec;
391 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
392 stream_tag, 0, format);
393 return 0;
396 static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
397 struct hda_codec *codec,
398 struct snd_pcm_substream *substream)
400 struct ad198x_spec *spec = codec->spec;
401 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
402 return 0;
408 static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
409 .substreams = 1,
410 .channels_min = 2,
411 .channels_max = 6, /* changed later */
412 .nid = 0, /* fill later */
413 .ops = {
414 .open = ad198x_playback_pcm_open,
415 .prepare = ad198x_playback_pcm_prepare,
416 .cleanup = ad198x_playback_pcm_cleanup
420 static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
421 .substreams = 1,
422 .channels_min = 2,
423 .channels_max = 2,
424 .nid = 0, /* fill later */
425 .ops = {
426 .prepare = ad198x_capture_pcm_prepare,
427 .cleanup = ad198x_capture_pcm_cleanup
431 static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
432 .substreams = 1,
433 .channels_min = 2,
434 .channels_max = 2,
435 .nid = 0, /* fill later */
436 .ops = {
437 .open = ad198x_dig_playback_pcm_open,
438 .close = ad198x_dig_playback_pcm_close,
439 .prepare = ad198x_dig_playback_pcm_prepare,
440 .cleanup = ad198x_dig_playback_pcm_cleanup
444 static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
445 .substreams = 1,
446 .channels_min = 2,
447 .channels_max = 2,
448 /* NID is set in alc_build_pcms */
451 static int ad198x_build_pcms(struct hda_codec *codec)
453 struct ad198x_spec *spec = codec->spec;
454 struct hda_pcm *info = spec->pcm_rec;
456 codec->num_pcms = 1;
457 codec->pcm_info = info;
459 info->name = "AD198x Analog";
460 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
461 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
462 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
463 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
464 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
465 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
467 if (spec->multiout.dig_out_nid) {
468 info++;
469 codec->num_pcms++;
470 info->name = "AD198x Digital";
471 info->pcm_type = HDA_PCM_TYPE_SPDIF;
472 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
473 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
474 if (spec->dig_in_nid) {
475 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
476 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
480 if (spec->alt_dac_nid && spec->stream_analog_alt_playback) {
481 codec->num_pcms++;
482 info = spec->pcm_rec + 2;
483 info->name = "AD198x Headphone";
484 info->pcm_type = HDA_PCM_TYPE_AUDIO;
485 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
486 *spec->stream_analog_alt_playback;
487 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
488 spec->alt_dac_nid[0];
491 return 0;
494 static void ad198x_free_kctls(struct hda_codec *codec)
496 struct ad198x_spec *spec = codec->spec;
498 if (spec->kctls.list) {
499 struct snd_kcontrol_new *kctl = spec->kctls.list;
500 int i;
501 for (i = 0; i < spec->kctls.used; i++)
502 kfree(kctl[i].name);
504 snd_array_free(&spec->kctls);
507 static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
508 hda_nid_t hp)
510 struct ad198x_spec *spec = codec->spec;
511 if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
512 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
513 !spec->inv_eapd ? 0x00 : 0x02);
514 if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
515 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
516 !spec->inv_eapd ? 0x00 : 0x02);
519 static void ad198x_power_eapd(struct hda_codec *codec)
521 /* We currently only handle front, HP */
522 switch (codec->vendor_id) {
523 case 0x11d41882:
524 case 0x11d4882a:
525 case 0x11d41884:
526 case 0x11d41984:
527 case 0x11d41883:
528 case 0x11d4184a:
529 case 0x11d4194a:
530 case 0x11d4194b:
531 case 0x11d41988:
532 case 0x11d4198b:
533 case 0x11d4989a:
534 case 0x11d4989b:
535 ad198x_power_eapd_write(codec, 0x12, 0x11);
536 break;
537 case 0x11d41981:
538 case 0x11d41983:
539 ad198x_power_eapd_write(codec, 0x05, 0x06);
540 break;
541 case 0x11d41986:
542 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
543 break;
547 static void ad198x_shutup(struct hda_codec *codec)
549 snd_hda_shutup_pins(codec);
550 ad198x_power_eapd(codec);
553 static void ad198x_free(struct hda_codec *codec)
555 struct ad198x_spec *spec = codec->spec;
557 if (!spec)
558 return;
560 ad198x_shutup(codec);
561 ad198x_free_kctls(codec);
562 kfree(spec);
563 snd_hda_detach_beep_device(codec);
566 #ifdef CONFIG_PM
567 static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
569 ad198x_shutup(codec);
570 return 0;
572 #endif
574 static const struct hda_codec_ops ad198x_patch_ops = {
575 .build_controls = ad198x_build_controls,
576 .build_pcms = ad198x_build_pcms,
577 .init = ad198x_init,
578 .free = ad198x_free,
579 #ifdef CONFIG_SND_HDA_POWER_SAVE
580 .check_power_status = ad198x_check_power_status,
581 #endif
582 #ifdef CONFIG_PM
583 .suspend = ad198x_suspend,
584 #endif
585 .reboot_notify = ad198x_shutup,
590 * EAPD control
591 * the private value = nid
593 #define ad198x_eapd_info snd_ctl_boolean_mono_info
595 static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
596 struct snd_ctl_elem_value *ucontrol)
598 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
599 struct ad198x_spec *spec = codec->spec;
600 if (spec->inv_eapd)
601 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
602 else
603 ucontrol->value.integer.value[0] = spec->cur_eapd;
604 return 0;
607 static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
608 struct snd_ctl_elem_value *ucontrol)
610 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
611 struct ad198x_spec *spec = codec->spec;
612 hda_nid_t nid = kcontrol->private_value & 0xff;
613 unsigned int eapd;
614 eapd = !!ucontrol->value.integer.value[0];
615 if (spec->inv_eapd)
616 eapd = !eapd;
617 if (eapd == spec->cur_eapd)
618 return 0;
619 spec->cur_eapd = eapd;
620 snd_hda_codec_write_cache(codec, nid,
621 0, AC_VERB_SET_EAPD_BTLENABLE,
622 eapd ? 0x02 : 0x00);
623 return 1;
626 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
627 struct snd_ctl_elem_info *uinfo);
628 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
629 struct snd_ctl_elem_value *ucontrol);
630 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
631 struct snd_ctl_elem_value *ucontrol);
635 * AD1986A specific
638 #define AD1986A_SPDIF_OUT 0x02
639 #define AD1986A_FRONT_DAC 0x03
640 #define AD1986A_SURR_DAC 0x04
641 #define AD1986A_CLFE_DAC 0x05
642 #define AD1986A_ADC 0x06
644 static const hda_nid_t ad1986a_dac_nids[3] = {
645 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
647 static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
648 static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
650 static const struct hda_input_mux ad1986a_capture_source = {
651 .num_items = 7,
652 .items = {
653 { "Mic", 0x0 },
654 { "CD", 0x1 },
655 { "Aux", 0x3 },
656 { "Line", 0x4 },
657 { "Mix", 0x5 },
658 { "Mono", 0x6 },
659 { "Phone", 0x7 },
664 static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
665 .ops = &snd_hda_bind_vol,
666 .values = {
667 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
668 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
669 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
674 static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
675 .ops = &snd_hda_bind_sw,
676 .values = {
677 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
678 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
679 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
685 * mixers
687 static const struct snd_kcontrol_new ad1986a_mixers[] = {
689 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
691 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
692 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
693 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
694 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
695 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
696 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
697 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
698 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
699 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
700 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
701 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
702 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
703 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
704 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
705 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
706 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
707 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
708 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
709 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
710 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
711 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
712 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
713 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
714 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
715 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
717 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
718 .name = "Capture Source",
719 .info = ad198x_mux_enum_info,
720 .get = ad198x_mux_enum_get,
721 .put = ad198x_mux_enum_put,
723 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
724 { } /* end */
727 /* additional mixers for 3stack mode */
728 static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
730 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
731 .name = "Channel Mode",
732 .info = ad198x_ch_mode_info,
733 .get = ad198x_ch_mode_get,
734 .put = ad198x_ch_mode_put,
736 { } /* end */
739 /* laptop model - 2ch only */
740 static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
742 /* master controls both pins 0x1a and 0x1b */
743 static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
744 .ops = &snd_hda_bind_vol,
745 .values = {
746 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
747 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
752 static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
753 .ops = &snd_hda_bind_sw,
754 .values = {
755 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
756 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
761 static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
762 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
763 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
764 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
765 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
766 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
767 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
768 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
769 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
770 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
771 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
772 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
773 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
774 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
776 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
777 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
778 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
779 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
781 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
782 .name = "Capture Source",
783 .info = ad198x_mux_enum_info,
784 .get = ad198x_mux_enum_get,
785 .put = ad198x_mux_enum_put,
787 { } /* end */
790 /* laptop-eapd model - 2ch only */
792 static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
793 .num_items = 3,
794 .items = {
795 { "Mic", 0x0 },
796 { "Internal Mic", 0x4 },
797 { "Mix", 0x5 },
801 static const struct hda_input_mux ad1986a_automic_capture_source = {
802 .num_items = 2,
803 .items = {
804 { "Mic", 0x0 },
805 { "Mix", 0x5 },
809 static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
810 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
811 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
812 { } /* end */
815 static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
816 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
817 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
818 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
819 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
820 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
821 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
822 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
824 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
825 .name = "Capture Source",
826 .info = ad198x_mux_enum_info,
827 .get = ad198x_mux_enum_get,
828 .put = ad198x_mux_enum_put,
831 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
832 .name = "External Amplifier",
833 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
834 .info = ad198x_eapd_info,
835 .get = ad198x_eapd_get,
836 .put = ad198x_eapd_put,
837 .private_value = 0x1b, /* port-D */
839 { } /* end */
842 static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
843 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
844 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
845 { } /* end */
848 /* re-connect the mic boost input according to the jack sensing */
849 static void ad1986a_automic(struct hda_codec *codec)
851 unsigned int present;
852 present = snd_hda_jack_detect(codec, 0x1f);
853 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
854 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
855 present ? 0 : 2);
858 #define AD1986A_MIC_EVENT 0x36
860 static void ad1986a_automic_unsol_event(struct hda_codec *codec,
861 unsigned int res)
863 if ((res >> 26) != AD1986A_MIC_EVENT)
864 return;
865 ad1986a_automic(codec);
868 static int ad1986a_automic_init(struct hda_codec *codec)
870 ad198x_init(codec);
871 ad1986a_automic(codec);
872 return 0;
875 /* laptop-automute - 2ch only */
877 static void ad1986a_update_hp(struct hda_codec *codec)
879 struct ad198x_spec *spec = codec->spec;
880 unsigned int mute;
882 if (spec->jack_present)
883 mute = HDA_AMP_MUTE; /* mute internal speaker */
884 else
885 /* unmute internal speaker if necessary */
886 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
887 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
888 HDA_AMP_MUTE, mute);
891 static void ad1986a_hp_automute(struct hda_codec *codec)
893 struct ad198x_spec *spec = codec->spec;
895 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
896 if (spec->inv_jack_detect)
897 spec->jack_present = !spec->jack_present;
898 ad1986a_update_hp(codec);
901 #define AD1986A_HP_EVENT 0x37
903 static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
905 if ((res >> 26) != AD1986A_HP_EVENT)
906 return;
907 ad1986a_hp_automute(codec);
910 static int ad1986a_hp_init(struct hda_codec *codec)
912 ad198x_init(codec);
913 ad1986a_hp_automute(codec);
914 return 0;
917 /* bind hp and internal speaker mute (with plug check) */
918 static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
919 struct snd_ctl_elem_value *ucontrol)
921 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
922 long *valp = ucontrol->value.integer.value;
923 int change;
925 change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
926 HDA_AMP_MUTE,
927 valp[0] ? 0 : HDA_AMP_MUTE);
928 change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
929 HDA_AMP_MUTE,
930 valp[1] ? 0 : HDA_AMP_MUTE);
931 if (change)
932 ad1986a_update_hp(codec);
933 return change;
936 static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
937 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
939 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
940 .name = "Master Playback Switch",
941 .subdevice = HDA_SUBDEV_AMP_FLAG,
942 .info = snd_hda_mixer_amp_switch_info,
943 .get = snd_hda_mixer_amp_switch_get,
944 .put = ad1986a_hp_master_sw_put,
945 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
947 { } /* end */
952 * initialization verbs
954 static const struct hda_verb ad1986a_init_verbs[] = {
955 /* Front, Surround, CLFE DAC; mute as default */
956 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
957 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
958 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
959 /* Downmix - off */
960 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
961 /* HP, Line-Out, Surround, CLFE selectors */
962 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
963 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
964 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
965 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
966 /* Mono selector */
967 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
968 /* Mic selector: Mic 1/2 pin */
969 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
970 /* Line-in selector: Line-in */
971 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
972 /* Mic 1/2 swap */
973 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
974 /* Record selector: mic */
975 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
976 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
977 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
978 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
979 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
980 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
981 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
982 /* PC beep */
983 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
984 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
985 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
986 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
987 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
988 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
989 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
990 /* HP Pin */
991 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
992 /* Front, Surround, CLFE Pins */
993 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
994 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
995 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
996 /* Mono Pin */
997 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
998 /* Mic Pin */
999 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1000 /* Line, Aux, CD, Beep-In Pin */
1001 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1002 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1003 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1004 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1005 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1006 { } /* end */
1009 static const struct hda_verb ad1986a_ch2_init[] = {
1010 /* Surround out -> Line In */
1011 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1012 /* Line-in selectors */
1013 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
1014 /* CLFE -> Mic in */
1015 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1016 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
1017 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1018 { } /* end */
1021 static const struct hda_verb ad1986a_ch4_init[] = {
1022 /* Surround out -> Surround */
1023 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1024 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1025 /* CLFE -> Mic in */
1026 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1027 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1028 { } /* end */
1031 static const struct hda_verb ad1986a_ch6_init[] = {
1032 /* Surround out -> Surround out */
1033 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1034 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1035 /* CLFE -> CLFE */
1036 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1037 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
1038 { } /* end */
1041 static const struct hda_channel_mode ad1986a_modes[3] = {
1042 { 2, ad1986a_ch2_init },
1043 { 4, ad1986a_ch4_init },
1044 { 6, ad1986a_ch6_init },
1047 /* eapd initialization */
1048 static const struct hda_verb ad1986a_eapd_init_verbs[] = {
1049 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1053 static const struct hda_verb ad1986a_automic_verbs[] = {
1054 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1055 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1056 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
1057 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1058 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
1062 /* Ultra initialization */
1063 static const struct hda_verb ad1986a_ultra_init[] = {
1064 /* eapd initialization */
1065 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1066 /* CLFE -> Mic in */
1067 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
1068 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1069 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
1070 { } /* end */
1073 /* pin sensing on HP jack */
1074 static const struct hda_verb ad1986a_hp_init_verbs[] = {
1075 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1079 static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
1080 unsigned int res)
1082 switch (res >> 26) {
1083 case AD1986A_HP_EVENT:
1084 ad1986a_hp_automute(codec);
1085 break;
1086 case AD1986A_MIC_EVENT:
1087 ad1986a_automic(codec);
1088 break;
1092 static int ad1986a_samsung_p50_init(struct hda_codec *codec)
1094 ad198x_init(codec);
1095 ad1986a_hp_automute(codec);
1096 ad1986a_automic(codec);
1097 return 0;
1101 /* models */
1102 enum {
1103 AD1986A_6STACK,
1104 AD1986A_3STACK,
1105 AD1986A_LAPTOP,
1106 AD1986A_LAPTOP_EAPD,
1107 AD1986A_LAPTOP_AUTOMUTE,
1108 AD1986A_ULTRA,
1109 AD1986A_SAMSUNG,
1110 AD1986A_SAMSUNG_P50,
1111 AD1986A_MODELS
1114 static const char * const ad1986a_models[AD1986A_MODELS] = {
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),
1156 #ifdef CONFIG_SND_HDA_POWER_SAVE
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 */
1163 { } /* end */
1165 #endif
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 patch_ad1986a(struct hda_codec *codec)
1175 struct ad198x_spec *spec;
1176 int err, board_config;
1178 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1179 if (spec == NULL)
1180 return -ENOMEM;
1182 codec->spec = spec;
1184 err = snd_hda_attach_beep_device(codec, 0x19);
1185 if (err < 0) {
1186 ad198x_free(codec);
1187 return err;
1189 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1191 spec->multiout.max_channels = 6;
1192 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1193 spec->multiout.dac_nids = ad1986a_dac_nids;
1194 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
1195 spec->num_adc_nids = 1;
1196 spec->adc_nids = ad1986a_adc_nids;
1197 spec->capsrc_nids = ad1986a_capsrc_nids;
1198 spec->input_mux = &ad1986a_capture_source;
1199 spec->num_mixers = 1;
1200 spec->mixers[0] = ad1986a_mixers;
1201 spec->num_init_verbs = 1;
1202 spec->init_verbs[0] = ad1986a_init_verbs;
1203 #ifdef CONFIG_SND_HDA_POWER_SAVE
1204 spec->loopback.amplist = ad1986a_loopbacks;
1205 #endif
1206 spec->vmaster_nid = 0x1b;
1207 spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
1209 codec->patch_ops = ad198x_patch_ops;
1211 /* override some parameters */
1212 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1213 ad1986a_models,
1214 ad1986a_cfg_tbl);
1215 switch (board_config) {
1216 case AD1986A_3STACK:
1217 spec->num_mixers = 2;
1218 spec->mixers[1] = ad1986a_3st_mixers;
1219 spec->num_init_verbs = 2;
1220 spec->init_verbs[1] = ad1986a_ch2_init;
1221 spec->channel_mode = ad1986a_modes;
1222 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
1223 spec->need_dac_fix = 1;
1224 spec->multiout.max_channels = 2;
1225 spec->multiout.num_dacs = 1;
1226 break;
1227 case AD1986A_LAPTOP:
1228 spec->mixers[0] = ad1986a_laptop_mixers;
1229 spec->multiout.max_channels = 2;
1230 spec->multiout.num_dacs = 1;
1231 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1232 break;
1233 case AD1986A_LAPTOP_EAPD:
1234 spec->num_mixers = 3;
1235 spec->mixers[0] = ad1986a_laptop_master_mixers;
1236 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1237 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1238 spec->num_init_verbs = 2;
1239 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1240 spec->multiout.max_channels = 2;
1241 spec->multiout.num_dacs = 1;
1242 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1243 if (!is_jack_available(codec, 0x25))
1244 spec->multiout.dig_out_nid = 0;
1245 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1246 break;
1247 case AD1986A_SAMSUNG:
1248 spec->num_mixers = 2;
1249 spec->mixers[0] = ad1986a_laptop_master_mixers;
1250 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1251 spec->num_init_verbs = 3;
1252 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1253 spec->init_verbs[2] = ad1986a_automic_verbs;
1254 spec->multiout.max_channels = 2;
1255 spec->multiout.num_dacs = 1;
1256 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1257 if (!is_jack_available(codec, 0x25))
1258 spec->multiout.dig_out_nid = 0;
1259 spec->input_mux = &ad1986a_automic_capture_source;
1260 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1261 codec->patch_ops.init = ad1986a_automic_init;
1262 break;
1263 case AD1986A_SAMSUNG_P50:
1264 spec->num_mixers = 2;
1265 spec->mixers[0] = ad1986a_automute_master_mixers;
1266 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1267 spec->num_init_verbs = 4;
1268 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1269 spec->init_verbs[2] = ad1986a_automic_verbs;
1270 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1271 spec->multiout.max_channels = 2;
1272 spec->multiout.num_dacs = 1;
1273 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1274 if (!is_jack_available(codec, 0x25))
1275 spec->multiout.dig_out_nid = 0;
1276 spec->input_mux = &ad1986a_automic_capture_source;
1277 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1278 codec->patch_ops.init = ad1986a_samsung_p50_init;
1279 break;
1280 case AD1986A_LAPTOP_AUTOMUTE:
1281 spec->num_mixers = 3;
1282 spec->mixers[0] = ad1986a_automute_master_mixers;
1283 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1284 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1285 spec->num_init_verbs = 3;
1286 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1287 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1288 spec->multiout.max_channels = 2;
1289 spec->multiout.num_dacs = 1;
1290 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1291 if (!is_jack_available(codec, 0x25))
1292 spec->multiout.dig_out_nid = 0;
1293 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1294 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1295 codec->patch_ops.init = ad1986a_hp_init;
1296 /* Lenovo N100 seems to report the reversed bit
1297 * for HP jack-sensing
1299 spec->inv_jack_detect = 1;
1300 break;
1301 case AD1986A_ULTRA:
1302 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1303 spec->num_init_verbs = 2;
1304 spec->init_verbs[1] = ad1986a_ultra_init;
1305 spec->multiout.max_channels = 2;
1306 spec->multiout.num_dacs = 1;
1307 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1308 spec->multiout.dig_out_nid = 0;
1309 break;
1312 /* AD1986A has a hardware problem that it can't share a stream
1313 * with multiple output pins. The copy of front to surrounds
1314 * causes noisy or silent outputs at a certain timing, e.g.
1315 * changing the volume.
1316 * So, let's disable the shared stream.
1318 spec->multiout.no_share_stream = 1;
1320 codec->no_trigger_sense = 1;
1321 codec->no_sticky_stream = 1;
1323 return 0;
1327 * AD1983 specific
1330 #define AD1983_SPDIF_OUT 0x02
1331 #define AD1983_DAC 0x03
1332 #define AD1983_ADC 0x04
1334 static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
1335 static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
1336 static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
1338 static const struct hda_input_mux ad1983_capture_source = {
1339 .num_items = 4,
1340 .items = {
1341 { "Mic", 0x0 },
1342 { "Line", 0x1 },
1343 { "Mix", 0x2 },
1344 { "Mix Mono", 0x3 },
1349 * SPDIF playback route
1351 static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1353 static const char * const texts[] = { "PCM", "ADC" };
1355 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1356 uinfo->count = 1;
1357 uinfo->value.enumerated.items = 2;
1358 if (uinfo->value.enumerated.item > 1)
1359 uinfo->value.enumerated.item = 1;
1360 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1361 return 0;
1364 static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1366 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1367 struct ad198x_spec *spec = codec->spec;
1369 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1370 return 0;
1373 static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1375 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1376 struct ad198x_spec *spec = codec->spec;
1378 if (ucontrol->value.enumerated.item[0] > 1)
1379 return -EINVAL;
1380 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1381 spec->spdif_route = ucontrol->value.enumerated.item[0];
1382 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1383 AC_VERB_SET_CONNECT_SEL,
1384 spec->spdif_route);
1385 return 1;
1387 return 0;
1390 static const struct snd_kcontrol_new ad1983_mixers[] = {
1391 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1392 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1393 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1394 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1395 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1396 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1397 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1398 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1399 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1400 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1401 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1402 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1403 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
1404 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1405 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1407 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1408 .name = "Capture Source",
1409 .info = ad198x_mux_enum_info,
1410 .get = ad198x_mux_enum_get,
1411 .put = ad198x_mux_enum_put,
1414 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1415 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1416 .info = ad1983_spdif_route_info,
1417 .get = ad1983_spdif_route_get,
1418 .put = ad1983_spdif_route_put,
1420 { } /* end */
1423 static const struct hda_verb ad1983_init_verbs[] = {
1424 /* Front, HP, Mono; mute as default */
1425 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1426 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1427 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1428 /* Beep, PCM, Mic, Line-In: mute */
1429 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1430 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1431 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1432 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1433 /* Front, HP selectors; from Mix */
1434 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1435 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1436 /* Mono selector; from Mix */
1437 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1438 /* Mic selector; Mic */
1439 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1440 /* Line-in selector: Line-in */
1441 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1442 /* Mic boost: 0dB */
1443 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1444 /* Record selector: mic */
1445 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1446 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1447 /* SPDIF route: PCM */
1448 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1449 /* Front Pin */
1450 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1451 /* HP Pin */
1452 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1453 /* Mono Pin */
1454 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1455 /* Mic Pin */
1456 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1457 /* Line Pin */
1458 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1459 { } /* end */
1462 #ifdef CONFIG_SND_HDA_POWER_SAVE
1463 static const struct hda_amp_list ad1983_loopbacks[] = {
1464 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
1465 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1466 { } /* end */
1468 #endif
1470 static int patch_ad1983(struct hda_codec *codec)
1472 struct ad198x_spec *spec;
1473 int err;
1475 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1476 if (spec == NULL)
1477 return -ENOMEM;
1479 codec->spec = spec;
1481 err = snd_hda_attach_beep_device(codec, 0x10);
1482 if (err < 0) {
1483 ad198x_free(codec);
1484 return err;
1486 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1488 spec->multiout.max_channels = 2;
1489 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1490 spec->multiout.dac_nids = ad1983_dac_nids;
1491 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
1492 spec->num_adc_nids = 1;
1493 spec->adc_nids = ad1983_adc_nids;
1494 spec->capsrc_nids = ad1983_capsrc_nids;
1495 spec->input_mux = &ad1983_capture_source;
1496 spec->num_mixers = 1;
1497 spec->mixers[0] = ad1983_mixers;
1498 spec->num_init_verbs = 1;
1499 spec->init_verbs[0] = ad1983_init_verbs;
1500 spec->spdif_route = 0;
1501 #ifdef CONFIG_SND_HDA_POWER_SAVE
1502 spec->loopback.amplist = ad1983_loopbacks;
1503 #endif
1504 spec->vmaster_nid = 0x05;
1506 codec->patch_ops = ad198x_patch_ops;
1508 codec->no_trigger_sense = 1;
1509 codec->no_sticky_stream = 1;
1511 return 0;
1516 * AD1981 HD specific
1519 #define AD1981_SPDIF_OUT 0x02
1520 #define AD1981_DAC 0x03
1521 #define AD1981_ADC 0x04
1523 static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
1524 static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
1525 static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
1527 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
1528 static const struct hda_input_mux ad1981_capture_source = {
1529 .num_items = 7,
1530 .items = {
1531 { "Front Mic", 0x0 },
1532 { "Line", 0x1 },
1533 { "Mix", 0x2 },
1534 { "Mix Mono", 0x3 },
1535 { "CD", 0x4 },
1536 { "Mic", 0x6 },
1537 { "Aux", 0x7 },
1541 static const struct snd_kcontrol_new ad1981_mixers[] = {
1542 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1543 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1544 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1545 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1546 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1547 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1548 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1549 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1550 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1551 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1552 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1553 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1554 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1555 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1556 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1557 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1558 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1559 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1560 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1561 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
1562 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1563 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1565 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1566 .name = "Capture Source",
1567 .info = ad198x_mux_enum_info,
1568 .get = ad198x_mux_enum_get,
1569 .put = ad198x_mux_enum_put,
1571 /* identical with AD1983 */
1573 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1574 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1575 .info = ad1983_spdif_route_info,
1576 .get = ad1983_spdif_route_get,
1577 .put = ad1983_spdif_route_put,
1579 { } /* end */
1582 static const struct hda_verb ad1981_init_verbs[] = {
1583 /* Front, HP, Mono; mute as default */
1584 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1585 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1586 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1587 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1588 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1589 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1590 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1591 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1592 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1593 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1594 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1595 /* Front, HP selectors; from Mix */
1596 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1597 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1598 /* Mono selector; from Mix */
1599 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1600 /* Mic Mixer; select Front Mic */
1601 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1602 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1603 /* Mic boost: 0dB */
1604 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1605 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1606 /* Record selector: Front mic */
1607 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1608 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1609 /* SPDIF route: PCM */
1610 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1611 /* Front Pin */
1612 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1613 /* HP Pin */
1614 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1615 /* Mono Pin */
1616 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1617 /* Front & Rear Mic Pins */
1618 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1619 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1620 /* Line Pin */
1621 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1622 /* Digital Beep */
1623 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1624 /* Line-Out as Input: disabled */
1625 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1626 { } /* end */
1629 #ifdef CONFIG_SND_HDA_POWER_SAVE
1630 static const struct hda_amp_list ad1981_loopbacks[] = {
1631 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1632 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1633 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1634 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1635 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1636 { } /* end */
1638 #endif
1641 * Patch for HP nx6320
1643 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
1644 * speaker output enabled _and_ mute-LED off.
1647 #define AD1981_HP_EVENT 0x37
1648 #define AD1981_MIC_EVENT 0x38
1650 static const struct hda_verb ad1981_hp_init_verbs[] = {
1651 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1652 /* pin sensing on HP and Mic jacks */
1653 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1654 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1658 /* turn on/off EAPD (+ mute HP) as a master switch */
1659 static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1660 struct snd_ctl_elem_value *ucontrol)
1662 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1663 struct ad198x_spec *spec = codec->spec;
1665 if (! ad198x_eapd_put(kcontrol, ucontrol))
1666 return 0;
1667 /* change speaker pin appropriately */
1668 snd_hda_codec_write(codec, 0x05, 0,
1669 AC_VERB_SET_PIN_WIDGET_CONTROL,
1670 spec->cur_eapd ? PIN_OUT : 0);
1671 /* toggle HP mute appropriately */
1672 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1673 HDA_AMP_MUTE,
1674 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
1675 return 1;
1678 /* bind volumes of both NID 0x05 and 0x06 */
1679 static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1680 .ops = &snd_hda_bind_vol,
1681 .values = {
1682 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1683 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1688 /* mute internal speaker if HP is plugged */
1689 static void ad1981_hp_automute(struct hda_codec *codec)
1691 unsigned int present;
1693 present = snd_hda_jack_detect(codec, 0x06);
1694 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1695 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1698 /* toggle input of built-in and mic jack appropriately */
1699 static void ad1981_hp_automic(struct hda_codec *codec)
1701 static const struct hda_verb mic_jack_on[] = {
1702 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1703 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1706 static const struct hda_verb mic_jack_off[] = {
1707 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1708 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1711 unsigned int present;
1713 present = snd_hda_jack_detect(codec, 0x08);
1714 if (present)
1715 snd_hda_sequence_write(codec, mic_jack_on);
1716 else
1717 snd_hda_sequence_write(codec, mic_jack_off);
1720 /* unsolicited event for HP jack sensing */
1721 static void ad1981_hp_unsol_event(struct hda_codec *codec,
1722 unsigned int res)
1724 res >>= 26;
1725 switch (res) {
1726 case AD1981_HP_EVENT:
1727 ad1981_hp_automute(codec);
1728 break;
1729 case AD1981_MIC_EVENT:
1730 ad1981_hp_automic(codec);
1731 break;
1735 static const struct hda_input_mux ad1981_hp_capture_source = {
1736 .num_items = 3,
1737 .items = {
1738 { "Mic", 0x0 },
1739 { "Docking-Station", 0x1 },
1740 { "Mix", 0x2 },
1744 static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
1745 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
1747 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1748 .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
1749 .name = "Master Playback Switch",
1750 .info = ad198x_eapd_info,
1751 .get = ad198x_eapd_get,
1752 .put = ad1981_hp_master_sw_put,
1753 .private_value = 0x05,
1755 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1756 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1757 #if 0
1758 /* FIXME: analog mic/line loopback doesn't work with my tests...
1759 * (although recording is OK)
1761 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1762 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1763 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1764 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1765 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1766 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1767 /* FIXME: does this laptop have analog CD connection? */
1768 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1769 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1770 #endif
1771 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1772 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
1773 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1774 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1776 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1777 .name = "Capture Source",
1778 .info = ad198x_mux_enum_info,
1779 .get = ad198x_mux_enum_get,
1780 .put = ad198x_mux_enum_put,
1782 { } /* end */
1785 /* initialize jack-sensing, too */
1786 static int ad1981_hp_init(struct hda_codec *codec)
1788 ad198x_init(codec);
1789 ad1981_hp_automute(codec);
1790 ad1981_hp_automic(codec);
1791 return 0;
1794 /* configuration for Toshiba Laptops */
1795 static const struct hda_verb ad1981_toshiba_init_verbs[] = {
1796 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
1797 /* pin sensing on HP and Mic jacks */
1798 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1799 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1803 static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1804 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1805 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1809 /* configuration for Lenovo Thinkpad T60 */
1810 static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1811 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1812 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1813 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1814 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1815 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1816 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1817 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1818 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1819 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1820 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1821 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1824 .name = "Capture Source",
1825 .info = ad198x_mux_enum_info,
1826 .get = ad198x_mux_enum_get,
1827 .put = ad198x_mux_enum_put,
1829 /* identical with AD1983 */
1831 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1832 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1833 .info = ad1983_spdif_route_info,
1834 .get = ad1983_spdif_route_get,
1835 .put = ad1983_spdif_route_put,
1837 { } /* end */
1840 static const struct hda_input_mux ad1981_thinkpad_capture_source = {
1841 .num_items = 3,
1842 .items = {
1843 { "Mic", 0x0 },
1844 { "Mix", 0x2 },
1845 { "CD", 0x4 },
1849 /* models */
1850 enum {
1851 AD1981_BASIC,
1852 AD1981_HP,
1853 AD1981_THINKPAD,
1854 AD1981_TOSHIBA,
1855 AD1981_MODELS
1858 static const char * const ad1981_models[AD1981_MODELS] = {
1859 [AD1981_HP] = "hp",
1860 [AD1981_THINKPAD] = "thinkpad",
1861 [AD1981_BASIC] = "basic",
1862 [AD1981_TOSHIBA] = "toshiba"
1865 static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
1866 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
1867 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
1868 /* All HP models */
1869 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
1870 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
1871 /* Lenovo Thinkpad T60/X60/Z6xx */
1872 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
1873 /* HP nx6320 (reversed SSID, H/W bug) */
1874 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
1878 static int patch_ad1981(struct hda_codec *codec)
1880 struct ad198x_spec *spec;
1881 int err, board_config;
1883 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1884 if (spec == NULL)
1885 return -ENOMEM;
1887 codec->spec = spec;
1889 err = snd_hda_attach_beep_device(codec, 0x10);
1890 if (err < 0) {
1891 ad198x_free(codec);
1892 return err;
1894 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
1896 spec->multiout.max_channels = 2;
1897 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
1898 spec->multiout.dac_nids = ad1981_dac_nids;
1899 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
1900 spec->num_adc_nids = 1;
1901 spec->adc_nids = ad1981_adc_nids;
1902 spec->capsrc_nids = ad1981_capsrc_nids;
1903 spec->input_mux = &ad1981_capture_source;
1904 spec->num_mixers = 1;
1905 spec->mixers[0] = ad1981_mixers;
1906 spec->num_init_verbs = 1;
1907 spec->init_verbs[0] = ad1981_init_verbs;
1908 spec->spdif_route = 0;
1909 #ifdef CONFIG_SND_HDA_POWER_SAVE
1910 spec->loopback.amplist = ad1981_loopbacks;
1911 #endif
1912 spec->vmaster_nid = 0x05;
1914 codec->patch_ops = ad198x_patch_ops;
1916 /* override some parameters */
1917 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
1918 ad1981_models,
1919 ad1981_cfg_tbl);
1920 switch (board_config) {
1921 case AD1981_HP:
1922 spec->mixers[0] = ad1981_hp_mixers;
1923 spec->num_init_verbs = 2;
1924 spec->init_verbs[1] = ad1981_hp_init_verbs;
1925 if (!is_jack_available(codec, 0x0a))
1926 spec->multiout.dig_out_nid = 0;
1927 spec->input_mux = &ad1981_hp_capture_source;
1929 codec->patch_ops.init = ad1981_hp_init;
1930 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1931 /* set the upper-limit for mixer amp to 0dB for avoiding the
1932 * possible damage by overloading
1934 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
1935 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1936 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1937 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1938 (1 << AC_AMPCAP_MUTE_SHIFT));
1939 break;
1940 case AD1981_THINKPAD:
1941 spec->mixers[0] = ad1981_thinkpad_mixers;
1942 spec->input_mux = &ad1981_thinkpad_capture_source;
1943 /* set the upper-limit for mixer amp to 0dB for avoiding the
1944 * possible damage by overloading
1946 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
1947 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1948 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1949 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1950 (1 << AC_AMPCAP_MUTE_SHIFT));
1951 break;
1952 case AD1981_TOSHIBA:
1953 spec->mixers[0] = ad1981_hp_mixers;
1954 spec->mixers[1] = ad1981_toshiba_mixers;
1955 spec->num_init_verbs = 2;
1956 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
1957 spec->multiout.dig_out_nid = 0;
1958 spec->input_mux = &ad1981_hp_capture_source;
1959 codec->patch_ops.init = ad1981_hp_init;
1960 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1961 break;
1964 codec->no_trigger_sense = 1;
1965 codec->no_sticky_stream = 1;
1967 return 0;
1972 * AD1988
1974 * Output pins and routes
1976 * Pin Mix Sel DAC (*)
1977 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
1978 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
1979 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
1980 * port-D 0x12 (mute/hp) <- 0x29 <- 04
1981 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
1982 * port-F 0x16 (mute) <- 0x2a <- 06
1983 * port-G 0x24 (mute) <- 0x27 <- 05
1984 * port-H 0x25 (mute) <- 0x28 <- 0a
1985 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
1987 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
1988 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
1990 * Input pins and routes
1992 * pin boost mix input # / adc input #
1993 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
1994 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
1995 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
1996 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
1997 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
1998 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
1999 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
2000 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
2003 * DAC assignment
2004 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
2005 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
2007 * Inputs of Analog Mix (0x20)
2008 * 0:Port-B (front mic)
2009 * 1:Port-C/G/H (line-in)
2010 * 2:Port-A
2011 * 3:Port-D (line-in/2)
2012 * 4:Port-E/G/H (mic-in)
2013 * 5:Port-F (mic2-in)
2014 * 6:CD
2015 * 7:Beep
2017 * ADC selection
2018 * 0:Port-A
2019 * 1:Port-B (front mic-in)
2020 * 2:Port-C (line-in)
2021 * 3:Port-F (mic2-in)
2022 * 4:Port-E (mic-in)
2023 * 5:CD
2024 * 6:Port-G
2025 * 7:Port-H
2026 * 8:Port-D (line-in/2)
2027 * 9:Mix
2029 * Proposed pin assignments by the datasheet
2031 * 6-stack
2032 * Port-A front headphone
2033 * B front mic-in
2034 * C rear line-in
2035 * D rear front-out
2036 * E rear mic-in
2037 * F rear surround
2038 * G rear CLFE
2039 * H rear side
2041 * 3-stack
2042 * Port-A front headphone
2043 * B front mic
2044 * C rear line-in/surround
2045 * D rear front-out
2046 * E rear mic-in/CLFE
2048 * laptop
2049 * Port-A headphone
2050 * B mic-in
2051 * C docking station
2052 * D internal speaker (with EAPD)
2053 * E/F quad mic array
2057 /* models */
2058 enum {
2059 AD1988_6STACK,
2060 AD1988_6STACK_DIG,
2061 AD1988_6STACK_DIG_FP,
2062 AD1988_3STACK,
2063 AD1988_3STACK_DIG,
2064 AD1988_LAPTOP,
2065 AD1988_LAPTOP_DIG,
2066 AD1988_AUTO,
2067 AD1988_MODEL_LAST,
2070 /* reivision id to check workarounds */
2071 #define AD1988A_REV2 0x100200
2073 #define is_rev2(codec) \
2074 ((codec)->vendor_id == 0x11d41988 && \
2075 (codec)->revision_id == AD1988A_REV2)
2078 * mixers
2081 static const hda_nid_t ad1988_6stack_dac_nids[4] = {
2082 0x04, 0x06, 0x05, 0x0a
2085 static const hda_nid_t ad1988_3stack_dac_nids[3] = {
2086 0x04, 0x05, 0x0a
2089 /* for AD1988A revision-2, DAC2-4 are swapped */
2090 static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
2091 0x04, 0x05, 0x0a, 0x06
2094 static const hda_nid_t ad1988_alt_dac_nid[1] = {
2095 0x03
2098 static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
2099 0x04, 0x0a, 0x06
2102 static const hda_nid_t ad1988_adc_nids[3] = {
2103 0x08, 0x09, 0x0f
2106 static const hda_nid_t ad1988_capsrc_nids[3] = {
2107 0x0c, 0x0d, 0x0e
2110 #define AD1988_SPDIF_OUT 0x02
2111 #define AD1988_SPDIF_OUT_HDMI 0x0b
2112 #define AD1988_SPDIF_IN 0x07
2114 static const hda_nid_t ad1989b_slave_dig_outs[] = {
2115 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
2118 static const struct hda_input_mux ad1988_6stack_capture_source = {
2119 .num_items = 5,
2120 .items = {
2121 { "Front Mic", 0x1 }, /* port-B */
2122 { "Line", 0x2 }, /* port-C */
2123 { "Mic", 0x4 }, /* port-E */
2124 { "CD", 0x5 },
2125 { "Mix", 0x9 },
2129 static const struct hda_input_mux ad1988_laptop_capture_source = {
2130 .num_items = 3,
2131 .items = {
2132 { "Mic/Line", 0x1 }, /* port-B */
2133 { "CD", 0x5 },
2134 { "Mix", 0x9 },
2140 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
2141 struct snd_ctl_elem_info *uinfo)
2143 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2144 struct ad198x_spec *spec = codec->spec;
2145 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
2146 spec->num_channel_mode);
2149 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
2150 struct snd_ctl_elem_value *ucontrol)
2152 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2153 struct ad198x_spec *spec = codec->spec;
2154 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
2155 spec->num_channel_mode, spec->multiout.max_channels);
2158 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
2159 struct snd_ctl_elem_value *ucontrol)
2161 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2162 struct ad198x_spec *spec = codec->spec;
2163 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
2164 spec->num_channel_mode,
2165 &spec->multiout.max_channels);
2166 if (err >= 0 && spec->need_dac_fix)
2167 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2168 return err;
2171 /* 6-stack mode */
2172 static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
2173 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2174 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2175 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2176 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2177 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2178 { } /* end */
2181 static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
2182 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2183 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2184 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2185 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2186 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2187 { } /* end */
2190 static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
2191 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2192 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2193 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2194 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2195 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2196 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2197 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2199 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2200 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2201 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2202 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2203 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2204 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2205 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2206 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2208 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2209 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2211 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2212 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2214 { } /* end */
2217 static const struct snd_kcontrol_new ad1988_6stack_fp_mixers[] = {
2218 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2220 { } /* end */
2223 /* 3-stack mode */
2224 static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
2225 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2226 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2227 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2228 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2229 { } /* end */
2232 static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2233 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2234 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2235 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2236 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
2237 { } /* end */
2240 static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
2241 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2242 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2243 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2244 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
2245 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2246 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2248 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2249 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2250 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2251 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2252 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2253 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2254 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2255 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2257 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2258 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2260 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2261 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2263 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2264 .name = "Channel Mode",
2265 .info = ad198x_ch_mode_info,
2266 .get = ad198x_ch_mode_get,
2267 .put = ad198x_ch_mode_put,
2270 { } /* end */
2273 /* laptop mode */
2274 static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2275 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2276 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2277 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2279 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2280 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2281 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2282 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2283 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2284 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2286 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2287 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2289 HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2292 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2293 .name = "External Amplifier",
2294 .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
2295 .info = ad198x_eapd_info,
2296 .get = ad198x_eapd_get,
2297 .put = ad198x_eapd_put,
2298 .private_value = 0x12, /* port-D */
2301 { } /* end */
2304 /* capture */
2305 static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
2306 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2307 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2308 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2309 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2310 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2311 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2313 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2314 /* The multiple "Capture Source" controls confuse alsamixer
2315 * So call somewhat different..
2317 /* .name = "Capture Source", */
2318 .name = "Input Source",
2319 .count = 3,
2320 .info = ad198x_mux_enum_info,
2321 .get = ad198x_mux_enum_get,
2322 .put = ad198x_mux_enum_put,
2324 { } /* end */
2327 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2328 struct snd_ctl_elem_info *uinfo)
2330 static const char * const texts[] = {
2331 "PCM", "ADC1", "ADC2", "ADC3"
2333 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2334 uinfo->count = 1;
2335 uinfo->value.enumerated.items = 4;
2336 if (uinfo->value.enumerated.item >= 4)
2337 uinfo->value.enumerated.item = 3;
2338 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2339 return 0;
2342 static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2343 struct snd_ctl_elem_value *ucontrol)
2345 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2346 unsigned int sel;
2348 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2349 AC_AMP_GET_INPUT);
2350 if (!(sel & 0x80))
2351 ucontrol->value.enumerated.item[0] = 0;
2352 else {
2353 sel = snd_hda_codec_read(codec, 0x0b, 0,
2354 AC_VERB_GET_CONNECT_SEL, 0);
2355 if (sel < 3)
2356 sel++;
2357 else
2358 sel = 0;
2359 ucontrol->value.enumerated.item[0] = sel;
2361 return 0;
2364 static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2365 struct snd_ctl_elem_value *ucontrol)
2367 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2368 unsigned int val, sel;
2369 int change;
2371 val = ucontrol->value.enumerated.item[0];
2372 if (val > 3)
2373 return -EINVAL;
2374 if (!val) {
2375 sel = snd_hda_codec_read(codec, 0x1d, 0,
2376 AC_VERB_GET_AMP_GAIN_MUTE,
2377 AC_AMP_GET_INPUT);
2378 change = sel & 0x80;
2379 if (change) {
2380 snd_hda_codec_write_cache(codec, 0x1d, 0,
2381 AC_VERB_SET_AMP_GAIN_MUTE,
2382 AMP_IN_UNMUTE(0));
2383 snd_hda_codec_write_cache(codec, 0x1d, 0,
2384 AC_VERB_SET_AMP_GAIN_MUTE,
2385 AMP_IN_MUTE(1));
2387 } else {
2388 sel = snd_hda_codec_read(codec, 0x1d, 0,
2389 AC_VERB_GET_AMP_GAIN_MUTE,
2390 AC_AMP_GET_INPUT | 0x01);
2391 change = sel & 0x80;
2392 if (change) {
2393 snd_hda_codec_write_cache(codec, 0x1d, 0,
2394 AC_VERB_SET_AMP_GAIN_MUTE,
2395 AMP_IN_MUTE(0));
2396 snd_hda_codec_write_cache(codec, 0x1d, 0,
2397 AC_VERB_SET_AMP_GAIN_MUTE,
2398 AMP_IN_UNMUTE(1));
2400 sel = snd_hda_codec_read(codec, 0x0b, 0,
2401 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2402 change |= sel != val;
2403 if (change)
2404 snd_hda_codec_write_cache(codec, 0x0b, 0,
2405 AC_VERB_SET_CONNECT_SEL,
2406 val - 1);
2408 return change;
2411 static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2412 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2414 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2415 .name = "IEC958 Playback Source",
2416 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
2417 .info = ad1988_spdif_playback_source_info,
2418 .get = ad1988_spdif_playback_source_get,
2419 .put = ad1988_spdif_playback_source_put,
2421 { } /* end */
2424 static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2425 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2426 { } /* end */
2429 static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2430 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2431 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2432 { } /* end */
2436 * initialization verbs
2440 * for 6-stack (+dig)
2442 static const struct hda_verb ad1988_6stack_init_verbs[] = {
2443 /* Front, Surround, CLFE, side DAC; unmute as default */
2444 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2445 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2446 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2447 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2448 /* Port-A front headphon path */
2449 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2450 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2451 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2452 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2453 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2454 /* Port-D line-out path */
2455 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2456 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2457 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2458 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2459 /* Port-F surround path */
2460 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2461 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2462 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2463 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2464 /* Port-G CLFE path */
2465 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2466 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2467 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2468 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2469 /* Port-H side path */
2470 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2471 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2472 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2473 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2474 /* Mono out path */
2475 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2476 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2477 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2478 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2479 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2480 /* Port-B front mic-in path */
2481 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2482 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2483 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2484 /* Port-C line-in path */
2485 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2486 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2487 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2488 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2489 /* Port-E mic-in path */
2490 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2491 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2492 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2493 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2494 /* Analog CD Input */
2495 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2496 /* Analog Mix output amp */
2497 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2502 static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
2503 /* Headphone; unmute as default */
2504 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2505 /* Port-A front headphon path */
2506 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2507 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2508 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2509 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2510 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2515 static const struct hda_verb ad1988_capture_init_verbs[] = {
2516 /* mute analog mix */
2517 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2518 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2519 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2520 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2521 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2522 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2523 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2524 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2525 /* select ADCs - front-mic */
2526 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2527 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2528 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2533 static const struct hda_verb ad1988_spdif_init_verbs[] = {
2534 /* SPDIF out sel */
2535 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2536 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2537 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2538 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2539 /* SPDIF out pin */
2540 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2545 static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
2546 /* unmute SPDIF input pin */
2547 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2551 /* AD1989 has no ADC -> SPDIF route */
2552 static const struct hda_verb ad1989_spdif_init_verbs[] = {
2553 /* SPDIF-1 out pin */
2554 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2555 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2556 /* SPDIF-2/HDMI out pin */
2557 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2558 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2563 * verbs for 3stack (+dig)
2565 static const struct hda_verb ad1988_3stack_ch2_init[] = {
2566 /* set port-C to line-in */
2567 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2568 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2569 /* set port-E to mic-in */
2570 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2571 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2572 { } /* end */
2575 static const struct hda_verb ad1988_3stack_ch6_init[] = {
2576 /* set port-C to surround out */
2577 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2578 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2579 /* set port-E to CLFE out */
2580 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2581 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2582 { } /* end */
2585 static const struct hda_channel_mode ad1988_3stack_modes[2] = {
2586 { 2, ad1988_3stack_ch2_init },
2587 { 6, ad1988_3stack_ch6_init },
2590 static const struct hda_verb ad1988_3stack_init_verbs[] = {
2591 /* Front, Surround, CLFE, side DAC; unmute as default */
2592 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2593 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2594 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2595 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2596 /* Port-A front headphon path */
2597 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2598 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2599 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2600 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2601 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2602 /* Port-D line-out path */
2603 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2604 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2605 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2606 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2607 /* Mono out path */
2608 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2609 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2610 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2611 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2612 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2613 /* Port-B front mic-in path */
2614 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2615 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2616 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2617 /* Port-C line-in/surround path - 6ch mode as default */
2618 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2619 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2620 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2621 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
2622 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2623 /* Port-E mic-in/CLFE path - 6ch mode as default */
2624 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2625 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2626 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2627 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
2628 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2629 /* mute analog mix */
2630 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2631 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2632 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2633 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2634 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2635 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2636 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2637 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2638 /* select ADCs - front-mic */
2639 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2640 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2641 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2642 /* Analog Mix output amp */
2643 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2648 * verbs for laptop mode (+dig)
2650 static const struct hda_verb ad1988_laptop_hp_on[] = {
2651 /* unmute port-A and mute port-D */
2652 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2653 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2654 { } /* end */
2656 static const struct hda_verb ad1988_laptop_hp_off[] = {
2657 /* mute port-A and unmute port-D */
2658 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2659 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2660 { } /* end */
2663 #define AD1988_HP_EVENT 0x01
2665 static const struct hda_verb ad1988_laptop_init_verbs[] = {
2666 /* Front, Surround, CLFE, side DAC; unmute as default */
2667 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2668 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2669 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2670 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2671 /* Port-A front headphon path */
2672 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2673 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2674 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2675 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2676 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2677 /* unsolicited event for pin-sense */
2678 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2679 /* Port-D line-out path + EAPD */
2680 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2681 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2682 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2683 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2684 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
2685 /* Mono out path */
2686 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2687 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2688 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2689 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2690 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2691 /* Port-B mic-in path */
2692 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2693 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2694 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2695 /* Port-C docking station - try to output */
2696 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2697 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2698 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2699 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2700 /* mute analog mix */
2701 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2702 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2703 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2704 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2705 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2706 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2707 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2708 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2709 /* select ADCs - mic */
2710 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2711 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2712 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2713 /* Analog Mix output amp */
2714 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2718 static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2720 if ((res >> 26) != AD1988_HP_EVENT)
2721 return;
2722 if (snd_hda_jack_detect(codec, 0x11))
2723 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2724 else
2725 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2728 #ifdef CONFIG_SND_HDA_POWER_SAVE
2729 static const struct hda_amp_list ad1988_loopbacks[] = {
2730 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2731 { 0x20, HDA_INPUT, 1 }, /* Line */
2732 { 0x20, HDA_INPUT, 4 }, /* Mic */
2733 { 0x20, HDA_INPUT, 6 }, /* CD */
2734 { } /* end */
2736 #endif
2739 * Automatic parse of I/O pins from the BIOS configuration
2742 enum {
2743 AD_CTL_WIDGET_VOL,
2744 AD_CTL_WIDGET_MUTE,
2745 AD_CTL_BIND_MUTE,
2747 static const struct snd_kcontrol_new ad1988_control_templates[] = {
2748 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2749 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2750 HDA_BIND_MUTE(NULL, 0, 0, 0),
2753 /* add dynamic controls */
2754 static int add_control(struct ad198x_spec *spec, int type, const char *name,
2755 unsigned long val)
2757 struct snd_kcontrol_new *knew;
2759 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2760 knew = snd_array_new(&spec->kctls);
2761 if (!knew)
2762 return -ENOMEM;
2763 *knew = ad1988_control_templates[type];
2764 knew->name = kstrdup(name, GFP_KERNEL);
2765 if (! knew->name)
2766 return -ENOMEM;
2767 if (get_amp_nid_(val))
2768 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2769 knew->private_value = val;
2770 return 0;
2773 #define AD1988_PIN_CD_NID 0x18
2774 #define AD1988_PIN_BEEP_NID 0x10
2776 static const hda_nid_t ad1988_mixer_nids[8] = {
2777 /* A B C D E F G H */
2778 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
2781 static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
2783 static const hda_nid_t idx_to_dac[8] = {
2784 /* A B C D E F G H */
2785 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
2787 static const hda_nid_t idx_to_dac_rev2[8] = {
2788 /* A B C D E F G H */
2789 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
2791 if (is_rev2(codec))
2792 return idx_to_dac_rev2[idx];
2793 else
2794 return idx_to_dac[idx];
2797 static const hda_nid_t ad1988_boost_nids[8] = {
2798 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
2801 static int ad1988_pin_idx(hda_nid_t nid)
2803 static const hda_nid_t ad1988_io_pins[8] = {
2804 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
2806 int i;
2807 for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)
2808 if (ad1988_io_pins[i] == nid)
2809 return i;
2810 return 0; /* should be -1 */
2813 static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
2815 static const int loopback_idx[8] = {
2816 2, 0, 1, 3, 4, 5, 1, 4
2818 switch (nid) {
2819 case AD1988_PIN_CD_NID:
2820 return 6;
2821 default:
2822 return loopback_idx[ad1988_pin_idx(nid)];
2826 static int ad1988_pin_to_adc_idx(hda_nid_t nid)
2828 static const int adc_idx[8] = {
2829 0, 1, 2, 8, 4, 3, 6, 7
2831 switch (nid) {
2832 case AD1988_PIN_CD_NID:
2833 return 5;
2834 default:
2835 return adc_idx[ad1988_pin_idx(nid)];
2839 /* fill in the dac_nids table from the parsed pin configuration */
2840 static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
2841 const struct auto_pin_cfg *cfg)
2843 struct ad198x_spec *spec = codec->spec;
2844 int i, idx;
2846 spec->multiout.dac_nids = spec->private_dac_nids;
2848 /* check the pins hardwired to audio widget */
2849 for (i = 0; i < cfg->line_outs; i++) {
2850 idx = ad1988_pin_idx(cfg->line_out_pins[i]);
2851 spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx);
2853 spec->multiout.num_dacs = cfg->line_outs;
2854 return 0;
2857 /* add playback controls from the parsed DAC table */
2858 static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
2859 const struct auto_pin_cfg *cfg)
2861 char name[32];
2862 static const char * const chname[4] = {
2863 "Front", "Surround", NULL /*CLFE*/, "Side"
2865 hda_nid_t nid;
2866 int i, err;
2868 for (i = 0; i < cfg->line_outs; i++) {
2869 hda_nid_t dac = spec->multiout.dac_nids[i];
2870 if (! dac)
2871 continue;
2872 nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];
2873 if (i == 2) {
2874 /* Center/LFE */
2875 err = add_control(spec, AD_CTL_WIDGET_VOL,
2876 "Center Playback Volume",
2877 HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));
2878 if (err < 0)
2879 return err;
2880 err = add_control(spec, AD_CTL_WIDGET_VOL,
2881 "LFE Playback Volume",
2882 HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));
2883 if (err < 0)
2884 return err;
2885 err = add_control(spec, AD_CTL_BIND_MUTE,
2886 "Center Playback Switch",
2887 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
2888 if (err < 0)
2889 return err;
2890 err = add_control(spec, AD_CTL_BIND_MUTE,
2891 "LFE Playback Switch",
2892 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
2893 if (err < 0)
2894 return err;
2895 } else {
2896 sprintf(name, "%s Playback Volume", chname[i]);
2897 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2898 HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));
2899 if (err < 0)
2900 return err;
2901 sprintf(name, "%s Playback Switch", chname[i]);
2902 err = add_control(spec, AD_CTL_BIND_MUTE, name,
2903 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
2904 if (err < 0)
2905 return err;
2908 return 0;
2911 /* add playback controls for speaker and HP outputs */
2912 static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
2913 const char *pfx)
2915 struct ad198x_spec *spec = codec->spec;
2916 hda_nid_t nid;
2917 int i, idx, err;
2918 char name[32];
2920 if (! pin)
2921 return 0;
2923 idx = ad1988_pin_idx(pin);
2924 nid = ad1988_idx_to_dac(codec, idx);
2925 /* check whether the corresponding DAC was already taken */
2926 for (i = 0; i < spec->autocfg.line_outs; i++) {
2927 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2928 hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
2929 if (dac == nid)
2930 break;
2932 if (i >= spec->autocfg.line_outs) {
2933 /* specify the DAC as the extra output */
2934 if (!spec->multiout.hp_nid)
2935 spec->multiout.hp_nid = nid;
2936 else
2937 spec->multiout.extra_out_nid[0] = nid;
2938 /* control HP volume/switch on the output mixer amp */
2939 sprintf(name, "%s Playback Volume", pfx);
2940 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2941 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2942 if (err < 0)
2943 return err;
2945 nid = ad1988_mixer_nids[idx];
2946 sprintf(name, "%s Playback Switch", pfx);
2947 if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
2948 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2949 return err;
2950 return 0;
2953 /* create input playback/capture controls for the given pin */
2954 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
2955 const char *ctlname, int ctlidx, int boost)
2957 char name[32];
2958 int err, idx;
2960 sprintf(name, "%s Playback Volume", ctlname);
2961 idx = ad1988_pin_to_loopback_idx(pin);
2962 if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2963 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2964 return err;
2965 sprintf(name, "%s Playback Switch", ctlname);
2966 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,
2967 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2968 return err;
2969 if (boost) {
2970 hda_nid_t bnid;
2971 idx = ad1988_pin_idx(pin);
2972 bnid = ad1988_boost_nids[idx];
2973 if (bnid) {
2974 sprintf(name, "%s Boost Volume", ctlname);
2975 return add_control(spec, AD_CTL_WIDGET_VOL, name,
2976 HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
2980 return 0;
2983 /* create playback/capture controls for input pins */
2984 static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
2985 const struct auto_pin_cfg *cfg)
2987 struct ad198x_spec *spec = codec->spec;
2988 struct hda_input_mux *imux = &spec->private_imux;
2989 int i, err, type, type_idx;
2991 for (i = 0; i < cfg->num_inputs; i++) {
2992 const char *label;
2993 type = cfg->inputs[i].type;
2994 label = hda_get_autocfg_input_label(codec, cfg, i);
2995 snd_hda_add_imux_item(imux, label,
2996 ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
2997 &type_idx);
2998 err = new_analog_input(spec, cfg->inputs[i].pin,
2999 label, type_idx,
3000 type == AUTO_PIN_MIC);
3001 if (err < 0)
3002 return err;
3004 snd_hda_add_imux_item(imux, "Mix", 9, NULL);
3006 if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
3007 "Analog Mix Playback Volume",
3008 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
3009 return err;
3010 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,
3011 "Analog Mix Playback Switch",
3012 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
3013 return err;
3015 return 0;
3018 static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
3019 hda_nid_t nid, int pin_type,
3020 int dac_idx)
3022 /* set as output */
3023 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
3024 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
3025 switch (nid) {
3026 case 0x11: /* port-A - DAC 04 */
3027 snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
3028 break;
3029 case 0x14: /* port-B - DAC 06 */
3030 snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
3031 break;
3032 case 0x15: /* port-C - DAC 05 */
3033 snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
3034 break;
3035 case 0x17: /* port-E - DAC 0a */
3036 snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
3037 break;
3038 case 0x13: /* mono - DAC 04 */
3039 snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
3040 break;
3044 static void ad1988_auto_init_multi_out(struct hda_codec *codec)
3046 struct ad198x_spec *spec = codec->spec;
3047 int i;
3049 for (i = 0; i < spec->autocfg.line_outs; i++) {
3050 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3051 ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
3055 static void ad1988_auto_init_extra_out(struct hda_codec *codec)
3057 struct ad198x_spec *spec = codec->spec;
3058 hda_nid_t pin;
3060 pin = spec->autocfg.speaker_pins[0];
3061 if (pin) /* connect to front */
3062 ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
3063 pin = spec->autocfg.hp_pins[0];
3064 if (pin) /* connect to front */
3065 ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3068 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
3070 struct ad198x_spec *spec = codec->spec;
3071 const struct auto_pin_cfg *cfg = &spec->autocfg;
3072 int i, idx;
3074 for (i = 0; i < cfg->num_inputs; i++) {
3075 hda_nid_t nid = cfg->inputs[i].pin;
3076 int type = cfg->inputs[i].type;
3077 switch (nid) {
3078 case 0x15: /* port-C */
3079 snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3080 break;
3081 case 0x17: /* port-E */
3082 snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3083 break;
3085 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3086 type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
3087 if (nid != AD1988_PIN_CD_NID)
3088 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3089 AMP_OUT_MUTE);
3090 idx = ad1988_pin_idx(nid);
3091 if (ad1988_boost_nids[idx])
3092 snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,
3093 AC_VERB_SET_AMP_GAIN_MUTE,
3094 AMP_OUT_ZERO);
3098 /* parse the BIOS configuration and set up the alc_spec */
3099 /* return 1 if successful, 0 if the proper config is not found, or a negative error code */
3100 static int ad1988_parse_auto_config(struct hda_codec *codec)
3102 struct ad198x_spec *spec = codec->spec;
3103 int err;
3105 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
3106 return err;
3107 if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3108 return err;
3109 if (! spec->autocfg.line_outs)
3110 return 0; /* can't find valid BIOS pin config */
3111 if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
3112 (err = ad1988_auto_create_extra_out(codec,
3113 spec->autocfg.speaker_pins[0],
3114 "Speaker")) < 0 ||
3115 (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
3116 "Headphone")) < 0 ||
3117 (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3118 return err;
3120 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3122 if (spec->autocfg.dig_outs)
3123 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3124 if (spec->autocfg.dig_in_pin)
3125 spec->dig_in_nid = AD1988_SPDIF_IN;
3127 if (spec->kctls.list)
3128 spec->mixers[spec->num_mixers++] = spec->kctls.list;
3130 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
3132 spec->input_mux = &spec->private_imux;
3134 return 1;
3137 /* init callback for auto-configuration model -- overriding the default init */
3138 static int ad1988_auto_init(struct hda_codec *codec)
3140 ad198x_init(codec);
3141 ad1988_auto_init_multi_out(codec);
3142 ad1988_auto_init_extra_out(codec);
3143 ad1988_auto_init_analog_input(codec);
3144 return 0;
3150 static const char * const ad1988_models[AD1988_MODEL_LAST] = {
3151 [AD1988_6STACK] = "6stack",
3152 [AD1988_6STACK_DIG] = "6stack-dig",
3153 [AD1988_6STACK_DIG_FP] = "6stack-dig-fp",
3154 [AD1988_3STACK] = "3stack",
3155 [AD1988_3STACK_DIG] = "3stack-dig",
3156 [AD1988_LAPTOP] = "laptop",
3157 [AD1988_LAPTOP_DIG] = "laptop-dig",
3158 [AD1988_AUTO] = "auto",
3161 static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
3162 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
3163 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
3164 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
3165 SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
3166 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
3170 static int patch_ad1988(struct hda_codec *codec)
3172 struct ad198x_spec *spec;
3173 int err, board_config;
3175 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3176 if (spec == NULL)
3177 return -ENOMEM;
3179 codec->spec = spec;
3181 if (is_rev2(codec))
3182 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
3184 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
3185 ad1988_models, ad1988_cfg_tbl);
3186 if (board_config < 0) {
3187 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3188 codec->chip_name);
3189 board_config = AD1988_AUTO;
3192 if (board_config == AD1988_AUTO) {
3193 /* automatic parse from the BIOS config */
3194 err = ad1988_parse_auto_config(codec);
3195 if (err < 0) {
3196 ad198x_free(codec);
3197 return err;
3198 } else if (! err) {
3199 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n");
3200 board_config = AD1988_6STACK;
3204 err = snd_hda_attach_beep_device(codec, 0x10);
3205 if (err < 0) {
3206 ad198x_free(codec);
3207 return err;
3209 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3211 switch (board_config) {
3212 case AD1988_6STACK:
3213 case AD1988_6STACK_DIG:
3214 case AD1988_6STACK_DIG_FP:
3215 spec->multiout.max_channels = 8;
3216 spec->multiout.num_dacs = 4;
3217 if (is_rev2(codec))
3218 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3219 else
3220 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
3221 spec->input_mux = &ad1988_6stack_capture_source;
3222 spec->num_mixers = 2;
3223 if (is_rev2(codec))
3224 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3225 else
3226 spec->mixers[0] = ad1988_6stack_mixers1;
3227 spec->mixers[1] = ad1988_6stack_mixers2;
3228 spec->num_init_verbs = 1;
3229 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3230 if (board_config == AD1988_6STACK_DIG_FP) {
3231 spec->num_mixers++;
3232 spec->mixers[2] = ad1988_6stack_fp_mixers;
3233 spec->num_init_verbs++;
3234 spec->init_verbs[1] = ad1988_6stack_fp_init_verbs;
3235 spec->slave_vols = ad1988_6stack_fp_slave_vols;
3236 spec->slave_sws = ad1988_6stack_fp_slave_sws;
3237 spec->alt_dac_nid = ad1988_alt_dac_nid;
3238 spec->stream_analog_alt_playback =
3239 &ad198x_pcm_analog_alt_playback;
3241 if ((board_config == AD1988_6STACK_DIG) ||
3242 (board_config == AD1988_6STACK_DIG_FP)) {
3243 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3244 spec->dig_in_nid = AD1988_SPDIF_IN;
3246 break;
3247 case AD1988_3STACK:
3248 case AD1988_3STACK_DIG:
3249 spec->multiout.max_channels = 6;
3250 spec->multiout.num_dacs = 3;
3251 if (is_rev2(codec))
3252 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3253 else
3254 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3255 spec->input_mux = &ad1988_6stack_capture_source;
3256 spec->channel_mode = ad1988_3stack_modes;
3257 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
3258 spec->num_mixers = 2;
3259 if (is_rev2(codec))
3260 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3261 else
3262 spec->mixers[0] = ad1988_3stack_mixers1;
3263 spec->mixers[1] = ad1988_3stack_mixers2;
3264 spec->num_init_verbs = 1;
3265 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3266 if (board_config == AD1988_3STACK_DIG)
3267 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3268 break;
3269 case AD1988_LAPTOP:
3270 case AD1988_LAPTOP_DIG:
3271 spec->multiout.max_channels = 2;
3272 spec->multiout.num_dacs = 1;
3273 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3274 spec->input_mux = &ad1988_laptop_capture_source;
3275 spec->num_mixers = 1;
3276 spec->mixers[0] = ad1988_laptop_mixers;
3277 spec->inv_eapd = 1; /* inverted EAPD */
3278 spec->num_init_verbs = 1;
3279 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3280 if (board_config == AD1988_LAPTOP_DIG)
3281 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3282 break;
3285 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3286 spec->adc_nids = ad1988_adc_nids;
3287 spec->capsrc_nids = ad1988_capsrc_nids;
3288 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3289 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3290 if (spec->multiout.dig_out_nid) {
3291 if (codec->vendor_id >= 0x11d4989a) {
3292 spec->mixers[spec->num_mixers++] =
3293 ad1989_spdif_out_mixers;
3294 spec->init_verbs[spec->num_init_verbs++] =
3295 ad1989_spdif_init_verbs;
3296 codec->slave_dig_outs = ad1989b_slave_dig_outs;
3297 } else {
3298 spec->mixers[spec->num_mixers++] =
3299 ad1988_spdif_out_mixers;
3300 spec->init_verbs[spec->num_init_verbs++] =
3301 ad1988_spdif_init_verbs;
3304 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
3305 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
3306 spec->init_verbs[spec->num_init_verbs++] =
3307 ad1988_spdif_in_init_verbs;
3310 codec->patch_ops = ad198x_patch_ops;
3311 switch (board_config) {
3312 case AD1988_AUTO:
3313 codec->patch_ops.init = ad1988_auto_init;
3314 break;
3315 case AD1988_LAPTOP:
3316 case AD1988_LAPTOP_DIG:
3317 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3318 break;
3320 #ifdef CONFIG_SND_HDA_POWER_SAVE
3321 spec->loopback.amplist = ad1988_loopbacks;
3322 #endif
3323 spec->vmaster_nid = 0x04;
3325 codec->no_trigger_sense = 1;
3326 codec->no_sticky_stream = 1;
3328 return 0;
3333 * AD1884 / AD1984
3335 * port-B - front line/mic-in
3336 * port-E - aux in/out
3337 * port-F - aux in/out
3338 * port-C - rear line/mic-in
3339 * port-D - rear line/hp-out
3340 * port-A - front line/hp-out
3342 * AD1984 = AD1884 + two digital mic-ins
3344 * FIXME:
3345 * For simplicity, we share the single DAC for both HP and line-outs
3346 * right now. The inidividual playbacks could be easily implemented,
3347 * but no build-up framework is given, so far.
3350 static const hda_nid_t ad1884_dac_nids[1] = {
3351 0x04,
3354 static const hda_nid_t ad1884_adc_nids[2] = {
3355 0x08, 0x09,
3358 static const hda_nid_t ad1884_capsrc_nids[2] = {
3359 0x0c, 0x0d,
3362 #define AD1884_SPDIF_OUT 0x02
3364 static const struct hda_input_mux ad1884_capture_source = {
3365 .num_items = 4,
3366 .items = {
3367 { "Front Mic", 0x0 },
3368 { "Mic", 0x1 },
3369 { "CD", 0x2 },
3370 { "Mix", 0x3 },
3374 static const struct snd_kcontrol_new ad1884_base_mixers[] = {
3375 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3376 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3377 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3378 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3379 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3380 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3381 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3382 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3383 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3384 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3385 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3386 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3387 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3388 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3389 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3390 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3391 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3392 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3394 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3395 /* The multiple "Capture Source" controls confuse alsamixer
3396 * So call somewhat different..
3398 /* .name = "Capture Source", */
3399 .name = "Input Source",
3400 .count = 2,
3401 .info = ad198x_mux_enum_info,
3402 .get = ad198x_mux_enum_get,
3403 .put = ad198x_mux_enum_put,
3405 /* SPDIF controls */
3406 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3408 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3409 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3410 /* identical with ad1983 */
3411 .info = ad1983_spdif_route_info,
3412 .get = ad1983_spdif_route_get,
3413 .put = ad1983_spdif_route_put,
3415 { } /* end */
3418 static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3419 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3420 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3421 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
3422 HDA_INPUT),
3423 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
3424 HDA_INPUT),
3425 { } /* end */
3429 * initialization verbs
3431 static const struct hda_verb ad1884_init_verbs[] = {
3432 /* DACs; mute as default */
3433 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3434 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3435 /* Port-A (HP) mixer */
3436 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3437 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3438 /* Port-A pin */
3439 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3440 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3441 /* HP selector - select DAC2 */
3442 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3443 /* Port-D (Line-out) mixer */
3444 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3445 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3446 /* Port-D pin */
3447 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3448 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3449 /* Mono-out mixer */
3450 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3451 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3452 /* Mono-out pin */
3453 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3454 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3455 /* Mono selector */
3456 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3457 /* Port-B (front mic) pin */
3458 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3459 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3460 /* Port-C (rear mic) pin */
3461 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3462 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3463 /* Analog mixer; mute as default */
3464 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3465 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3466 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3467 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3468 /* Analog Mix output amp */
3469 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3470 /* SPDIF output selector */
3471 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3472 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3473 { } /* end */
3476 #ifdef CONFIG_SND_HDA_POWER_SAVE
3477 static const struct hda_amp_list ad1884_loopbacks[] = {
3478 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3479 { 0x20, HDA_INPUT, 1 }, /* Mic */
3480 { 0x20, HDA_INPUT, 2 }, /* CD */
3481 { 0x20, HDA_INPUT, 4 }, /* Docking */
3482 { } /* end */
3484 #endif
3486 static const char * const ad1884_slave_vols[] = {
3487 "PCM Playback Volume",
3488 "Mic Playback Volume",
3489 "Mono Playback Volume",
3490 "Front Mic Playback Volume",
3491 "Mic Playback Volume",
3492 "CD Playback Volume",
3493 "Internal Mic Playback Volume",
3494 "Docking Mic Playback Volume",
3495 /* "Beep Playback Volume", */
3496 "IEC958 Playback Volume",
3497 NULL
3500 static int patch_ad1884(struct hda_codec *codec)
3502 struct ad198x_spec *spec;
3503 int err;
3505 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3506 if (spec == NULL)
3507 return -ENOMEM;
3509 codec->spec = spec;
3511 err = snd_hda_attach_beep_device(codec, 0x10);
3512 if (err < 0) {
3513 ad198x_free(codec);
3514 return err;
3516 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3518 spec->multiout.max_channels = 2;
3519 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3520 spec->multiout.dac_nids = ad1884_dac_nids;
3521 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3522 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3523 spec->adc_nids = ad1884_adc_nids;
3524 spec->capsrc_nids = ad1884_capsrc_nids;
3525 spec->input_mux = &ad1884_capture_source;
3526 spec->num_mixers = 1;
3527 spec->mixers[0] = ad1884_base_mixers;
3528 spec->num_init_verbs = 1;
3529 spec->init_verbs[0] = ad1884_init_verbs;
3530 spec->spdif_route = 0;
3531 #ifdef CONFIG_SND_HDA_POWER_SAVE
3532 spec->loopback.amplist = ad1884_loopbacks;
3533 #endif
3534 spec->vmaster_nid = 0x04;
3535 /* we need to cover all playback volumes */
3536 spec->slave_vols = ad1884_slave_vols;
3538 codec->patch_ops = ad198x_patch_ops;
3540 codec->no_trigger_sense = 1;
3541 codec->no_sticky_stream = 1;
3543 return 0;
3547 * Lenovo Thinkpad T61/X61
3549 static const struct hda_input_mux ad1984_thinkpad_capture_source = {
3550 .num_items = 4,
3551 .items = {
3552 { "Mic", 0x0 },
3553 { "Internal Mic", 0x1 },
3554 { "Mix", 0x3 },
3555 { "Docking-Station", 0x4 },
3561 * Dell Precision T3400
3563 static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
3564 .num_items = 3,
3565 .items = {
3566 { "Front Mic", 0x0 },
3567 { "Line-In", 0x1 },
3568 { "Mix", 0x3 },
3573 static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3574 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3575 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3576 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3577 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3578 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3579 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3580 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3581 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3582 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3583 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3584 HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3585 HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3586 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3587 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3588 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3589 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3590 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3591 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3592 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3594 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3595 /* The multiple "Capture Source" controls confuse alsamixer
3596 * So call somewhat different..
3598 /* .name = "Capture Source", */
3599 .name = "Input Source",
3600 .count = 2,
3601 .info = ad198x_mux_enum_info,
3602 .get = ad198x_mux_enum_get,
3603 .put = ad198x_mux_enum_put,
3605 /* SPDIF controls */
3606 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3608 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3609 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3610 /* identical with ad1983 */
3611 .info = ad1983_spdif_route_info,
3612 .get = ad1983_spdif_route_get,
3613 .put = ad1983_spdif_route_put,
3615 { } /* end */
3618 /* additional verbs */
3619 static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
3620 /* Port-E (docking station mic) pin */
3621 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3622 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3623 /* docking mic boost */
3624 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3625 /* Analog PC Beeper - allow firmware/ACPI beeps */
3626 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
3627 /* Analog mixer - docking mic; mute as default */
3628 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3629 /* enable EAPD bit */
3630 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3631 { } /* end */
3635 * Dell Precision T3400
3637 static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3638 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3639 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3640 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3641 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3642 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3643 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3644 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3645 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3646 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
3647 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
3648 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3649 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3650 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3651 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3652 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3654 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3655 /* The multiple "Capture Source" controls confuse alsamixer
3656 * So call somewhat different..
3658 /* .name = "Capture Source", */
3659 .name = "Input Source",
3660 .count = 2,
3661 .info = ad198x_mux_enum_info,
3662 .get = ad198x_mux_enum_get,
3663 .put = ad198x_mux_enum_put,
3665 { } /* end */
3668 /* Digial MIC ADC NID 0x05 + 0x06 */
3669 static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3670 struct hda_codec *codec,
3671 unsigned int stream_tag,
3672 unsigned int format,
3673 struct snd_pcm_substream *substream)
3675 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3676 stream_tag, 0, format);
3677 return 0;
3680 static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3681 struct hda_codec *codec,
3682 struct snd_pcm_substream *substream)
3684 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
3685 return 0;
3688 static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3689 .substreams = 2,
3690 .channels_min = 2,
3691 .channels_max = 2,
3692 .nid = 0x05,
3693 .ops = {
3694 .prepare = ad1984_pcm_dmic_prepare,
3695 .cleanup = ad1984_pcm_dmic_cleanup
3699 static int ad1984_build_pcms(struct hda_codec *codec)
3701 struct ad198x_spec *spec = codec->spec;
3702 struct hda_pcm *info;
3703 int err;
3705 err = ad198x_build_pcms(codec);
3706 if (err < 0)
3707 return err;
3709 info = spec->pcm_rec + codec->num_pcms;
3710 codec->num_pcms++;
3711 info->name = "AD1984 Digital Mic";
3712 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3713 return 0;
3716 /* models */
3717 enum {
3718 AD1984_BASIC,
3719 AD1984_THINKPAD,
3720 AD1984_DELL_DESKTOP,
3721 AD1984_MODELS
3724 static const char * const ad1984_models[AD1984_MODELS] = {
3725 [AD1984_BASIC] = "basic",
3726 [AD1984_THINKPAD] = "thinkpad",
3727 [AD1984_DELL_DESKTOP] = "dell_desktop",
3730 static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
3731 /* Lenovo Thinkpad T61/X61 */
3732 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
3733 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
3734 SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
3738 static int patch_ad1984(struct hda_codec *codec)
3740 struct ad198x_spec *spec;
3741 int board_config, err;
3743 err = patch_ad1884(codec);
3744 if (err < 0)
3745 return err;
3746 spec = codec->spec;
3747 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3748 ad1984_models, ad1984_cfg_tbl);
3749 switch (board_config) {
3750 case AD1984_BASIC:
3751 /* additional digital mics */
3752 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3753 codec->patch_ops.build_pcms = ad1984_build_pcms;
3754 break;
3755 case AD1984_THINKPAD:
3756 if (codec->subsystem_id == 0x17aa20fb) {
3757 /* Thinpad X300 does not have the ability to do SPDIF,
3758 or attach to docking station to use SPDIF */
3759 spec->multiout.dig_out_nid = 0;
3760 } else
3761 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3762 spec->input_mux = &ad1984_thinkpad_capture_source;
3763 spec->mixers[0] = ad1984_thinkpad_mixers;
3764 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
3765 spec->analog_beep = 1;
3766 break;
3767 case AD1984_DELL_DESKTOP:
3768 spec->multiout.dig_out_nid = 0;
3769 spec->input_mux = &ad1984_dell_desktop_capture_source;
3770 spec->mixers[0] = ad1984_dell_desktop_mixers;
3771 break;
3773 return 0;
3778 * AD1883 / AD1884A / AD1984A / AD1984B
3780 * port-B (0x14) - front mic-in
3781 * port-E (0x1c) - rear mic-in
3782 * port-F (0x16) - CD / ext out
3783 * port-C (0x15) - rear line-in
3784 * port-D (0x12) - rear line-out
3785 * port-A (0x11) - front hp-out
3787 * AD1984A = AD1884A + digital-mic
3788 * AD1883 = equivalent with AD1984A
3789 * AD1984B = AD1984A + extra SPDIF-out
3791 * FIXME:
3792 * We share the single DAC for both HP and line-outs (see AD1884/1984).
3795 static const hda_nid_t ad1884a_dac_nids[1] = {
3796 0x03,
3799 #define ad1884a_adc_nids ad1884_adc_nids
3800 #define ad1884a_capsrc_nids ad1884_capsrc_nids
3802 #define AD1884A_SPDIF_OUT 0x02
3804 static const struct hda_input_mux ad1884a_capture_source = {
3805 .num_items = 5,
3806 .items = {
3807 { "Front Mic", 0x0 },
3808 { "Mic", 0x4 },
3809 { "Line", 0x1 },
3810 { "CD", 0x2 },
3811 { "Mix", 0x3 },
3815 static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
3816 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3817 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3818 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3819 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3820 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3821 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3822 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3823 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3824 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3825 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3826 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3827 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3828 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3829 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3830 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3831 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3832 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3833 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
3834 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3835 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3836 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3837 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3838 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3840 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3841 /* The multiple "Capture Source" controls confuse alsamixer
3842 * So call somewhat different..
3844 /* .name = "Capture Source", */
3845 .name = "Input Source",
3846 .count = 2,
3847 .info = ad198x_mux_enum_info,
3848 .get = ad198x_mux_enum_get,
3849 .put = ad198x_mux_enum_put,
3851 /* SPDIF controls */
3852 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3854 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3855 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3856 /* identical with ad1983 */
3857 .info = ad1983_spdif_route_info,
3858 .get = ad1983_spdif_route_get,
3859 .put = ad1983_spdif_route_put,
3861 { } /* end */
3865 * initialization verbs
3867 static const struct hda_verb ad1884a_init_verbs[] = {
3868 /* DACs; unmute as default */
3869 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3870 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3871 /* Port-A (HP) mixer - route only from analog mixer */
3872 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3873 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3874 /* Port-A pin */
3875 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3876 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3877 /* Port-D (Line-out) mixer - route only from analog mixer */
3878 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3879 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3880 /* Port-D pin */
3881 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3882 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3883 /* Mono-out mixer - route only from analog mixer */
3884 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3885 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3886 /* Mono-out pin */
3887 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3888 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3889 /* Port-B (front mic) pin */
3890 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3891 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3892 /* Port-C (rear line-in) pin */
3893 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3894 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3895 /* Port-E (rear mic) pin */
3896 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3897 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3898 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
3899 /* Port-F (CD) pin */
3900 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3901 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3902 /* Analog mixer; mute as default */
3903 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3904 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3905 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3906 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3907 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
3908 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3909 /* Analog Mix output amp */
3910 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3911 /* capture sources */
3912 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
3913 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3914 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
3915 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3916 /* SPDIF output amp */
3917 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3918 { } /* end */
3921 #ifdef CONFIG_SND_HDA_POWER_SAVE
3922 static const struct hda_amp_list ad1884a_loopbacks[] = {
3923 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3924 { 0x20, HDA_INPUT, 1 }, /* Mic */
3925 { 0x20, HDA_INPUT, 2 }, /* CD */
3926 { 0x20, HDA_INPUT, 4 }, /* Docking */
3927 { } /* end */
3929 #endif
3932 * Laptop model
3934 * Port A: Headphone jack
3935 * Port B: MIC jack
3936 * Port C: Internal MIC
3937 * Port D: Dock Line Out (if enabled)
3938 * Port E: Dock Line In (if enabled)
3939 * Port F: Internal speakers
3942 static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
3943 struct snd_ctl_elem_value *ucontrol)
3945 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3946 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3947 int mute = (!ucontrol->value.integer.value[0] &&
3948 !ucontrol->value.integer.value[1]);
3949 /* toggle GPIO1 according to the mute state */
3950 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
3951 mute ? 0x02 : 0x0);
3952 return ret;
3955 static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
3956 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3958 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3959 .name = "Master Playback Switch",
3960 .subdevice = HDA_SUBDEV_AMP_FLAG,
3961 .info = snd_hda_mixer_amp_switch_info,
3962 .get = snd_hda_mixer_amp_switch_get,
3963 .put = ad1884a_mobile_master_sw_put,
3964 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3966 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3967 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3968 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3969 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3970 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3971 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3972 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3973 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3974 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3975 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3976 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3977 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3978 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3979 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3980 { } /* end */
3983 static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
3984 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3985 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
3987 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3988 .name = "Master Playback Switch",
3989 .subdevice = HDA_SUBDEV_AMP_FLAG,
3990 .info = snd_hda_mixer_amp_switch_info,
3991 .get = snd_hda_mixer_amp_switch_get,
3992 .put = ad1884a_mobile_master_sw_put,
3993 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3995 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3996 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3997 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
3998 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
3999 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4000 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4001 { } /* end */
4004 /* mute internal speaker if HP is plugged */
4005 static void ad1884a_hp_automute(struct hda_codec *codec)
4007 unsigned int present;
4009 present = snd_hda_jack_detect(codec, 0x11);
4010 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4011 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4012 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4013 present ? 0x00 : 0x02);
4016 /* switch to external mic if plugged */
4017 static void ad1884a_hp_automic(struct hda_codec *codec)
4019 unsigned int present;
4021 present = snd_hda_jack_detect(codec, 0x14);
4022 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
4023 present ? 0 : 1);
4026 #define AD1884A_HP_EVENT 0x37
4027 #define AD1884A_MIC_EVENT 0x36
4029 /* unsolicited event for HP jack sensing */
4030 static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4032 switch (res >> 26) {
4033 case AD1884A_HP_EVENT:
4034 ad1884a_hp_automute(codec);
4035 break;
4036 case AD1884A_MIC_EVENT:
4037 ad1884a_hp_automic(codec);
4038 break;
4042 /* initialize jack-sensing, too */
4043 static int ad1884a_hp_init(struct hda_codec *codec)
4045 ad198x_init(codec);
4046 ad1884a_hp_automute(codec);
4047 ad1884a_hp_automic(codec);
4048 return 0;
4051 /* mute internal speaker if HP or docking HP is plugged */
4052 static void ad1884a_laptop_automute(struct hda_codec *codec)
4054 unsigned int present;
4056 present = snd_hda_jack_detect(codec, 0x11);
4057 if (!present)
4058 present = snd_hda_jack_detect(codec, 0x12);
4059 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4060 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4061 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4062 present ? 0x00 : 0x02);
4065 /* switch to external mic if plugged */
4066 static void ad1884a_laptop_automic(struct hda_codec *codec)
4068 unsigned int idx;
4070 if (snd_hda_jack_detect(codec, 0x14))
4071 idx = 0;
4072 else if (snd_hda_jack_detect(codec, 0x1c))
4073 idx = 4;
4074 else
4075 idx = 1;
4076 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
4079 /* unsolicited event for HP jack sensing */
4080 static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
4081 unsigned int res)
4083 switch (res >> 26) {
4084 case AD1884A_HP_EVENT:
4085 ad1884a_laptop_automute(codec);
4086 break;
4087 case AD1884A_MIC_EVENT:
4088 ad1884a_laptop_automic(codec);
4089 break;
4093 /* initialize jack-sensing, too */
4094 static int ad1884a_laptop_init(struct hda_codec *codec)
4096 ad198x_init(codec);
4097 ad1884a_laptop_automute(codec);
4098 ad1884a_laptop_automic(codec);
4099 return 0;
4102 /* additional verbs for laptop model */
4103 static const struct hda_verb ad1884a_laptop_verbs[] = {
4104 /* Port-A (HP) pin - always unmuted */
4105 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4106 /* Port-F (int speaker) mixer - route only from analog mixer */
4107 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4108 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4109 /* Port-F (int speaker) pin */
4110 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4111 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4112 /* required for compaq 6530s/6531s speaker output */
4113 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4114 /* Port-C pin - internal mic-in */
4115 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4116 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4117 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4118 /* Port-D (docking line-out) pin - default unmuted */
4119 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4120 /* analog mix */
4121 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4122 /* unsolicited event for pin-sense */
4123 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4124 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4125 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4126 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4127 /* allow to touch GPIO1 (for mute control) */
4128 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4129 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4130 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4131 { } /* end */
4134 static const struct hda_verb ad1884a_mobile_verbs[] = {
4135 /* DACs; unmute as default */
4136 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4137 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4138 /* Port-A (HP) mixer - route only from analog mixer */
4139 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4140 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4141 /* Port-A pin */
4142 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4143 /* Port-A (HP) pin - always unmuted */
4144 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4145 /* Port-B (mic jack) pin */
4146 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4147 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4148 /* Port-C (int mic) pin */
4149 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4150 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4151 /* Port-F (int speaker) mixer - route only from analog mixer */
4152 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4153 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4154 /* Port-F pin */
4155 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4156 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4157 /* Analog mixer; mute as default */
4158 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4159 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4160 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4161 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4162 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4163 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4164 /* Analog Mix output amp */
4165 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4166 /* capture sources */
4167 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4168 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4169 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4170 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4171 /* unsolicited event for pin-sense */
4172 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4173 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4174 /* allow to touch GPIO1 (for mute control) */
4175 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4176 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4177 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4178 { } /* end */
4182 * Thinkpad X300
4183 * 0x11 - HP
4184 * 0x12 - speaker
4185 * 0x14 - mic-in
4186 * 0x17 - built-in mic
4189 static const struct hda_verb ad1984a_thinkpad_verbs[] = {
4190 /* HP unmute */
4191 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4192 /* analog mix */
4193 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4194 /* turn on EAPD */
4195 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4196 /* unsolicited event for pin-sense */
4197 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4198 /* internal mic - dmic */
4199 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4200 /* set magic COEFs for dmic */
4201 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4202 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4203 { } /* end */
4206 static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
4207 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4208 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4209 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4210 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4211 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4212 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4213 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4214 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
4215 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4216 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4218 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4219 .name = "Capture Source",
4220 .info = ad198x_mux_enum_info,
4221 .get = ad198x_mux_enum_get,
4222 .put = ad198x_mux_enum_put,
4224 { } /* end */
4227 static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
4228 .num_items = 3,
4229 .items = {
4230 { "Mic", 0x0 },
4231 { "Internal Mic", 0x5 },
4232 { "Mix", 0x3 },
4236 /* mute internal speaker if HP is plugged */
4237 static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4239 unsigned int present;
4241 present = snd_hda_jack_detect(codec, 0x11);
4242 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4243 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4246 /* unsolicited event for HP jack sensing */
4247 static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4248 unsigned int res)
4250 if ((res >> 26) != AD1884A_HP_EVENT)
4251 return;
4252 ad1984a_thinkpad_automute(codec);
4255 /* initialize jack-sensing, too */
4256 static int ad1984a_thinkpad_init(struct hda_codec *codec)
4258 ad198x_init(codec);
4259 ad1984a_thinkpad_automute(codec);
4260 return 0;
4264 * Precision R5500
4265 * 0x12 - HP/line-out
4266 * 0x13 - speaker (mono)
4267 * 0x15 - mic-in
4270 static const struct hda_verb ad1984a_precision_verbs[] = {
4271 /* Unmute main output path */
4272 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4273 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
4274 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */
4275 /* Analog mixer; mute as default */
4276 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4277 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4278 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4279 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4280 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4281 /* Select mic as input */
4282 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
4283 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */
4284 /* Configure as mic */
4285 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4286 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4287 /* HP unmute */
4288 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4289 /* turn on EAPD */
4290 {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4291 /* unsolicited event for pin-sense */
4292 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4293 { } /* end */
4296 static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
4297 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4298 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4299 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4300 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4301 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4302 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4303 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
4304 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4305 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT),
4306 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4307 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4308 { } /* end */
4312 /* mute internal speaker if HP is plugged */
4313 static void ad1984a_precision_automute(struct hda_codec *codec)
4315 unsigned int present;
4317 present = snd_hda_jack_detect(codec, 0x12);
4318 snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
4319 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4323 /* unsolicited event for HP jack sensing */
4324 static void ad1984a_precision_unsol_event(struct hda_codec *codec,
4325 unsigned int res)
4327 if ((res >> 26) != AD1884A_HP_EVENT)
4328 return;
4329 ad1984a_precision_automute(codec);
4332 /* initialize jack-sensing, too */
4333 static int ad1984a_precision_init(struct hda_codec *codec)
4335 ad198x_init(codec);
4336 ad1984a_precision_automute(codec);
4337 return 0;
4342 * HP Touchsmart
4343 * port-A (0x11) - front hp-out
4344 * port-B (0x14) - unused
4345 * port-C (0x15) - unused
4346 * port-D (0x12) - rear line out
4347 * port-E (0x1c) - front mic-in
4348 * port-F (0x16) - Internal speakers
4349 * digital-mic (0x17) - Internal mic
4352 static const struct hda_verb ad1984a_touchsmart_verbs[] = {
4353 /* DACs; unmute as default */
4354 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4355 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4356 /* Port-A (HP) mixer - route only from analog mixer */
4357 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4358 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4359 /* Port-A pin */
4360 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4361 /* Port-A (HP) pin - always unmuted */
4362 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4363 /* Port-E (int speaker) mixer - route only from analog mixer */
4364 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4365 /* Port-E pin */
4366 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4367 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4368 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4369 /* Port-F (int speaker) mixer - route only from analog mixer */
4370 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4371 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4372 /* Port-F pin */
4373 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4374 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4375 /* Analog mixer; mute as default */
4376 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4377 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4378 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4379 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4380 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4381 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4382 /* Analog Mix output amp */
4383 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4384 /* capture sources */
4385 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4386 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4387 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4388 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4389 /* unsolicited event for pin-sense */
4390 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4391 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4392 /* allow to touch GPIO1 (for mute control) */
4393 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4394 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4395 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4396 /* internal mic - dmic */
4397 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4398 /* set magic COEFs for dmic */
4399 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4400 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4401 { } /* end */
4404 static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
4405 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4406 /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4408 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4409 .subdevice = HDA_SUBDEV_AMP_FLAG,
4410 .name = "Master Playback Switch",
4411 .info = snd_hda_mixer_amp_switch_info,
4412 .get = snd_hda_mixer_amp_switch_get,
4413 .put = ad1884a_mobile_master_sw_put,
4414 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4416 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4417 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4418 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4419 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4420 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
4421 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
4422 { } /* end */
4425 /* switch to external mic if plugged */
4426 static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4428 if (snd_hda_jack_detect(codec, 0x1c))
4429 snd_hda_codec_write(codec, 0x0c, 0,
4430 AC_VERB_SET_CONNECT_SEL, 0x4);
4431 else
4432 snd_hda_codec_write(codec, 0x0c, 0,
4433 AC_VERB_SET_CONNECT_SEL, 0x5);
4437 /* unsolicited event for HP jack sensing */
4438 static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4439 unsigned int res)
4441 switch (res >> 26) {
4442 case AD1884A_HP_EVENT:
4443 ad1884a_hp_automute(codec);
4444 break;
4445 case AD1884A_MIC_EVENT:
4446 ad1984a_touchsmart_automic(codec);
4447 break;
4451 /* initialize jack-sensing, too */
4452 static int ad1984a_touchsmart_init(struct hda_codec *codec)
4454 ad198x_init(codec);
4455 ad1884a_hp_automute(codec);
4456 ad1984a_touchsmart_automic(codec);
4457 return 0;
4464 enum {
4465 AD1884A_DESKTOP,
4466 AD1884A_LAPTOP,
4467 AD1884A_MOBILE,
4468 AD1884A_THINKPAD,
4469 AD1984A_TOUCHSMART,
4470 AD1984A_PRECISION,
4471 AD1884A_MODELS
4474 static const char * const ad1884a_models[AD1884A_MODELS] = {
4475 [AD1884A_DESKTOP] = "desktop",
4476 [AD1884A_LAPTOP] = "laptop",
4477 [AD1884A_MOBILE] = "mobile",
4478 [AD1884A_THINKPAD] = "thinkpad",
4479 [AD1984A_TOUCHSMART] = "touchsmart",
4480 [AD1984A_PRECISION] = "precision",
4483 static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
4484 SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
4485 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
4486 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
4487 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
4488 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
4489 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
4490 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4491 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
4492 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
4493 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
4494 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
4498 static int patch_ad1884a(struct hda_codec *codec)
4500 struct ad198x_spec *spec;
4501 int err, board_config;
4503 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4504 if (spec == NULL)
4505 return -ENOMEM;
4507 codec->spec = spec;
4509 err = snd_hda_attach_beep_device(codec, 0x10);
4510 if (err < 0) {
4511 ad198x_free(codec);
4512 return err;
4514 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4516 spec->multiout.max_channels = 2;
4517 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4518 spec->multiout.dac_nids = ad1884a_dac_nids;
4519 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4520 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4521 spec->adc_nids = ad1884a_adc_nids;
4522 spec->capsrc_nids = ad1884a_capsrc_nids;
4523 spec->input_mux = &ad1884a_capture_source;
4524 spec->num_mixers = 1;
4525 spec->mixers[0] = ad1884a_base_mixers;
4526 spec->num_init_verbs = 1;
4527 spec->init_verbs[0] = ad1884a_init_verbs;
4528 spec->spdif_route = 0;
4529 #ifdef CONFIG_SND_HDA_POWER_SAVE
4530 spec->loopback.amplist = ad1884a_loopbacks;
4531 #endif
4532 codec->patch_ops = ad198x_patch_ops;
4534 /* override some parameters */
4535 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
4536 ad1884a_models,
4537 ad1884a_cfg_tbl);
4538 switch (board_config) {
4539 case AD1884A_LAPTOP:
4540 spec->mixers[0] = ad1884a_laptop_mixers;
4541 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4542 spec->multiout.dig_out_nid = 0;
4543 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4544 codec->patch_ops.init = ad1884a_laptop_init;
4545 /* set the upper-limit for mixer amp to 0dB for avoiding the
4546 * possible damage by overloading
4548 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4549 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4550 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4551 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4552 (1 << AC_AMPCAP_MUTE_SHIFT));
4553 break;
4554 case AD1884A_MOBILE:
4555 spec->mixers[0] = ad1884a_mobile_mixers;
4556 spec->init_verbs[0] = ad1884a_mobile_verbs;
4557 spec->multiout.dig_out_nid = 0;
4558 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4559 codec->patch_ops.init = ad1884a_hp_init;
4560 /* set the upper-limit for mixer amp to 0dB for avoiding the
4561 * possible damage by overloading
4563 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4564 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4565 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4566 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4567 (1 << AC_AMPCAP_MUTE_SHIFT));
4568 break;
4569 case AD1884A_THINKPAD:
4570 spec->mixers[0] = ad1984a_thinkpad_mixers;
4571 spec->init_verbs[spec->num_init_verbs++] =
4572 ad1984a_thinkpad_verbs;
4573 spec->multiout.dig_out_nid = 0;
4574 spec->input_mux = &ad1984a_thinkpad_capture_source;
4575 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4576 codec->patch_ops.init = ad1984a_thinkpad_init;
4577 break;
4578 case AD1984A_PRECISION:
4579 spec->mixers[0] = ad1984a_precision_mixers;
4580 spec->init_verbs[spec->num_init_verbs++] =
4581 ad1984a_precision_verbs;
4582 spec->multiout.dig_out_nid = 0;
4583 codec->patch_ops.unsol_event = ad1984a_precision_unsol_event;
4584 codec->patch_ops.init = ad1984a_precision_init;
4585 break;
4586 case AD1984A_TOUCHSMART:
4587 spec->mixers[0] = ad1984a_touchsmart_mixers;
4588 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4589 spec->multiout.dig_out_nid = 0;
4590 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4591 codec->patch_ops.init = ad1984a_touchsmart_init;
4592 /* set the upper-limit for mixer amp to 0dB for avoiding the
4593 * possible damage by overloading
4595 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4596 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4597 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4598 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4599 (1 << AC_AMPCAP_MUTE_SHIFT));
4600 break;
4603 codec->no_trigger_sense = 1;
4604 codec->no_sticky_stream = 1;
4606 return 0;
4611 * AD1882 / AD1882A
4613 * port-A - front hp-out
4614 * port-B - front mic-in
4615 * port-C - rear line-in, shared surr-out (3stack)
4616 * port-D - rear line-out
4617 * port-E - rear mic-in, shared clfe-out (3stack)
4618 * port-F - rear surr-out (6stack)
4619 * port-G - rear clfe-out (6stack)
4622 static const hda_nid_t ad1882_dac_nids[3] = {
4623 0x04, 0x03, 0x05
4626 static const hda_nid_t ad1882_adc_nids[2] = {
4627 0x08, 0x09,
4630 static const hda_nid_t ad1882_capsrc_nids[2] = {
4631 0x0c, 0x0d,
4634 #define AD1882_SPDIF_OUT 0x02
4636 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
4637 static const struct hda_input_mux ad1882_capture_source = {
4638 .num_items = 5,
4639 .items = {
4640 { "Front Mic", 0x1 },
4641 { "Mic", 0x4 },
4642 { "Line", 0x2 },
4643 { "CD", 0x3 },
4644 { "Mix", 0x7 },
4648 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
4649 static const struct hda_input_mux ad1882a_capture_source = {
4650 .num_items = 5,
4651 .items = {
4652 { "Front Mic", 0x1 },
4653 { "Mic", 0x4},
4654 { "Line", 0x2 },
4655 { "Digital Mic", 0x06 },
4656 { "Mix", 0x7 },
4660 static const struct snd_kcontrol_new ad1882_base_mixers[] = {
4661 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4662 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4663 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4664 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4665 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4666 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4667 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4668 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
4670 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
4671 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
4672 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
4673 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4674 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4675 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4676 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4678 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4679 /* The multiple "Capture Source" controls confuse alsamixer
4680 * So call somewhat different..
4682 /* .name = "Capture Source", */
4683 .name = "Input Source",
4684 .count = 2,
4685 .info = ad198x_mux_enum_info,
4686 .get = ad198x_mux_enum_get,
4687 .put = ad198x_mux_enum_put,
4689 /* SPDIF controls */
4690 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4692 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4693 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4694 /* identical with ad1983 */
4695 .info = ad1983_spdif_route_info,
4696 .get = ad1983_spdif_route_get,
4697 .put = ad1983_spdif_route_put,
4699 { } /* end */
4702 static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4703 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4704 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4705 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4706 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4707 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4708 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4709 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4710 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4711 { } /* end */
4714 static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4715 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4716 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4717 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4718 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4719 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4720 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4721 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4722 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4723 HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
4724 { } /* end */
4727 static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4728 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4729 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4730 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4732 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4733 .name = "Channel Mode",
4734 .info = ad198x_ch_mode_info,
4735 .get = ad198x_ch_mode_get,
4736 .put = ad198x_ch_mode_put,
4738 { } /* end */
4741 static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4742 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4743 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4744 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4745 { } /* end */
4748 static const struct hda_verb ad1882_ch2_init[] = {
4749 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4750 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4751 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4752 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4753 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4754 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4755 { } /* end */
4758 static const struct hda_verb ad1882_ch4_init[] = {
4759 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4760 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4761 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4762 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4763 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4764 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4765 { } /* end */
4768 static const struct hda_verb ad1882_ch6_init[] = {
4769 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4770 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4771 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4772 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4773 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4774 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4775 { } /* end */
4778 static const struct hda_channel_mode ad1882_modes[3] = {
4779 { 2, ad1882_ch2_init },
4780 { 4, ad1882_ch4_init },
4781 { 6, ad1882_ch6_init },
4785 * initialization verbs
4787 static const struct hda_verb ad1882_init_verbs[] = {
4788 /* DACs; mute as default */
4789 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4790 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4791 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4792 /* Port-A (HP) mixer */
4793 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4794 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4795 /* Port-A pin */
4796 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4797 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4798 /* HP selector - select DAC2 */
4799 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4800 /* Port-D (Line-out) mixer */
4801 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4802 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4803 /* Port-D pin */
4804 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4805 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4806 /* Mono-out mixer */
4807 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4808 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4809 /* Mono-out pin */
4810 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4811 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4812 /* Port-B (front mic) pin */
4813 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4814 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4815 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4816 /* Port-C (line-in) pin */
4817 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4818 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4819 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4820 /* Port-C mixer - mute as input */
4821 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4822 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4823 /* Port-E (mic-in) pin */
4824 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4825 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4826 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4827 /* Port-E mixer - mute as input */
4828 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4829 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4830 /* Port-F (surround) */
4831 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4832 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4833 /* Port-G (CLFE) */
4834 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4835 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4836 /* Analog mixer; mute as default */
4837 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
4838 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4839 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4840 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4841 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4842 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4843 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4844 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4845 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4846 /* Analog Mix output amp */
4847 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
4848 /* SPDIF output selector */
4849 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4850 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
4851 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4852 { } /* end */
4855 #ifdef CONFIG_SND_HDA_POWER_SAVE
4856 static const struct hda_amp_list ad1882_loopbacks[] = {
4857 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4858 { 0x20, HDA_INPUT, 1 }, /* Mic */
4859 { 0x20, HDA_INPUT, 4 }, /* Line */
4860 { 0x20, HDA_INPUT, 6 }, /* CD */
4861 { } /* end */
4863 #endif
4865 /* models */
4866 enum {
4867 AD1882_3STACK,
4868 AD1882_6STACK,
4869 AD1882_MODELS
4872 static const char * const ad1882_models[AD1986A_MODELS] = {
4873 [AD1882_3STACK] = "3stack",
4874 [AD1882_6STACK] = "6stack",
4878 static int patch_ad1882(struct hda_codec *codec)
4880 struct ad198x_spec *spec;
4881 int err, board_config;
4883 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4884 if (spec == NULL)
4885 return -ENOMEM;
4887 codec->spec = spec;
4889 err = snd_hda_attach_beep_device(codec, 0x10);
4890 if (err < 0) {
4891 ad198x_free(codec);
4892 return err;
4894 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4896 spec->multiout.max_channels = 6;
4897 spec->multiout.num_dacs = 3;
4898 spec->multiout.dac_nids = ad1882_dac_nids;
4899 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
4900 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
4901 spec->adc_nids = ad1882_adc_nids;
4902 spec->capsrc_nids = ad1882_capsrc_nids;
4903 if (codec->vendor_id == 0x11d41882)
4904 spec->input_mux = &ad1882_capture_source;
4905 else
4906 spec->input_mux = &ad1882a_capture_source;
4907 spec->num_mixers = 2;
4908 spec->mixers[0] = ad1882_base_mixers;
4909 if (codec->vendor_id == 0x11d41882)
4910 spec->mixers[1] = ad1882_loopback_mixers;
4911 else
4912 spec->mixers[1] = ad1882a_loopback_mixers;
4913 spec->num_init_verbs = 1;
4914 spec->init_verbs[0] = ad1882_init_verbs;
4915 spec->spdif_route = 0;
4916 #ifdef CONFIG_SND_HDA_POWER_SAVE
4917 spec->loopback.amplist = ad1882_loopbacks;
4918 #endif
4919 spec->vmaster_nid = 0x04;
4921 codec->patch_ops = ad198x_patch_ops;
4923 /* override some parameters */
4924 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
4925 ad1882_models, NULL);
4926 switch (board_config) {
4927 default:
4928 case AD1882_3STACK:
4929 spec->num_mixers = 3;
4930 spec->mixers[2] = ad1882_3stack_mixers;
4931 spec->channel_mode = ad1882_modes;
4932 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
4933 spec->need_dac_fix = 1;
4934 spec->multiout.max_channels = 2;
4935 spec->multiout.num_dacs = 1;
4936 break;
4937 case AD1882_6STACK:
4938 spec->num_mixers = 3;
4939 spec->mixers[2] = ad1882_6stack_mixers;
4940 break;
4943 codec->no_trigger_sense = 1;
4944 codec->no_sticky_stream = 1;
4946 return 0;
4951 * patch entries
4953 static const struct hda_codec_preset snd_hda_preset_analog[] = {
4954 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
4955 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
4956 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
4957 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
4958 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
4959 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
4960 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
4961 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
4962 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
4963 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
4964 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
4965 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
4966 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
4967 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
4968 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
4969 {} /* terminator */
4972 MODULE_ALIAS("snd-hda-codec-id:11d4*");
4974 MODULE_LICENSE("GPL");
4975 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
4977 static struct hda_codec_preset_list analog_list = {
4978 .preset = snd_hda_preset_analog,
4979 .owner = THIS_MODULE,
4982 static int __init patch_analog_init(void)
4984 return snd_hda_add_codec_preset(&analog_list);
4987 static void __exit patch_analog_exit(void)
4989 snd_hda_delete_codec_preset(&analog_list);
4992 module_init(patch_analog_init)
4993 module_exit(patch_analog_exit)