spi-topcliff-pch: Fix issue for transmitting over 4KByte
[zen-stable.git] / sound / pci / hda / patch_analog.c
blob9cb14b42dfff48f890ee10871dea7fffb14b7054
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>
26 #include <linux/module.h>
28 #include <sound/core.h>
29 #include "hda_codec.h"
30 #include "hda_local.h"
31 #include "hda_beep.h"
32 #include "hda_jack.h"
34 struct ad198x_spec {
35 const struct snd_kcontrol_new *mixers[6];
36 int num_mixers;
37 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
38 const struct hda_verb *init_verbs[6]; /* initialization verbs
39 * don't forget NULL termination!
41 unsigned int num_init_verbs;
43 /* playback */
44 struct hda_multi_out multiout; /* playback set-up
45 * max_channels, dacs must be set
46 * dig_out_nid and hp_nid are optional
48 unsigned int cur_eapd;
49 unsigned int need_dac_fix;
51 const hda_nid_t *alt_dac_nid;
52 const struct hda_pcm_stream *stream_analog_alt_playback;
53 int independent_hp;
54 int num_active_streams;
56 /* capture */
57 unsigned int num_adc_nids;
58 const hda_nid_t *adc_nids;
59 hda_nid_t dig_in_nid; /* digital-in NID; optional */
61 /* capture source */
62 const struct hda_input_mux *input_mux;
63 const hda_nid_t *capsrc_nids;
64 unsigned int cur_mux[3];
66 /* channel model */
67 const struct hda_channel_mode *channel_mode;
68 int num_channel_mode;
70 /* PCM information */
71 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
73 unsigned int spdif_route;
75 /* dynamic controls, init_verbs and input_mux */
76 struct auto_pin_cfg autocfg;
77 struct snd_array kctls;
78 struct hda_input_mux private_imux;
79 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
81 unsigned int jack_present: 1;
82 unsigned int inv_jack_detect: 1;/* inverted jack-detection */
83 unsigned int inv_eapd: 1; /* inverted EAPD implementation */
84 unsigned int analog_beep: 1; /* analog beep input present */
86 #ifdef CONFIG_SND_HDA_POWER_SAVE
87 struct hda_loopback_check loopback;
88 #endif
89 /* for virtual master */
90 hda_nid_t vmaster_nid;
91 const char * const *slave_vols;
92 const char * const *slave_sws;
96 * input MUX handling (common part)
98 static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
100 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
101 struct ad198x_spec *spec = codec->spec;
103 return snd_hda_input_mux_info(spec->input_mux, uinfo);
106 static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
108 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
109 struct ad198x_spec *spec = codec->spec;
110 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
112 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
113 return 0;
116 static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
118 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
119 struct ad198x_spec *spec = codec->spec;
120 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
122 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
123 spec->capsrc_nids[adc_idx],
124 &spec->cur_mux[adc_idx]);
128 * initialization (common callbacks)
130 static int ad198x_init(struct hda_codec *codec)
132 struct ad198x_spec *spec = codec->spec;
133 int i;
135 for (i = 0; i < spec->num_init_verbs; i++)
136 snd_hda_sequence_write(codec, spec->init_verbs[i]);
137 return 0;
140 static const char * const ad_slave_vols[] = {
141 "Front Playback Volume",
142 "Surround Playback Volume",
143 "Center Playback Volume",
144 "LFE Playback Volume",
145 "Side Playback Volume",
146 "Headphone Playback Volume",
147 "Mono Playback Volume",
148 "Speaker Playback Volume",
149 "IEC958 Playback Volume",
150 NULL
153 static const char * const ad_slave_sws[] = {
154 "Front Playback Switch",
155 "Surround Playback Switch",
156 "Center Playback Switch",
157 "LFE Playback Switch",
158 "Side Playback Switch",
159 "Headphone Playback Switch",
160 "Mono Playback Switch",
161 "Speaker Playback Switch",
162 "IEC958 Playback Switch",
163 NULL
166 static const char * const ad1988_6stack_fp_slave_vols[] = {
167 "Front Playback Volume",
168 "Surround Playback Volume",
169 "Center Playback Volume",
170 "LFE Playback Volume",
171 "Side Playback Volume",
172 "IEC958 Playback Volume",
173 NULL
176 static const char * const ad1988_6stack_fp_slave_sws[] = {
177 "Front Playback Switch",
178 "Surround Playback Switch",
179 "Center Playback Switch",
180 "LFE Playback Switch",
181 "Side Playback Switch",
182 "IEC958 Playback Switch",
183 NULL
185 static void ad198x_free_kctls(struct hda_codec *codec);
187 #ifdef CONFIG_SND_HDA_INPUT_BEEP
188 /* additional beep mixers; the actual parameters are overwritten at build */
189 static const struct snd_kcontrol_new ad_beep_mixer[] = {
190 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
191 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
192 { } /* end */
195 static const struct snd_kcontrol_new ad_beep2_mixer[] = {
196 HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
197 HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
198 { } /* end */
201 #define set_beep_amp(spec, nid, idx, dir) \
202 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
203 #else
204 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
205 #endif
207 static int ad198x_build_controls(struct hda_codec *codec)
209 struct ad198x_spec *spec = codec->spec;
210 struct snd_kcontrol *kctl;
211 unsigned int i;
212 int err;
214 for (i = 0; i < spec->num_mixers; i++) {
215 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
216 if (err < 0)
217 return err;
219 if (spec->multiout.dig_out_nid) {
220 err = snd_hda_create_spdif_out_ctls(codec,
221 spec->multiout.dig_out_nid,
222 spec->multiout.dig_out_nid);
223 if (err < 0)
224 return err;
225 err = snd_hda_create_spdif_share_sw(codec,
226 &spec->multiout);
227 if (err < 0)
228 return err;
229 spec->multiout.share_spdif = 1;
231 if (spec->dig_in_nid) {
232 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
233 if (err < 0)
234 return err;
237 /* create beep controls if needed */
238 #ifdef CONFIG_SND_HDA_INPUT_BEEP
239 if (spec->beep_amp) {
240 const struct snd_kcontrol_new *knew;
241 knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
242 for ( ; knew->name; knew++) {
243 struct snd_kcontrol *kctl;
244 kctl = snd_ctl_new1(knew, codec);
245 if (!kctl)
246 return -ENOMEM;
247 kctl->private_value = spec->beep_amp;
248 err = snd_hda_ctl_add(codec, 0, kctl);
249 if (err < 0)
250 return err;
253 #endif
255 /* if we have no master control, let's create it */
256 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
257 unsigned int vmaster_tlv[4];
258 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
259 HDA_OUTPUT, vmaster_tlv);
260 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
261 vmaster_tlv,
262 (spec->slave_vols ?
263 spec->slave_vols : ad_slave_vols));
264 if (err < 0)
265 return err;
267 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
268 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
269 NULL,
270 (spec->slave_sws ?
271 spec->slave_sws : ad_slave_sws));
272 if (err < 0)
273 return err;
276 ad198x_free_kctls(codec); /* no longer needed */
278 /* assign Capture Source enums to NID */
279 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
280 if (!kctl)
281 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
282 for (i = 0; kctl && i < kctl->count; i++) {
283 err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
284 if (err < 0)
285 return err;
288 /* assign IEC958 enums to NID */
289 kctl = snd_hda_find_mixer_ctl(codec,
290 SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
291 if (kctl) {
292 err = snd_hda_add_nid(codec, kctl, 0,
293 spec->multiout.dig_out_nid);
294 if (err < 0)
295 return err;
298 return 0;
301 #ifdef CONFIG_SND_HDA_POWER_SAVE
302 static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
304 struct ad198x_spec *spec = codec->spec;
305 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
307 #endif
309 static void activate_ctl(struct hda_codec *codec, const char *name, int active)
311 struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
312 if (ctl) {
313 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
314 ctl->vd[0].access |= active ? 0 :
315 SNDRV_CTL_ELEM_ACCESS_INACTIVE;
316 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
317 ctl->vd[0].access |= active ?
318 SNDRV_CTL_ELEM_ACCESS_WRITE : 0;
319 snd_ctl_notify(codec->bus->card,
320 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
324 static void set_stream_active(struct hda_codec *codec, bool active)
326 struct ad198x_spec *spec = codec->spec;
327 if (active)
328 spec->num_active_streams++;
329 else
330 spec->num_active_streams--;
331 activate_ctl(codec, "Independent HP", spec->num_active_streams == 0);
334 static int ad1988_independent_hp_info(struct snd_kcontrol *kcontrol,
335 struct snd_ctl_elem_info *uinfo)
337 static const char * const texts[] = { "OFF", "ON", NULL};
338 int index;
339 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
340 uinfo->count = 1;
341 uinfo->value.enumerated.items = 2;
342 index = uinfo->value.enumerated.item;
343 if (index >= 2)
344 index = 1;
345 strcpy(uinfo->value.enumerated.name, texts[index]);
346 return 0;
349 static int ad1988_independent_hp_get(struct snd_kcontrol *kcontrol,
350 struct snd_ctl_elem_value *ucontrol)
352 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
353 struct ad198x_spec *spec = codec->spec;
354 ucontrol->value.enumerated.item[0] = spec->independent_hp;
355 return 0;
358 static int ad1988_independent_hp_put(struct snd_kcontrol *kcontrol,
359 struct snd_ctl_elem_value *ucontrol)
361 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
362 struct ad198x_spec *spec = codec->spec;
363 unsigned int select = ucontrol->value.enumerated.item[0];
364 if (spec->independent_hp != select) {
365 spec->independent_hp = select;
366 if (spec->independent_hp)
367 spec->multiout.hp_nid = 0;
368 else
369 spec->multiout.hp_nid = spec->alt_dac_nid[0];
370 return 1;
372 return 0;
376 * Analog playback callbacks
378 static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
379 struct hda_codec *codec,
380 struct snd_pcm_substream *substream)
382 struct ad198x_spec *spec = codec->spec;
383 int err;
384 set_stream_active(codec, true);
385 err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
386 hinfo);
387 if (err < 0) {
388 set_stream_active(codec, false);
389 return err;
391 return 0;
394 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
395 struct hda_codec *codec,
396 unsigned int stream_tag,
397 unsigned int format,
398 struct snd_pcm_substream *substream)
400 struct ad198x_spec *spec = codec->spec;
401 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
402 format, substream);
405 static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
406 struct hda_codec *codec,
407 struct snd_pcm_substream *substream)
409 struct ad198x_spec *spec = codec->spec;
410 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
413 static int ad198x_playback_pcm_close(struct hda_pcm_stream *hinfo,
414 struct hda_codec *codec,
415 struct snd_pcm_substream *substream)
417 set_stream_active(codec, false);
418 return 0;
421 static int ad1988_alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
422 struct hda_codec *codec,
423 struct snd_pcm_substream *substream)
425 struct ad198x_spec *spec = codec->spec;
426 if (!spec->independent_hp)
427 return -EBUSY;
428 set_stream_active(codec, true);
429 return 0;
432 static int ad1988_alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
433 struct hda_codec *codec,
434 struct snd_pcm_substream *substream)
436 set_stream_active(codec, false);
437 return 0;
440 static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
441 .substreams = 1,
442 .channels_min = 2,
443 .channels_max = 2,
444 .ops = {
445 .open = ad1988_alt_playback_pcm_open,
446 .close = ad1988_alt_playback_pcm_close
451 * Digital out
453 static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
454 struct hda_codec *codec,
455 struct snd_pcm_substream *substream)
457 struct ad198x_spec *spec = codec->spec;
458 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
461 static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
462 struct hda_codec *codec,
463 struct snd_pcm_substream *substream)
465 struct ad198x_spec *spec = codec->spec;
466 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
469 static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
470 struct hda_codec *codec,
471 unsigned int stream_tag,
472 unsigned int format,
473 struct snd_pcm_substream *substream)
475 struct ad198x_spec *spec = codec->spec;
476 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
477 format, substream);
480 static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
481 struct hda_codec *codec,
482 struct snd_pcm_substream *substream)
484 struct ad198x_spec *spec = codec->spec;
485 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
489 * Analog capture
491 static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
492 struct hda_codec *codec,
493 unsigned int stream_tag,
494 unsigned int format,
495 struct snd_pcm_substream *substream)
497 struct ad198x_spec *spec = codec->spec;
498 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
499 stream_tag, 0, format);
500 return 0;
503 static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
504 struct hda_codec *codec,
505 struct snd_pcm_substream *substream)
507 struct ad198x_spec *spec = codec->spec;
508 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
509 return 0;
514 static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
515 .substreams = 1,
516 .channels_min = 2,
517 .channels_max = 6, /* changed later */
518 .nid = 0, /* fill later */
519 .ops = {
520 .open = ad198x_playback_pcm_open,
521 .prepare = ad198x_playback_pcm_prepare,
522 .cleanup = ad198x_playback_pcm_cleanup,
523 .close = ad198x_playback_pcm_close
527 static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
528 .substreams = 1,
529 .channels_min = 2,
530 .channels_max = 2,
531 .nid = 0, /* fill later */
532 .ops = {
533 .prepare = ad198x_capture_pcm_prepare,
534 .cleanup = ad198x_capture_pcm_cleanup
538 static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
539 .substreams = 1,
540 .channels_min = 2,
541 .channels_max = 2,
542 .nid = 0, /* fill later */
543 .ops = {
544 .open = ad198x_dig_playback_pcm_open,
545 .close = ad198x_dig_playback_pcm_close,
546 .prepare = ad198x_dig_playback_pcm_prepare,
547 .cleanup = ad198x_dig_playback_pcm_cleanup
551 static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
552 .substreams = 1,
553 .channels_min = 2,
554 .channels_max = 2,
555 /* NID is set in alc_build_pcms */
558 static int ad198x_build_pcms(struct hda_codec *codec)
560 struct ad198x_spec *spec = codec->spec;
561 struct hda_pcm *info = spec->pcm_rec;
563 codec->num_pcms = 1;
564 codec->pcm_info = info;
566 info->name = "AD198x Analog";
567 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
568 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
569 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
570 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
571 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
572 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
574 if (spec->multiout.dig_out_nid) {
575 info++;
576 codec->num_pcms++;
577 info->name = "AD198x Digital";
578 info->pcm_type = HDA_PCM_TYPE_SPDIF;
579 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
580 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
581 if (spec->dig_in_nid) {
582 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
583 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
587 if (spec->alt_dac_nid && spec->stream_analog_alt_playback) {
588 codec->num_pcms++;
589 info = spec->pcm_rec + 2;
590 info->name = "AD198x Headphone";
591 info->pcm_type = HDA_PCM_TYPE_AUDIO;
592 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
593 *spec->stream_analog_alt_playback;
594 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
595 spec->alt_dac_nid[0];
598 return 0;
601 static void ad198x_free_kctls(struct hda_codec *codec)
603 struct ad198x_spec *spec = codec->spec;
605 if (spec->kctls.list) {
606 struct snd_kcontrol_new *kctl = spec->kctls.list;
607 int i;
608 for (i = 0; i < spec->kctls.used; i++)
609 kfree(kctl[i].name);
611 snd_array_free(&spec->kctls);
614 static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
615 hda_nid_t hp)
617 struct ad198x_spec *spec = codec->spec;
618 if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
619 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
620 !spec->inv_eapd ? 0x00 : 0x02);
621 if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
622 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
623 !spec->inv_eapd ? 0x00 : 0x02);
626 static void ad198x_power_eapd(struct hda_codec *codec)
628 /* We currently only handle front, HP */
629 switch (codec->vendor_id) {
630 case 0x11d41882:
631 case 0x11d4882a:
632 case 0x11d41884:
633 case 0x11d41984:
634 case 0x11d41883:
635 case 0x11d4184a:
636 case 0x11d4194a:
637 case 0x11d4194b:
638 case 0x11d41988:
639 case 0x11d4198b:
640 case 0x11d4989a:
641 case 0x11d4989b:
642 ad198x_power_eapd_write(codec, 0x12, 0x11);
643 break;
644 case 0x11d41981:
645 case 0x11d41983:
646 ad198x_power_eapd_write(codec, 0x05, 0x06);
647 break;
648 case 0x11d41986:
649 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
650 break;
654 static void ad198x_shutup(struct hda_codec *codec)
656 snd_hda_shutup_pins(codec);
657 ad198x_power_eapd(codec);
660 static void ad198x_free(struct hda_codec *codec)
662 struct ad198x_spec *spec = codec->spec;
664 if (!spec)
665 return;
667 ad198x_shutup(codec);
668 ad198x_free_kctls(codec);
669 kfree(spec);
670 snd_hda_detach_beep_device(codec);
673 #ifdef CONFIG_PM
674 static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
676 ad198x_shutup(codec);
677 return 0;
679 #endif
681 static const struct hda_codec_ops ad198x_patch_ops = {
682 .build_controls = ad198x_build_controls,
683 .build_pcms = ad198x_build_pcms,
684 .init = ad198x_init,
685 .free = ad198x_free,
686 #ifdef CONFIG_SND_HDA_POWER_SAVE
687 .check_power_status = ad198x_check_power_status,
688 #endif
689 #ifdef CONFIG_PM
690 .suspend = ad198x_suspend,
691 #endif
692 .reboot_notify = ad198x_shutup,
697 * EAPD control
698 * the private value = nid
700 #define ad198x_eapd_info snd_ctl_boolean_mono_info
702 static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
703 struct snd_ctl_elem_value *ucontrol)
705 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
706 struct ad198x_spec *spec = codec->spec;
707 if (spec->inv_eapd)
708 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
709 else
710 ucontrol->value.integer.value[0] = spec->cur_eapd;
711 return 0;
714 static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
715 struct snd_ctl_elem_value *ucontrol)
717 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
718 struct ad198x_spec *spec = codec->spec;
719 hda_nid_t nid = kcontrol->private_value & 0xff;
720 unsigned int eapd;
721 eapd = !!ucontrol->value.integer.value[0];
722 if (spec->inv_eapd)
723 eapd = !eapd;
724 if (eapd == spec->cur_eapd)
725 return 0;
726 spec->cur_eapd = eapd;
727 snd_hda_codec_write_cache(codec, nid,
728 0, AC_VERB_SET_EAPD_BTLENABLE,
729 eapd ? 0x02 : 0x00);
730 return 1;
733 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
734 struct snd_ctl_elem_info *uinfo);
735 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
736 struct snd_ctl_elem_value *ucontrol);
737 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
738 struct snd_ctl_elem_value *ucontrol);
742 * AD1986A specific
745 #define AD1986A_SPDIF_OUT 0x02
746 #define AD1986A_FRONT_DAC 0x03
747 #define AD1986A_SURR_DAC 0x04
748 #define AD1986A_CLFE_DAC 0x05
749 #define AD1986A_ADC 0x06
751 static const hda_nid_t ad1986a_dac_nids[3] = {
752 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
754 static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
755 static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
757 static const struct hda_input_mux ad1986a_capture_source = {
758 .num_items = 7,
759 .items = {
760 { "Mic", 0x0 },
761 { "CD", 0x1 },
762 { "Aux", 0x3 },
763 { "Line", 0x4 },
764 { "Mix", 0x5 },
765 { "Mono", 0x6 },
766 { "Phone", 0x7 },
771 static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
772 .ops = &snd_hda_bind_vol,
773 .values = {
774 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
775 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
776 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
781 static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
782 .ops = &snd_hda_bind_sw,
783 .values = {
784 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
785 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
786 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
792 * mixers
794 static const struct snd_kcontrol_new ad1986a_mixers[] = {
796 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
798 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
799 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
800 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
801 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
802 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
803 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
804 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
805 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
806 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
807 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
808 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
809 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
810 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
811 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
812 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
813 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
814 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
815 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
816 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
817 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
818 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
819 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
820 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 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,
830 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
831 { } /* end */
834 /* additional mixers for 3stack mode */
835 static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
837 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
838 .name = "Channel Mode",
839 .info = ad198x_ch_mode_info,
840 .get = ad198x_ch_mode_get,
841 .put = ad198x_ch_mode_put,
843 { } /* end */
846 /* laptop model - 2ch only */
847 static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
849 /* master controls both pins 0x1a and 0x1b */
850 static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
851 .ops = &snd_hda_bind_vol,
852 .values = {
853 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
854 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
859 static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
860 .ops = &snd_hda_bind_sw,
861 .values = {
862 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
863 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
868 static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
869 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
870 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
871 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
872 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
873 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
874 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
875 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
876 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
877 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
878 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
879 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
880 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
881 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
883 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
884 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
885 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
886 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
888 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
889 .name = "Capture Source",
890 .info = ad198x_mux_enum_info,
891 .get = ad198x_mux_enum_get,
892 .put = ad198x_mux_enum_put,
894 { } /* end */
897 /* laptop-eapd model - 2ch only */
899 static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
900 .num_items = 3,
901 .items = {
902 { "Mic", 0x0 },
903 { "Internal Mic", 0x4 },
904 { "Mix", 0x5 },
908 static const struct hda_input_mux ad1986a_automic_capture_source = {
909 .num_items = 2,
910 .items = {
911 { "Mic", 0x0 },
912 { "Mix", 0x5 },
916 static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
917 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
918 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
919 { } /* end */
922 static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
923 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
924 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
925 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
926 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
927 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
928 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
929 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
931 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
932 .name = "Capture Source",
933 .info = ad198x_mux_enum_info,
934 .get = ad198x_mux_enum_get,
935 .put = ad198x_mux_enum_put,
938 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
939 .name = "External Amplifier",
940 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
941 .info = ad198x_eapd_info,
942 .get = ad198x_eapd_get,
943 .put = ad198x_eapd_put,
944 .private_value = 0x1b, /* port-D */
946 { } /* end */
949 static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
950 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
951 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
952 { } /* end */
955 /* re-connect the mic boost input according to the jack sensing */
956 static void ad1986a_automic(struct hda_codec *codec)
958 unsigned int present;
959 present = snd_hda_jack_detect(codec, 0x1f);
960 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
961 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
962 present ? 0 : 2);
965 #define AD1986A_MIC_EVENT 0x36
967 static void ad1986a_automic_unsol_event(struct hda_codec *codec,
968 unsigned int res)
970 if ((res >> 26) != AD1986A_MIC_EVENT)
971 return;
972 ad1986a_automic(codec);
975 static int ad1986a_automic_init(struct hda_codec *codec)
977 ad198x_init(codec);
978 ad1986a_automic(codec);
979 return 0;
982 /* laptop-automute - 2ch only */
984 static void ad1986a_update_hp(struct hda_codec *codec)
986 struct ad198x_spec *spec = codec->spec;
987 unsigned int mute;
989 if (spec->jack_present)
990 mute = HDA_AMP_MUTE; /* mute internal speaker */
991 else
992 /* unmute internal speaker if necessary */
993 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
994 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
995 HDA_AMP_MUTE, mute);
998 static void ad1986a_hp_automute(struct hda_codec *codec)
1000 struct ad198x_spec *spec = codec->spec;
1002 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
1003 if (spec->inv_jack_detect)
1004 spec->jack_present = !spec->jack_present;
1005 ad1986a_update_hp(codec);
1008 #define AD1986A_HP_EVENT 0x37
1010 static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
1012 if ((res >> 26) != AD1986A_HP_EVENT)
1013 return;
1014 ad1986a_hp_automute(codec);
1017 static int ad1986a_hp_init(struct hda_codec *codec)
1019 ad198x_init(codec);
1020 ad1986a_hp_automute(codec);
1021 return 0;
1024 /* bind hp and internal speaker mute (with plug check) */
1025 static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1026 struct snd_ctl_elem_value *ucontrol)
1028 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1029 long *valp = ucontrol->value.integer.value;
1030 int change;
1032 change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
1033 HDA_AMP_MUTE,
1034 valp[0] ? 0 : HDA_AMP_MUTE);
1035 change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
1036 HDA_AMP_MUTE,
1037 valp[1] ? 0 : HDA_AMP_MUTE);
1038 if (change)
1039 ad1986a_update_hp(codec);
1040 return change;
1043 static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
1044 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
1046 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1047 .name = "Master Playback Switch",
1048 .subdevice = HDA_SUBDEV_AMP_FLAG,
1049 .info = snd_hda_mixer_amp_switch_info,
1050 .get = snd_hda_mixer_amp_switch_get,
1051 .put = ad1986a_hp_master_sw_put,
1052 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
1054 { } /* end */
1059 * initialization verbs
1061 static const struct hda_verb ad1986a_init_verbs[] = {
1062 /* Front, Surround, CLFE DAC; mute as default */
1063 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1064 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1065 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1066 /* Downmix - off */
1067 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1068 /* HP, Line-Out, Surround, CLFE selectors */
1069 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
1070 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
1071 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1072 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1073 /* Mono selector */
1074 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
1075 /* Mic selector: Mic 1/2 pin */
1076 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1077 /* Line-in selector: Line-in */
1078 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
1079 /* Mic 1/2 swap */
1080 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
1081 /* Record selector: mic */
1082 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
1083 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
1084 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1085 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1086 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1087 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1088 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1089 /* PC beep */
1090 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
1091 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
1092 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1093 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1094 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1095 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1096 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1097 /* HP Pin */
1098 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1099 /* Front, Surround, CLFE Pins */
1100 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1101 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1102 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1103 /* Mono Pin */
1104 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1105 /* Mic Pin */
1106 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1107 /* Line, Aux, CD, Beep-In Pin */
1108 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1109 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1110 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1111 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1112 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1113 { } /* end */
1116 static const struct hda_verb ad1986a_ch2_init[] = {
1117 /* Surround out -> Line In */
1118 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1119 /* Line-in selectors */
1120 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
1121 /* CLFE -> Mic in */
1122 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1123 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
1124 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1125 { } /* end */
1128 static const struct hda_verb ad1986a_ch4_init[] = {
1129 /* Surround out -> Surround */
1130 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1131 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1132 /* CLFE -> Mic in */
1133 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1134 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1135 { } /* end */
1138 static const struct hda_verb ad1986a_ch6_init[] = {
1139 /* Surround out -> Surround out */
1140 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1141 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1142 /* CLFE -> CLFE */
1143 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1144 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
1145 { } /* end */
1148 static const struct hda_channel_mode ad1986a_modes[3] = {
1149 { 2, ad1986a_ch2_init },
1150 { 4, ad1986a_ch4_init },
1151 { 6, ad1986a_ch6_init },
1154 /* eapd initialization */
1155 static const struct hda_verb ad1986a_eapd_init_verbs[] = {
1156 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1160 static const struct hda_verb ad1986a_automic_verbs[] = {
1161 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1162 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1163 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
1164 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1165 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
1169 /* Ultra initialization */
1170 static const struct hda_verb ad1986a_ultra_init[] = {
1171 /* eapd initialization */
1172 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1173 /* CLFE -> Mic in */
1174 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
1175 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1176 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
1177 { } /* end */
1180 /* pin sensing on HP jack */
1181 static const struct hda_verb ad1986a_hp_init_verbs[] = {
1182 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1186 static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
1187 unsigned int res)
1189 switch (res >> 26) {
1190 case AD1986A_HP_EVENT:
1191 ad1986a_hp_automute(codec);
1192 break;
1193 case AD1986A_MIC_EVENT:
1194 ad1986a_automic(codec);
1195 break;
1199 static int ad1986a_samsung_p50_init(struct hda_codec *codec)
1201 ad198x_init(codec);
1202 ad1986a_hp_automute(codec);
1203 ad1986a_automic(codec);
1204 return 0;
1208 /* models */
1209 enum {
1210 AD1986A_6STACK,
1211 AD1986A_3STACK,
1212 AD1986A_LAPTOP,
1213 AD1986A_LAPTOP_EAPD,
1214 AD1986A_LAPTOP_AUTOMUTE,
1215 AD1986A_ULTRA,
1216 AD1986A_SAMSUNG,
1217 AD1986A_SAMSUNG_P50,
1218 AD1986A_MODELS
1221 static const char * const ad1986a_models[AD1986A_MODELS] = {
1222 [AD1986A_6STACK] = "6stack",
1223 [AD1986A_3STACK] = "3stack",
1224 [AD1986A_LAPTOP] = "laptop",
1225 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
1226 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
1227 [AD1986A_ULTRA] = "ultra",
1228 [AD1986A_SAMSUNG] = "samsung",
1229 [AD1986A_SAMSUNG_P50] = "samsung-p50",
1232 static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
1233 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
1234 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
1235 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
1236 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
1237 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
1238 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
1239 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
1240 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
1241 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
1242 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
1243 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1244 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1245 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1246 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1247 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
1248 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
1249 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
1250 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
1251 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
1252 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
1253 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
1254 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
1255 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
1256 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
1257 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
1258 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
1259 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
1263 #ifdef CONFIG_SND_HDA_POWER_SAVE
1264 static const struct hda_amp_list ad1986a_loopbacks[] = {
1265 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1266 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1267 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1268 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1269 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1270 { } /* end */
1272 #endif
1274 static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1276 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
1277 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1280 static int patch_ad1986a(struct hda_codec *codec)
1282 struct ad198x_spec *spec;
1283 int err, board_config;
1285 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1286 if (spec == NULL)
1287 return -ENOMEM;
1289 codec->spec = spec;
1291 err = snd_hda_attach_beep_device(codec, 0x19);
1292 if (err < 0) {
1293 ad198x_free(codec);
1294 return err;
1296 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1298 spec->multiout.max_channels = 6;
1299 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1300 spec->multiout.dac_nids = ad1986a_dac_nids;
1301 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
1302 spec->num_adc_nids = 1;
1303 spec->adc_nids = ad1986a_adc_nids;
1304 spec->capsrc_nids = ad1986a_capsrc_nids;
1305 spec->input_mux = &ad1986a_capture_source;
1306 spec->num_mixers = 1;
1307 spec->mixers[0] = ad1986a_mixers;
1308 spec->num_init_verbs = 1;
1309 spec->init_verbs[0] = ad1986a_init_verbs;
1310 #ifdef CONFIG_SND_HDA_POWER_SAVE
1311 spec->loopback.amplist = ad1986a_loopbacks;
1312 #endif
1313 spec->vmaster_nid = 0x1b;
1314 spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
1316 codec->patch_ops = ad198x_patch_ops;
1318 /* override some parameters */
1319 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1320 ad1986a_models,
1321 ad1986a_cfg_tbl);
1322 switch (board_config) {
1323 case AD1986A_3STACK:
1324 spec->num_mixers = 2;
1325 spec->mixers[1] = ad1986a_3st_mixers;
1326 spec->num_init_verbs = 2;
1327 spec->init_verbs[1] = ad1986a_ch2_init;
1328 spec->channel_mode = ad1986a_modes;
1329 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
1330 spec->need_dac_fix = 1;
1331 spec->multiout.max_channels = 2;
1332 spec->multiout.num_dacs = 1;
1333 break;
1334 case AD1986A_LAPTOP:
1335 spec->mixers[0] = ad1986a_laptop_mixers;
1336 spec->multiout.max_channels = 2;
1337 spec->multiout.num_dacs = 1;
1338 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1339 break;
1340 case AD1986A_LAPTOP_EAPD:
1341 spec->num_mixers = 3;
1342 spec->mixers[0] = ad1986a_laptop_master_mixers;
1343 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1344 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1345 spec->num_init_verbs = 2;
1346 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1347 spec->multiout.max_channels = 2;
1348 spec->multiout.num_dacs = 1;
1349 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1350 if (!is_jack_available(codec, 0x25))
1351 spec->multiout.dig_out_nid = 0;
1352 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1353 break;
1354 case AD1986A_SAMSUNG:
1355 spec->num_mixers = 2;
1356 spec->mixers[0] = ad1986a_laptop_master_mixers;
1357 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1358 spec->num_init_verbs = 3;
1359 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1360 spec->init_verbs[2] = ad1986a_automic_verbs;
1361 spec->multiout.max_channels = 2;
1362 spec->multiout.num_dacs = 1;
1363 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1364 if (!is_jack_available(codec, 0x25))
1365 spec->multiout.dig_out_nid = 0;
1366 spec->input_mux = &ad1986a_automic_capture_source;
1367 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1368 codec->patch_ops.init = ad1986a_automic_init;
1369 break;
1370 case AD1986A_SAMSUNG_P50:
1371 spec->num_mixers = 2;
1372 spec->mixers[0] = ad1986a_automute_master_mixers;
1373 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1374 spec->num_init_verbs = 4;
1375 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1376 spec->init_verbs[2] = ad1986a_automic_verbs;
1377 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1378 spec->multiout.max_channels = 2;
1379 spec->multiout.num_dacs = 1;
1380 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1381 if (!is_jack_available(codec, 0x25))
1382 spec->multiout.dig_out_nid = 0;
1383 spec->input_mux = &ad1986a_automic_capture_source;
1384 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1385 codec->patch_ops.init = ad1986a_samsung_p50_init;
1386 break;
1387 case AD1986A_LAPTOP_AUTOMUTE:
1388 spec->num_mixers = 3;
1389 spec->mixers[0] = ad1986a_automute_master_mixers;
1390 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1391 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1392 spec->num_init_verbs = 3;
1393 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1394 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1395 spec->multiout.max_channels = 2;
1396 spec->multiout.num_dacs = 1;
1397 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1398 if (!is_jack_available(codec, 0x25))
1399 spec->multiout.dig_out_nid = 0;
1400 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1401 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1402 codec->patch_ops.init = ad1986a_hp_init;
1403 /* Lenovo N100 seems to report the reversed bit
1404 * for HP jack-sensing
1406 spec->inv_jack_detect = 1;
1407 break;
1408 case AD1986A_ULTRA:
1409 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1410 spec->num_init_verbs = 2;
1411 spec->init_verbs[1] = ad1986a_ultra_init;
1412 spec->multiout.max_channels = 2;
1413 spec->multiout.num_dacs = 1;
1414 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1415 spec->multiout.dig_out_nid = 0;
1416 break;
1419 /* AD1986A has a hardware problem that it can't share a stream
1420 * with multiple output pins. The copy of front to surrounds
1421 * causes noisy or silent outputs at a certain timing, e.g.
1422 * changing the volume.
1423 * So, let's disable the shared stream.
1425 spec->multiout.no_share_stream = 1;
1427 codec->no_trigger_sense = 1;
1428 codec->no_sticky_stream = 1;
1430 return 0;
1434 * AD1983 specific
1437 #define AD1983_SPDIF_OUT 0x02
1438 #define AD1983_DAC 0x03
1439 #define AD1983_ADC 0x04
1441 static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
1442 static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
1443 static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
1445 static const struct hda_input_mux ad1983_capture_source = {
1446 .num_items = 4,
1447 .items = {
1448 { "Mic", 0x0 },
1449 { "Line", 0x1 },
1450 { "Mix", 0x2 },
1451 { "Mix Mono", 0x3 },
1456 * SPDIF playback route
1458 static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1460 static const char * const texts[] = { "PCM", "ADC" };
1462 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1463 uinfo->count = 1;
1464 uinfo->value.enumerated.items = 2;
1465 if (uinfo->value.enumerated.item > 1)
1466 uinfo->value.enumerated.item = 1;
1467 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1468 return 0;
1471 static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1473 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1474 struct ad198x_spec *spec = codec->spec;
1476 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1477 return 0;
1480 static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1482 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1483 struct ad198x_spec *spec = codec->spec;
1485 if (ucontrol->value.enumerated.item[0] > 1)
1486 return -EINVAL;
1487 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1488 spec->spdif_route = ucontrol->value.enumerated.item[0];
1489 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1490 AC_VERB_SET_CONNECT_SEL,
1491 spec->spdif_route);
1492 return 1;
1494 return 0;
1497 static const struct snd_kcontrol_new ad1983_mixers[] = {
1498 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1499 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1500 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1501 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1502 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1503 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1504 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1505 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1506 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1507 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1508 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1509 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1510 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
1511 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1512 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1514 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1515 .name = "Capture Source",
1516 .info = ad198x_mux_enum_info,
1517 .get = ad198x_mux_enum_get,
1518 .put = ad198x_mux_enum_put,
1521 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1522 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1523 .info = ad1983_spdif_route_info,
1524 .get = ad1983_spdif_route_get,
1525 .put = ad1983_spdif_route_put,
1527 { } /* end */
1530 static const struct hda_verb ad1983_init_verbs[] = {
1531 /* Front, HP, Mono; mute as default */
1532 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1533 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1534 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1535 /* Beep, PCM, Mic, Line-In: mute */
1536 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1537 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1538 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1539 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1540 /* Front, HP selectors; from Mix */
1541 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1542 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1543 /* Mono selector; from Mix */
1544 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1545 /* Mic selector; Mic */
1546 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1547 /* Line-in selector: Line-in */
1548 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1549 /* Mic boost: 0dB */
1550 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1551 /* Record selector: mic */
1552 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1553 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1554 /* SPDIF route: PCM */
1555 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1556 /* Front Pin */
1557 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1558 /* HP Pin */
1559 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1560 /* Mono Pin */
1561 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1562 /* Mic Pin */
1563 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1564 /* Line Pin */
1565 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1566 { } /* end */
1569 #ifdef CONFIG_SND_HDA_POWER_SAVE
1570 static const struct hda_amp_list ad1983_loopbacks[] = {
1571 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
1572 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1573 { } /* end */
1575 #endif
1577 static int patch_ad1983(struct hda_codec *codec)
1579 struct ad198x_spec *spec;
1580 int err;
1582 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1583 if (spec == NULL)
1584 return -ENOMEM;
1586 codec->spec = spec;
1588 err = snd_hda_attach_beep_device(codec, 0x10);
1589 if (err < 0) {
1590 ad198x_free(codec);
1591 return err;
1593 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1595 spec->multiout.max_channels = 2;
1596 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1597 spec->multiout.dac_nids = ad1983_dac_nids;
1598 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
1599 spec->num_adc_nids = 1;
1600 spec->adc_nids = ad1983_adc_nids;
1601 spec->capsrc_nids = ad1983_capsrc_nids;
1602 spec->input_mux = &ad1983_capture_source;
1603 spec->num_mixers = 1;
1604 spec->mixers[0] = ad1983_mixers;
1605 spec->num_init_verbs = 1;
1606 spec->init_verbs[0] = ad1983_init_verbs;
1607 spec->spdif_route = 0;
1608 #ifdef CONFIG_SND_HDA_POWER_SAVE
1609 spec->loopback.amplist = ad1983_loopbacks;
1610 #endif
1611 spec->vmaster_nid = 0x05;
1613 codec->patch_ops = ad198x_patch_ops;
1615 codec->no_trigger_sense = 1;
1616 codec->no_sticky_stream = 1;
1618 return 0;
1623 * AD1981 HD specific
1626 #define AD1981_SPDIF_OUT 0x02
1627 #define AD1981_DAC 0x03
1628 #define AD1981_ADC 0x04
1630 static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
1631 static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
1632 static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
1634 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
1635 static const struct hda_input_mux ad1981_capture_source = {
1636 .num_items = 7,
1637 .items = {
1638 { "Front Mic", 0x0 },
1639 { "Line", 0x1 },
1640 { "Mix", 0x2 },
1641 { "Mix Mono", 0x3 },
1642 { "CD", 0x4 },
1643 { "Mic", 0x6 },
1644 { "Aux", 0x7 },
1648 static const struct snd_kcontrol_new ad1981_mixers[] = {
1649 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1650 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1651 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1652 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1653 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1654 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1655 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1656 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1657 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1658 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1659 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1660 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1661 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1662 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1663 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1664 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1665 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1666 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1667 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1668 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
1669 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1670 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1672 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1673 .name = "Capture Source",
1674 .info = ad198x_mux_enum_info,
1675 .get = ad198x_mux_enum_get,
1676 .put = ad198x_mux_enum_put,
1678 /* identical with AD1983 */
1680 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1681 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1682 .info = ad1983_spdif_route_info,
1683 .get = ad1983_spdif_route_get,
1684 .put = ad1983_spdif_route_put,
1686 { } /* end */
1689 static const struct hda_verb ad1981_init_verbs[] = {
1690 /* Front, HP, Mono; mute as default */
1691 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1692 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1693 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1694 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1695 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1696 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1697 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1698 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1699 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1700 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1701 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1702 /* Front, HP selectors; from Mix */
1703 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1704 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1705 /* Mono selector; from Mix */
1706 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1707 /* Mic Mixer; select Front Mic */
1708 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1709 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1710 /* Mic boost: 0dB */
1711 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1712 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1713 /* Record selector: Front mic */
1714 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1715 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1716 /* SPDIF route: PCM */
1717 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1718 /* Front Pin */
1719 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1720 /* HP Pin */
1721 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1722 /* Mono Pin */
1723 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1724 /* Front & Rear Mic Pins */
1725 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1726 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1727 /* Line Pin */
1728 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1729 /* Digital Beep */
1730 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1731 /* Line-Out as Input: disabled */
1732 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1733 { } /* end */
1736 #ifdef CONFIG_SND_HDA_POWER_SAVE
1737 static const struct hda_amp_list ad1981_loopbacks[] = {
1738 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1739 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1740 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1741 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1742 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1743 { } /* end */
1745 #endif
1748 * Patch for HP nx6320
1750 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
1751 * speaker output enabled _and_ mute-LED off.
1754 #define AD1981_HP_EVENT 0x37
1755 #define AD1981_MIC_EVENT 0x38
1757 static const struct hda_verb ad1981_hp_init_verbs[] = {
1758 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1759 /* pin sensing on HP and Mic jacks */
1760 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1761 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1765 /* turn on/off EAPD (+ mute HP) as a master switch */
1766 static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1767 struct snd_ctl_elem_value *ucontrol)
1769 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1770 struct ad198x_spec *spec = codec->spec;
1772 if (! ad198x_eapd_put(kcontrol, ucontrol))
1773 return 0;
1774 /* change speaker pin appropriately */
1775 snd_hda_codec_write(codec, 0x05, 0,
1776 AC_VERB_SET_PIN_WIDGET_CONTROL,
1777 spec->cur_eapd ? PIN_OUT : 0);
1778 /* toggle HP mute appropriately */
1779 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1780 HDA_AMP_MUTE,
1781 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
1782 return 1;
1785 /* bind volumes of both NID 0x05 and 0x06 */
1786 static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1787 .ops = &snd_hda_bind_vol,
1788 .values = {
1789 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1790 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1795 /* mute internal speaker if HP is plugged */
1796 static void ad1981_hp_automute(struct hda_codec *codec)
1798 unsigned int present;
1800 present = snd_hda_jack_detect(codec, 0x06);
1801 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1802 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1805 /* toggle input of built-in and mic jack appropriately */
1806 static void ad1981_hp_automic(struct hda_codec *codec)
1808 static const struct hda_verb mic_jack_on[] = {
1809 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1810 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1813 static const struct hda_verb mic_jack_off[] = {
1814 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1815 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1818 unsigned int present;
1820 present = snd_hda_jack_detect(codec, 0x08);
1821 if (present)
1822 snd_hda_sequence_write(codec, mic_jack_on);
1823 else
1824 snd_hda_sequence_write(codec, mic_jack_off);
1827 /* unsolicited event for HP jack sensing */
1828 static void ad1981_hp_unsol_event(struct hda_codec *codec,
1829 unsigned int res)
1831 res >>= 26;
1832 switch (res) {
1833 case AD1981_HP_EVENT:
1834 ad1981_hp_automute(codec);
1835 break;
1836 case AD1981_MIC_EVENT:
1837 ad1981_hp_automic(codec);
1838 break;
1842 static const struct hda_input_mux ad1981_hp_capture_source = {
1843 .num_items = 3,
1844 .items = {
1845 { "Mic", 0x0 },
1846 { "Docking-Station", 0x1 },
1847 { "Mix", 0x2 },
1851 static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
1852 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
1854 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1855 .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
1856 .name = "Master Playback Switch",
1857 .info = ad198x_eapd_info,
1858 .get = ad198x_eapd_get,
1859 .put = ad1981_hp_master_sw_put,
1860 .private_value = 0x05,
1862 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1863 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1864 #if 0
1865 /* FIXME: analog mic/line loopback doesn't work with my tests...
1866 * (although recording is OK)
1868 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1869 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1870 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1871 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1872 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1873 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1874 /* FIXME: does this laptop have analog CD connection? */
1875 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1876 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1877 #endif
1878 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1879 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
1880 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1881 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1883 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1884 .name = "Capture Source",
1885 .info = ad198x_mux_enum_info,
1886 .get = ad198x_mux_enum_get,
1887 .put = ad198x_mux_enum_put,
1889 { } /* end */
1892 /* initialize jack-sensing, too */
1893 static int ad1981_hp_init(struct hda_codec *codec)
1895 ad198x_init(codec);
1896 ad1981_hp_automute(codec);
1897 ad1981_hp_automic(codec);
1898 return 0;
1901 /* configuration for Toshiba Laptops */
1902 static const struct hda_verb ad1981_toshiba_init_verbs[] = {
1903 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
1904 /* pin sensing on HP and Mic jacks */
1905 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1906 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1910 static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1911 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1912 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1916 /* configuration for Lenovo Thinkpad T60 */
1917 static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1918 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1919 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1920 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1921 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1922 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1923 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1924 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1925 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1926 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1927 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1928 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1930 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1931 .name = "Capture Source",
1932 .info = ad198x_mux_enum_info,
1933 .get = ad198x_mux_enum_get,
1934 .put = ad198x_mux_enum_put,
1936 /* identical with AD1983 */
1938 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1939 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1940 .info = ad1983_spdif_route_info,
1941 .get = ad1983_spdif_route_get,
1942 .put = ad1983_spdif_route_put,
1944 { } /* end */
1947 static const struct hda_input_mux ad1981_thinkpad_capture_source = {
1948 .num_items = 3,
1949 .items = {
1950 { "Mic", 0x0 },
1951 { "Mix", 0x2 },
1952 { "CD", 0x4 },
1956 /* models */
1957 enum {
1958 AD1981_BASIC,
1959 AD1981_HP,
1960 AD1981_THINKPAD,
1961 AD1981_TOSHIBA,
1962 AD1981_MODELS
1965 static const char * const ad1981_models[AD1981_MODELS] = {
1966 [AD1981_HP] = "hp",
1967 [AD1981_THINKPAD] = "thinkpad",
1968 [AD1981_BASIC] = "basic",
1969 [AD1981_TOSHIBA] = "toshiba"
1972 static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
1973 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
1974 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
1975 /* All HP models */
1976 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
1977 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
1978 /* Lenovo Thinkpad T60/X60/Z6xx */
1979 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
1980 /* HP nx6320 (reversed SSID, H/W bug) */
1981 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
1985 static int patch_ad1981(struct hda_codec *codec)
1987 struct ad198x_spec *spec;
1988 int err, board_config;
1990 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1991 if (spec == NULL)
1992 return -ENOMEM;
1994 codec->spec = spec;
1996 err = snd_hda_attach_beep_device(codec, 0x10);
1997 if (err < 0) {
1998 ad198x_free(codec);
1999 return err;
2001 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
2003 spec->multiout.max_channels = 2;
2004 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
2005 spec->multiout.dac_nids = ad1981_dac_nids;
2006 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
2007 spec->num_adc_nids = 1;
2008 spec->adc_nids = ad1981_adc_nids;
2009 spec->capsrc_nids = ad1981_capsrc_nids;
2010 spec->input_mux = &ad1981_capture_source;
2011 spec->num_mixers = 1;
2012 spec->mixers[0] = ad1981_mixers;
2013 spec->num_init_verbs = 1;
2014 spec->init_verbs[0] = ad1981_init_verbs;
2015 spec->spdif_route = 0;
2016 #ifdef CONFIG_SND_HDA_POWER_SAVE
2017 spec->loopback.amplist = ad1981_loopbacks;
2018 #endif
2019 spec->vmaster_nid = 0x05;
2021 codec->patch_ops = ad198x_patch_ops;
2023 /* override some parameters */
2024 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
2025 ad1981_models,
2026 ad1981_cfg_tbl);
2027 switch (board_config) {
2028 case AD1981_HP:
2029 spec->mixers[0] = ad1981_hp_mixers;
2030 spec->num_init_verbs = 2;
2031 spec->init_verbs[1] = ad1981_hp_init_verbs;
2032 if (!is_jack_available(codec, 0x0a))
2033 spec->multiout.dig_out_nid = 0;
2034 spec->input_mux = &ad1981_hp_capture_source;
2036 codec->patch_ops.init = ad1981_hp_init;
2037 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
2038 /* set the upper-limit for mixer amp to 0dB for avoiding the
2039 * possible damage by overloading
2041 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2042 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2043 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2044 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2045 (1 << AC_AMPCAP_MUTE_SHIFT));
2046 break;
2047 case AD1981_THINKPAD:
2048 spec->mixers[0] = ad1981_thinkpad_mixers;
2049 spec->input_mux = &ad1981_thinkpad_capture_source;
2050 /* set the upper-limit for mixer amp to 0dB for avoiding the
2051 * possible damage by overloading
2053 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2054 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2055 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2056 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2057 (1 << AC_AMPCAP_MUTE_SHIFT));
2058 break;
2059 case AD1981_TOSHIBA:
2060 spec->mixers[0] = ad1981_hp_mixers;
2061 spec->mixers[1] = ad1981_toshiba_mixers;
2062 spec->num_init_verbs = 2;
2063 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
2064 spec->multiout.dig_out_nid = 0;
2065 spec->input_mux = &ad1981_hp_capture_source;
2066 codec->patch_ops.init = ad1981_hp_init;
2067 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
2068 break;
2071 codec->no_trigger_sense = 1;
2072 codec->no_sticky_stream = 1;
2074 return 0;
2079 * AD1988
2081 * Output pins and routes
2083 * Pin Mix Sel DAC (*)
2084 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
2085 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
2086 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
2087 * port-D 0x12 (mute/hp) <- 0x29 <- 04
2088 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
2089 * port-F 0x16 (mute) <- 0x2a <- 06
2090 * port-G 0x24 (mute) <- 0x27 <- 05
2091 * port-H 0x25 (mute) <- 0x28 <- 0a
2092 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
2094 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
2095 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
2097 * Input pins and routes
2099 * pin boost mix input # / adc input #
2100 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
2101 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
2102 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
2103 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
2104 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
2105 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
2106 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
2107 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
2110 * DAC assignment
2111 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
2112 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
2114 * Inputs of Analog Mix (0x20)
2115 * 0:Port-B (front mic)
2116 * 1:Port-C/G/H (line-in)
2117 * 2:Port-A
2118 * 3:Port-D (line-in/2)
2119 * 4:Port-E/G/H (mic-in)
2120 * 5:Port-F (mic2-in)
2121 * 6:CD
2122 * 7:Beep
2124 * ADC selection
2125 * 0:Port-A
2126 * 1:Port-B (front mic-in)
2127 * 2:Port-C (line-in)
2128 * 3:Port-F (mic2-in)
2129 * 4:Port-E (mic-in)
2130 * 5:CD
2131 * 6:Port-G
2132 * 7:Port-H
2133 * 8:Port-D (line-in/2)
2134 * 9:Mix
2136 * Proposed pin assignments by the datasheet
2138 * 6-stack
2139 * Port-A front headphone
2140 * B front mic-in
2141 * C rear line-in
2142 * D rear front-out
2143 * E rear mic-in
2144 * F rear surround
2145 * G rear CLFE
2146 * H rear side
2148 * 3-stack
2149 * Port-A front headphone
2150 * B front mic
2151 * C rear line-in/surround
2152 * D rear front-out
2153 * E rear mic-in/CLFE
2155 * laptop
2156 * Port-A headphone
2157 * B mic-in
2158 * C docking station
2159 * D internal speaker (with EAPD)
2160 * E/F quad mic array
2164 /* models */
2165 enum {
2166 AD1988_6STACK,
2167 AD1988_6STACK_DIG,
2168 AD1988_3STACK,
2169 AD1988_3STACK_DIG,
2170 AD1988_LAPTOP,
2171 AD1988_LAPTOP_DIG,
2172 AD1988_AUTO,
2173 AD1988_MODEL_LAST,
2176 /* reivision id to check workarounds */
2177 #define AD1988A_REV2 0x100200
2179 #define is_rev2(codec) \
2180 ((codec)->vendor_id == 0x11d41988 && \
2181 (codec)->revision_id == AD1988A_REV2)
2184 * mixers
2187 static const hda_nid_t ad1988_6stack_dac_nids[4] = {
2188 0x04, 0x06, 0x05, 0x0a
2191 static const hda_nid_t ad1988_3stack_dac_nids[3] = {
2192 0x04, 0x05, 0x0a
2195 /* for AD1988A revision-2, DAC2-4 are swapped */
2196 static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
2197 0x04, 0x05, 0x0a, 0x06
2200 static const hda_nid_t ad1988_alt_dac_nid[1] = {
2201 0x03
2204 static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
2205 0x04, 0x0a, 0x06
2208 static const hda_nid_t ad1988_adc_nids[3] = {
2209 0x08, 0x09, 0x0f
2212 static const hda_nid_t ad1988_capsrc_nids[3] = {
2213 0x0c, 0x0d, 0x0e
2216 #define AD1988_SPDIF_OUT 0x02
2217 #define AD1988_SPDIF_OUT_HDMI 0x0b
2218 #define AD1988_SPDIF_IN 0x07
2220 static const hda_nid_t ad1989b_slave_dig_outs[] = {
2221 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
2224 static const struct hda_input_mux ad1988_6stack_capture_source = {
2225 .num_items = 5,
2226 .items = {
2227 { "Front Mic", 0x1 }, /* port-B */
2228 { "Line", 0x2 }, /* port-C */
2229 { "Mic", 0x4 }, /* port-E */
2230 { "CD", 0x5 },
2231 { "Mix", 0x9 },
2235 static const struct hda_input_mux ad1988_laptop_capture_source = {
2236 .num_items = 3,
2237 .items = {
2238 { "Mic/Line", 0x1 }, /* port-B */
2239 { "CD", 0x5 },
2240 { "Mix", 0x9 },
2246 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
2247 struct snd_ctl_elem_info *uinfo)
2249 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2250 struct ad198x_spec *spec = codec->spec;
2251 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
2252 spec->num_channel_mode);
2255 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
2256 struct snd_ctl_elem_value *ucontrol)
2258 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2259 struct ad198x_spec *spec = codec->spec;
2260 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
2261 spec->num_channel_mode, spec->multiout.max_channels);
2264 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
2265 struct snd_ctl_elem_value *ucontrol)
2267 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2268 struct ad198x_spec *spec = codec->spec;
2269 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
2270 spec->num_channel_mode,
2271 &spec->multiout.max_channels);
2272 if (err >= 0 && spec->need_dac_fix)
2273 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2274 return err;
2277 static const struct snd_kcontrol_new ad1988_hp_mixers[] = {
2279 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2280 .name = "Independent HP",
2281 .info = ad1988_independent_hp_info,
2282 .get = ad1988_independent_hp_get,
2283 .put = ad1988_independent_hp_put,
2285 { } /* end */
2288 /* 6-stack mode */
2289 static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
2290 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2291 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2292 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2293 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2294 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2295 { } /* end */
2298 static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
2299 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2300 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2301 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2302 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2303 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2304 { } /* end */
2307 static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
2308 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2309 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2310 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2311 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2312 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2313 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2314 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2315 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2317 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2318 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2319 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2320 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2321 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2322 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2323 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2324 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2326 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2327 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2329 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2330 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2331 { } /* end */
2334 /* 3-stack mode */
2335 static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
2336 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2337 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2338 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2339 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2340 { } /* end */
2343 static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2344 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2345 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2346 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2347 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
2348 { } /* end */
2351 static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
2352 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2353 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2354 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2355 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2356 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
2357 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2358 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2360 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2361 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2362 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2363 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2364 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2365 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2366 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2367 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2369 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2370 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2372 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2373 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2375 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2376 .name = "Channel Mode",
2377 .info = ad198x_ch_mode_info,
2378 .get = ad198x_ch_mode_get,
2379 .put = ad198x_ch_mode_put,
2382 { } /* end */
2385 /* laptop mode */
2386 static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2387 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2388 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2389 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2390 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2392 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2393 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2394 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2395 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2396 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2397 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2399 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2400 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2402 HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2405 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2406 .name = "External Amplifier",
2407 .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
2408 .info = ad198x_eapd_info,
2409 .get = ad198x_eapd_get,
2410 .put = ad198x_eapd_put,
2411 .private_value = 0x12, /* port-D */
2414 { } /* end */
2417 /* capture */
2418 static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
2419 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2420 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2421 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2422 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2423 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2424 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2426 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2427 /* The multiple "Capture Source" controls confuse alsamixer
2428 * So call somewhat different..
2430 /* .name = "Capture Source", */
2431 .name = "Input Source",
2432 .count = 3,
2433 .info = ad198x_mux_enum_info,
2434 .get = ad198x_mux_enum_get,
2435 .put = ad198x_mux_enum_put,
2437 { } /* end */
2440 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2441 struct snd_ctl_elem_info *uinfo)
2443 static const char * const texts[] = {
2444 "PCM", "ADC1", "ADC2", "ADC3"
2446 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2447 uinfo->count = 1;
2448 uinfo->value.enumerated.items = 4;
2449 if (uinfo->value.enumerated.item >= 4)
2450 uinfo->value.enumerated.item = 3;
2451 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2452 return 0;
2455 static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2456 struct snd_ctl_elem_value *ucontrol)
2458 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2459 unsigned int sel;
2461 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2462 AC_AMP_GET_INPUT);
2463 if (!(sel & 0x80))
2464 ucontrol->value.enumerated.item[0] = 0;
2465 else {
2466 sel = snd_hda_codec_read(codec, 0x0b, 0,
2467 AC_VERB_GET_CONNECT_SEL, 0);
2468 if (sel < 3)
2469 sel++;
2470 else
2471 sel = 0;
2472 ucontrol->value.enumerated.item[0] = sel;
2474 return 0;
2477 static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2478 struct snd_ctl_elem_value *ucontrol)
2480 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2481 unsigned int val, sel;
2482 int change;
2484 val = ucontrol->value.enumerated.item[0];
2485 if (val > 3)
2486 return -EINVAL;
2487 if (!val) {
2488 sel = snd_hda_codec_read(codec, 0x1d, 0,
2489 AC_VERB_GET_AMP_GAIN_MUTE,
2490 AC_AMP_GET_INPUT);
2491 change = sel & 0x80;
2492 if (change) {
2493 snd_hda_codec_write_cache(codec, 0x1d, 0,
2494 AC_VERB_SET_AMP_GAIN_MUTE,
2495 AMP_IN_UNMUTE(0));
2496 snd_hda_codec_write_cache(codec, 0x1d, 0,
2497 AC_VERB_SET_AMP_GAIN_MUTE,
2498 AMP_IN_MUTE(1));
2500 } else {
2501 sel = snd_hda_codec_read(codec, 0x1d, 0,
2502 AC_VERB_GET_AMP_GAIN_MUTE,
2503 AC_AMP_GET_INPUT | 0x01);
2504 change = sel & 0x80;
2505 if (change) {
2506 snd_hda_codec_write_cache(codec, 0x1d, 0,
2507 AC_VERB_SET_AMP_GAIN_MUTE,
2508 AMP_IN_MUTE(0));
2509 snd_hda_codec_write_cache(codec, 0x1d, 0,
2510 AC_VERB_SET_AMP_GAIN_MUTE,
2511 AMP_IN_UNMUTE(1));
2513 sel = snd_hda_codec_read(codec, 0x0b, 0,
2514 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2515 change |= sel != val;
2516 if (change)
2517 snd_hda_codec_write_cache(codec, 0x0b, 0,
2518 AC_VERB_SET_CONNECT_SEL,
2519 val - 1);
2521 return change;
2524 static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2525 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2527 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2528 .name = "IEC958 Playback Source",
2529 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
2530 .info = ad1988_spdif_playback_source_info,
2531 .get = ad1988_spdif_playback_source_get,
2532 .put = ad1988_spdif_playback_source_put,
2534 { } /* end */
2537 static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2538 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2539 { } /* end */
2542 static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2543 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2544 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2545 { } /* end */
2549 * initialization verbs
2553 * for 6-stack (+dig)
2555 static const struct hda_verb ad1988_6stack_init_verbs[] = {
2556 /* Front, Surround, CLFE, side DAC; unmute as default */
2557 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2558 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2559 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2560 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2561 /* Port-A front headphon path */
2562 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2563 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2564 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2565 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2566 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2567 /* Port-D line-out path */
2568 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2569 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2570 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2571 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2572 /* Port-F surround path */
2573 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2574 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2575 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2576 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2577 /* Port-G CLFE path */
2578 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2579 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2580 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2581 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2582 /* Port-H side path */
2583 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2584 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2585 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2586 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2587 /* Mono out path */
2588 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2589 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2590 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2591 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2592 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2593 /* Port-B front mic-in path */
2594 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2595 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2596 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2597 /* Port-C line-in path */
2598 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2599 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2600 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2601 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2602 /* Port-E mic-in path */
2603 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2604 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2605 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2606 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2607 /* Analog CD Input */
2608 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2609 /* Analog Mix output amp */
2610 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2615 static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
2616 /* Headphone; unmute as default */
2617 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2618 /* Port-A front headphon path */
2619 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2622 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2623 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2628 static const struct hda_verb ad1988_capture_init_verbs[] = {
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},
2646 static const struct hda_verb ad1988_spdif_init_verbs[] = {
2647 /* SPDIF out sel */
2648 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2649 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2650 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2651 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2652 /* SPDIF out pin */
2653 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2658 static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
2659 /* unmute SPDIF input pin */
2660 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2664 /* AD1989 has no ADC -> SPDIF route */
2665 static const struct hda_verb ad1989_spdif_init_verbs[] = {
2666 /* SPDIF-1 out pin */
2667 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2668 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2669 /* SPDIF-2/HDMI out pin */
2670 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2671 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2676 * verbs for 3stack (+dig)
2678 static const struct hda_verb ad1988_3stack_ch2_init[] = {
2679 /* set port-C to line-in */
2680 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2681 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2682 /* set port-E to mic-in */
2683 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2684 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2685 { } /* end */
2688 static const struct hda_verb ad1988_3stack_ch6_init[] = {
2689 /* set port-C to surround out */
2690 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2691 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2692 /* set port-E to CLFE out */
2693 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2694 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2695 { } /* end */
2698 static const struct hda_channel_mode ad1988_3stack_modes[2] = {
2699 { 2, ad1988_3stack_ch2_init },
2700 { 6, ad1988_3stack_ch6_init },
2703 static const struct hda_verb ad1988_3stack_init_verbs[] = {
2704 /* Front, Surround, CLFE, side DAC; unmute as default */
2705 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2706 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2707 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2708 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2709 /* Port-A front headphon path */
2710 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2711 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2712 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2713 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2714 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2715 /* Port-D line-out path */
2716 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2717 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2718 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2719 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2720 /* Mono out path */
2721 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2722 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2723 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2724 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2725 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2726 /* Port-B front mic-in path */
2727 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2728 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2729 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2730 /* Port-C line-in/surround path - 6ch mode as default */
2731 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2732 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2733 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2734 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
2735 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2736 /* Port-E mic-in/CLFE path - 6ch mode as default */
2737 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2738 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2739 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2740 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
2741 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2742 /* mute analog mix */
2743 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2744 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2745 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2746 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2747 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2748 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2749 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2750 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2751 /* select ADCs - front-mic */
2752 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2753 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2754 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2755 /* Analog Mix output amp */
2756 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2761 * verbs for laptop mode (+dig)
2763 static const struct hda_verb ad1988_laptop_hp_on[] = {
2764 /* unmute port-A and mute port-D */
2765 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2766 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2767 { } /* end */
2769 static const struct hda_verb ad1988_laptop_hp_off[] = {
2770 /* mute port-A and unmute port-D */
2771 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2772 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2773 { } /* end */
2776 #define AD1988_HP_EVENT 0x01
2778 static const struct hda_verb ad1988_laptop_init_verbs[] = {
2779 /* Front, Surround, CLFE, side DAC; unmute as default */
2780 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2781 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2782 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2783 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2784 /* Port-A front headphon path */
2785 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */
2786 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2787 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2788 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2789 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2790 /* unsolicited event for pin-sense */
2791 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2792 /* Port-D line-out path + EAPD */
2793 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2794 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2795 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2796 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2797 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
2798 /* Mono out path */
2799 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2800 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2801 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2802 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2803 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2804 /* Port-B mic-in path */
2805 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2806 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2807 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2808 /* Port-C docking station - try to output */
2809 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2810 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2811 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2812 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2813 /* mute analog mix */
2814 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2815 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2816 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2817 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2818 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2819 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2820 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2821 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2822 /* select ADCs - mic */
2823 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2824 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2825 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2826 /* Analog Mix output amp */
2827 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2831 static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2833 if ((res >> 26) != AD1988_HP_EVENT)
2834 return;
2835 if (snd_hda_jack_detect(codec, 0x11))
2836 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2837 else
2838 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2841 #ifdef CONFIG_SND_HDA_POWER_SAVE
2842 static const struct hda_amp_list ad1988_loopbacks[] = {
2843 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2844 { 0x20, HDA_INPUT, 1 }, /* Line */
2845 { 0x20, HDA_INPUT, 4 }, /* Mic */
2846 { 0x20, HDA_INPUT, 6 }, /* CD */
2847 { } /* end */
2849 #endif
2852 * Automatic parse of I/O pins from the BIOS configuration
2855 enum {
2856 AD_CTL_WIDGET_VOL,
2857 AD_CTL_WIDGET_MUTE,
2858 AD_CTL_BIND_MUTE,
2860 static const struct snd_kcontrol_new ad1988_control_templates[] = {
2861 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2862 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2863 HDA_BIND_MUTE(NULL, 0, 0, 0),
2866 /* add dynamic controls */
2867 static int add_control(struct ad198x_spec *spec, int type, const char *name,
2868 unsigned long val)
2870 struct snd_kcontrol_new *knew;
2872 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2873 knew = snd_array_new(&spec->kctls);
2874 if (!knew)
2875 return -ENOMEM;
2876 *knew = ad1988_control_templates[type];
2877 knew->name = kstrdup(name, GFP_KERNEL);
2878 if (! knew->name)
2879 return -ENOMEM;
2880 if (get_amp_nid_(val))
2881 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2882 knew->private_value = val;
2883 return 0;
2886 #define AD1988_PIN_CD_NID 0x18
2887 #define AD1988_PIN_BEEP_NID 0x10
2889 static const hda_nid_t ad1988_mixer_nids[8] = {
2890 /* A B C D E F G H */
2891 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
2894 static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
2896 static const hda_nid_t idx_to_dac[8] = {
2897 /* A B C D E F G H */
2898 0x03, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
2900 static const hda_nid_t idx_to_dac_rev2[8] = {
2901 /* A B C D E F G H */
2902 0x03, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
2904 if (is_rev2(codec))
2905 return idx_to_dac_rev2[idx];
2906 else
2907 return idx_to_dac[idx];
2910 static const hda_nid_t ad1988_boost_nids[8] = {
2911 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
2914 static int ad1988_pin_idx(hda_nid_t nid)
2916 static const hda_nid_t ad1988_io_pins[8] = {
2917 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
2919 int i;
2920 for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)
2921 if (ad1988_io_pins[i] == nid)
2922 return i;
2923 return 0; /* should be -1 */
2926 static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
2928 static const int loopback_idx[8] = {
2929 2, 0, 1, 3, 4, 5, 1, 4
2931 switch (nid) {
2932 case AD1988_PIN_CD_NID:
2933 return 6;
2934 default:
2935 return loopback_idx[ad1988_pin_idx(nid)];
2939 static int ad1988_pin_to_adc_idx(hda_nid_t nid)
2941 static const int adc_idx[8] = {
2942 0, 1, 2, 8, 4, 3, 6, 7
2944 switch (nid) {
2945 case AD1988_PIN_CD_NID:
2946 return 5;
2947 default:
2948 return adc_idx[ad1988_pin_idx(nid)];
2952 /* fill in the dac_nids table from the parsed pin configuration */
2953 static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
2954 const struct auto_pin_cfg *cfg)
2956 struct ad198x_spec *spec = codec->spec;
2957 int i, idx;
2959 spec->multiout.dac_nids = spec->private_dac_nids;
2961 /* check the pins hardwired to audio widget */
2962 for (i = 0; i < cfg->line_outs; i++) {
2963 idx = ad1988_pin_idx(cfg->line_out_pins[i]);
2964 spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx);
2966 spec->multiout.num_dacs = cfg->line_outs;
2967 return 0;
2970 /* add playback controls from the parsed DAC table */
2971 static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
2972 const struct auto_pin_cfg *cfg)
2974 char name[32];
2975 static const char * const chname[4] = {
2976 "Front", "Surround", NULL /*CLFE*/, "Side"
2978 hda_nid_t nid;
2979 int i, err;
2981 for (i = 0; i < cfg->line_outs; i++) {
2982 hda_nid_t dac = spec->multiout.dac_nids[i];
2983 if (! dac)
2984 continue;
2985 nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];
2986 if (i == 2) {
2987 /* Center/LFE */
2988 err = add_control(spec, AD_CTL_WIDGET_VOL,
2989 "Center Playback Volume",
2990 HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));
2991 if (err < 0)
2992 return err;
2993 err = add_control(spec, AD_CTL_WIDGET_VOL,
2994 "LFE Playback Volume",
2995 HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));
2996 if (err < 0)
2997 return err;
2998 err = add_control(spec, AD_CTL_BIND_MUTE,
2999 "Center Playback Switch",
3000 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
3001 if (err < 0)
3002 return err;
3003 err = add_control(spec, AD_CTL_BIND_MUTE,
3004 "LFE Playback Switch",
3005 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
3006 if (err < 0)
3007 return err;
3008 } else {
3009 sprintf(name, "%s Playback Volume", chname[i]);
3010 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
3011 HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));
3012 if (err < 0)
3013 return err;
3014 sprintf(name, "%s Playback Switch", chname[i]);
3015 err = add_control(spec, AD_CTL_BIND_MUTE, name,
3016 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3017 if (err < 0)
3018 return err;
3021 return 0;
3024 /* add playback controls for speaker and HP outputs */
3025 static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
3026 const char *pfx)
3028 struct ad198x_spec *spec = codec->spec;
3029 hda_nid_t nid;
3030 int i, idx, err;
3031 char name[32];
3033 if (! pin)
3034 return 0;
3036 idx = ad1988_pin_idx(pin);
3037 nid = ad1988_idx_to_dac(codec, idx);
3038 /* check whether the corresponding DAC was already taken */
3039 for (i = 0; i < spec->autocfg.line_outs; i++) {
3040 hda_nid_t pin = spec->autocfg.line_out_pins[i];
3041 hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
3042 if (dac == nid)
3043 break;
3045 if (i >= spec->autocfg.line_outs) {
3046 /* specify the DAC as the extra output */
3047 if (!spec->multiout.hp_nid)
3048 spec->multiout.hp_nid = nid;
3049 else
3050 spec->multiout.extra_out_nid[0] = nid;
3051 /* control HP volume/switch on the output mixer amp */
3052 sprintf(name, "%s Playback Volume", pfx);
3053 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
3054 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3055 if (err < 0)
3056 return err;
3058 nid = ad1988_mixer_nids[idx];
3059 sprintf(name, "%s Playback Switch", pfx);
3060 if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
3061 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
3062 return err;
3063 return 0;
3066 /* create input playback/capture controls for the given pin */
3067 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
3068 const char *ctlname, int ctlidx, int boost)
3070 char name[32];
3071 int err, idx;
3073 sprintf(name, "%s Playback Volume", ctlname);
3074 idx = ad1988_pin_to_loopback_idx(pin);
3075 if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
3076 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
3077 return err;
3078 sprintf(name, "%s Playback Switch", ctlname);
3079 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,
3080 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
3081 return err;
3082 if (boost) {
3083 hda_nid_t bnid;
3084 idx = ad1988_pin_idx(pin);
3085 bnid = ad1988_boost_nids[idx];
3086 if (bnid) {
3087 sprintf(name, "%s Boost Volume", ctlname);
3088 return add_control(spec, AD_CTL_WIDGET_VOL, name,
3089 HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
3093 return 0;
3096 /* create playback/capture controls for input pins */
3097 static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
3098 const struct auto_pin_cfg *cfg)
3100 struct ad198x_spec *spec = codec->spec;
3101 struct hda_input_mux *imux = &spec->private_imux;
3102 int i, err, type, type_idx;
3104 for (i = 0; i < cfg->num_inputs; i++) {
3105 const char *label;
3106 type = cfg->inputs[i].type;
3107 label = hda_get_autocfg_input_label(codec, cfg, i);
3108 snd_hda_add_imux_item(imux, label,
3109 ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
3110 &type_idx);
3111 err = new_analog_input(spec, cfg->inputs[i].pin,
3112 label, type_idx,
3113 type == AUTO_PIN_MIC);
3114 if (err < 0)
3115 return err;
3117 snd_hda_add_imux_item(imux, "Mix", 9, NULL);
3119 if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
3120 "Analog Mix Playback Volume",
3121 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
3122 return err;
3123 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,
3124 "Analog Mix Playback Switch",
3125 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
3126 return err;
3128 return 0;
3131 static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
3132 hda_nid_t nid, int pin_type,
3133 int dac_idx)
3135 /* set as output */
3136 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
3137 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
3138 switch (nid) {
3139 case 0x11: /* port-A - DAC 03 */
3140 snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
3141 break;
3142 case 0x14: /* port-B - DAC 06 */
3143 snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
3144 break;
3145 case 0x15: /* port-C - DAC 05 */
3146 snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
3147 break;
3148 case 0x17: /* port-E - DAC 0a */
3149 snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
3150 break;
3151 case 0x13: /* mono - DAC 04 */
3152 snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
3153 break;
3157 static void ad1988_auto_init_multi_out(struct hda_codec *codec)
3159 struct ad198x_spec *spec = codec->spec;
3160 int i;
3162 for (i = 0; i < spec->autocfg.line_outs; i++) {
3163 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3164 ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
3168 static void ad1988_auto_init_extra_out(struct hda_codec *codec)
3170 struct ad198x_spec *spec = codec->spec;
3171 hda_nid_t pin;
3173 pin = spec->autocfg.speaker_pins[0];
3174 if (pin) /* connect to front */
3175 ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
3176 pin = spec->autocfg.hp_pins[0];
3177 if (pin) /* connect to front */
3178 ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3181 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
3183 struct ad198x_spec *spec = codec->spec;
3184 const struct auto_pin_cfg *cfg = &spec->autocfg;
3185 int i, idx;
3187 for (i = 0; i < cfg->num_inputs; i++) {
3188 hda_nid_t nid = cfg->inputs[i].pin;
3189 int type = cfg->inputs[i].type;
3190 switch (nid) {
3191 case 0x15: /* port-C */
3192 snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3193 break;
3194 case 0x17: /* port-E */
3195 snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3196 break;
3198 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3199 type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
3200 if (nid != AD1988_PIN_CD_NID)
3201 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3202 AMP_OUT_MUTE);
3203 idx = ad1988_pin_idx(nid);
3204 if (ad1988_boost_nids[idx])
3205 snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,
3206 AC_VERB_SET_AMP_GAIN_MUTE,
3207 AMP_OUT_ZERO);
3211 /* parse the BIOS configuration and set up the alc_spec */
3212 /* return 1 if successful, 0 if the proper config is not found, or a negative error code */
3213 static int ad1988_parse_auto_config(struct hda_codec *codec)
3215 struct ad198x_spec *spec = codec->spec;
3216 int err;
3218 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
3219 return err;
3220 if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3221 return err;
3222 if (! spec->autocfg.line_outs)
3223 return 0; /* can't find valid BIOS pin config */
3224 if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
3225 (err = ad1988_auto_create_extra_out(codec,
3226 spec->autocfg.speaker_pins[0],
3227 "Speaker")) < 0 ||
3228 (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
3229 "Headphone")) < 0 ||
3230 (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3231 return err;
3233 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3235 if (spec->autocfg.dig_outs)
3236 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3237 if (spec->autocfg.dig_in_pin)
3238 spec->dig_in_nid = AD1988_SPDIF_IN;
3240 if (spec->kctls.list)
3241 spec->mixers[spec->num_mixers++] = spec->kctls.list;
3243 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
3245 spec->input_mux = &spec->private_imux;
3247 return 1;
3250 /* init callback for auto-configuration model -- overriding the default init */
3251 static int ad1988_auto_init(struct hda_codec *codec)
3253 ad198x_init(codec);
3254 ad1988_auto_init_multi_out(codec);
3255 ad1988_auto_init_extra_out(codec);
3256 ad1988_auto_init_analog_input(codec);
3257 return 0;
3263 static const char * const ad1988_models[AD1988_MODEL_LAST] = {
3264 [AD1988_6STACK] = "6stack",
3265 [AD1988_6STACK_DIG] = "6stack-dig",
3266 [AD1988_3STACK] = "3stack",
3267 [AD1988_3STACK_DIG] = "3stack-dig",
3268 [AD1988_LAPTOP] = "laptop",
3269 [AD1988_LAPTOP_DIG] = "laptop-dig",
3270 [AD1988_AUTO] = "auto",
3273 static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
3274 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
3275 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
3276 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
3277 SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
3278 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
3282 static int patch_ad1988(struct hda_codec *codec)
3284 struct ad198x_spec *spec;
3285 int err, board_config;
3287 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3288 if (spec == NULL)
3289 return -ENOMEM;
3291 codec->spec = spec;
3293 if (is_rev2(codec))
3294 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
3296 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
3297 ad1988_models, ad1988_cfg_tbl);
3298 if (board_config < 0) {
3299 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3300 codec->chip_name);
3301 board_config = AD1988_AUTO;
3304 if (board_config == AD1988_AUTO) {
3305 /* automatic parse from the BIOS config */
3306 err = ad1988_parse_auto_config(codec);
3307 if (err < 0) {
3308 ad198x_free(codec);
3309 return err;
3310 } else if (! err) {
3311 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n");
3312 board_config = AD1988_6STACK;
3316 err = snd_hda_attach_beep_device(codec, 0x10);
3317 if (err < 0) {
3318 ad198x_free(codec);
3319 return err;
3321 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3323 if (!spec->multiout.hp_nid)
3324 spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
3325 switch (board_config) {
3326 case AD1988_6STACK:
3327 case AD1988_6STACK_DIG:
3328 spec->multiout.max_channels = 8;
3329 spec->multiout.num_dacs = 4;
3330 if (is_rev2(codec))
3331 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3332 else
3333 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
3334 spec->input_mux = &ad1988_6stack_capture_source;
3335 spec->num_mixers = 2;
3336 if (is_rev2(codec))
3337 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3338 else
3339 spec->mixers[0] = ad1988_6stack_mixers1;
3340 spec->mixers[1] = ad1988_6stack_mixers2;
3341 spec->num_init_verbs = 1;
3342 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3343 if (board_config == AD1988_6STACK_DIG) {
3344 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3345 spec->dig_in_nid = AD1988_SPDIF_IN;
3347 break;
3348 case AD1988_3STACK:
3349 case AD1988_3STACK_DIG:
3350 spec->multiout.max_channels = 6;
3351 spec->multiout.num_dacs = 3;
3352 if (is_rev2(codec))
3353 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3354 else
3355 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3356 spec->input_mux = &ad1988_6stack_capture_source;
3357 spec->channel_mode = ad1988_3stack_modes;
3358 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
3359 spec->num_mixers = 2;
3360 if (is_rev2(codec))
3361 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3362 else
3363 spec->mixers[0] = ad1988_3stack_mixers1;
3364 spec->mixers[1] = ad1988_3stack_mixers2;
3365 spec->num_init_verbs = 1;
3366 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3367 if (board_config == AD1988_3STACK_DIG)
3368 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3369 break;
3370 case AD1988_LAPTOP:
3371 case AD1988_LAPTOP_DIG:
3372 spec->multiout.max_channels = 2;
3373 spec->multiout.num_dacs = 1;
3374 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3375 spec->input_mux = &ad1988_laptop_capture_source;
3376 spec->num_mixers = 1;
3377 spec->mixers[0] = ad1988_laptop_mixers;
3378 spec->inv_eapd = 1; /* inverted EAPD */
3379 spec->num_init_verbs = 1;
3380 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3381 if (board_config == AD1988_LAPTOP_DIG)
3382 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3383 break;
3386 if (spec->autocfg.hp_pins[0]) {
3387 spec->mixers[spec->num_mixers++] = ad1988_hp_mixers;
3388 spec->slave_vols = ad1988_6stack_fp_slave_vols;
3389 spec->slave_sws = ad1988_6stack_fp_slave_sws;
3390 spec->alt_dac_nid = ad1988_alt_dac_nid;
3391 spec->stream_analog_alt_playback =
3392 &ad198x_pcm_analog_alt_playback;
3395 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3396 spec->adc_nids = ad1988_adc_nids;
3397 spec->capsrc_nids = ad1988_capsrc_nids;
3398 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3399 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3400 if (spec->multiout.dig_out_nid) {
3401 if (codec->vendor_id >= 0x11d4989a) {
3402 spec->mixers[spec->num_mixers++] =
3403 ad1989_spdif_out_mixers;
3404 spec->init_verbs[spec->num_init_verbs++] =
3405 ad1989_spdif_init_verbs;
3406 codec->slave_dig_outs = ad1989b_slave_dig_outs;
3407 } else {
3408 spec->mixers[spec->num_mixers++] =
3409 ad1988_spdif_out_mixers;
3410 spec->init_verbs[spec->num_init_verbs++] =
3411 ad1988_spdif_init_verbs;
3414 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
3415 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
3416 spec->init_verbs[spec->num_init_verbs++] =
3417 ad1988_spdif_in_init_verbs;
3420 codec->patch_ops = ad198x_patch_ops;
3421 switch (board_config) {
3422 case AD1988_AUTO:
3423 codec->patch_ops.init = ad1988_auto_init;
3424 break;
3425 case AD1988_LAPTOP:
3426 case AD1988_LAPTOP_DIG:
3427 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3428 break;
3430 #ifdef CONFIG_SND_HDA_POWER_SAVE
3431 spec->loopback.amplist = ad1988_loopbacks;
3432 #endif
3433 spec->vmaster_nid = 0x04;
3435 codec->no_trigger_sense = 1;
3436 codec->no_sticky_stream = 1;
3438 return 0;
3443 * AD1884 / AD1984
3445 * port-B - front line/mic-in
3446 * port-E - aux in/out
3447 * port-F - aux in/out
3448 * port-C - rear line/mic-in
3449 * port-D - rear line/hp-out
3450 * port-A - front line/hp-out
3452 * AD1984 = AD1884 + two digital mic-ins
3454 * FIXME:
3455 * For simplicity, we share the single DAC for both HP and line-outs
3456 * right now. The inidividual playbacks could be easily implemented,
3457 * but no build-up framework is given, so far.
3460 static const hda_nid_t ad1884_dac_nids[1] = {
3461 0x04,
3464 static const hda_nid_t ad1884_adc_nids[2] = {
3465 0x08, 0x09,
3468 static const hda_nid_t ad1884_capsrc_nids[2] = {
3469 0x0c, 0x0d,
3472 #define AD1884_SPDIF_OUT 0x02
3474 static const struct hda_input_mux ad1884_capture_source = {
3475 .num_items = 4,
3476 .items = {
3477 { "Front Mic", 0x0 },
3478 { "Mic", 0x1 },
3479 { "CD", 0x2 },
3480 { "Mix", 0x3 },
3484 static const struct snd_kcontrol_new ad1884_base_mixers[] = {
3485 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3486 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3487 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3488 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3489 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3490 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3491 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3492 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3493 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3494 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3495 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3496 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3497 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3498 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3499 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3500 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3501 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3502 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3504 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3505 /* The multiple "Capture Source" controls confuse alsamixer
3506 * So call somewhat different..
3508 /* .name = "Capture Source", */
3509 .name = "Input Source",
3510 .count = 2,
3511 .info = ad198x_mux_enum_info,
3512 .get = ad198x_mux_enum_get,
3513 .put = ad198x_mux_enum_put,
3515 /* SPDIF controls */
3516 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3518 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3519 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3520 /* identical with ad1983 */
3521 .info = ad1983_spdif_route_info,
3522 .get = ad1983_spdif_route_get,
3523 .put = ad1983_spdif_route_put,
3525 { } /* end */
3528 static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3529 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3530 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3531 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
3532 HDA_INPUT),
3533 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
3534 HDA_INPUT),
3535 { } /* end */
3539 * initialization verbs
3541 static const struct hda_verb ad1884_init_verbs[] = {
3542 /* DACs; mute as default */
3543 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3544 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3545 /* Port-A (HP) mixer */
3546 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3547 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3548 /* Port-A pin */
3549 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3550 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3551 /* HP selector - select DAC2 */
3552 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3553 /* Port-D (Line-out) mixer */
3554 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3555 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3556 /* Port-D pin */
3557 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3558 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3559 /* Mono-out mixer */
3560 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3561 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3562 /* Mono-out pin */
3563 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3564 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3565 /* Mono selector */
3566 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3567 /* Port-B (front mic) pin */
3568 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3569 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3570 /* Port-C (rear mic) pin */
3571 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3572 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3573 /* Analog mixer; mute as default */
3574 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3575 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3576 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3577 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3578 /* Analog Mix output amp */
3579 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3580 /* SPDIF output selector */
3581 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3582 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3583 { } /* end */
3586 #ifdef CONFIG_SND_HDA_POWER_SAVE
3587 static const struct hda_amp_list ad1884_loopbacks[] = {
3588 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3589 { 0x20, HDA_INPUT, 1 }, /* Mic */
3590 { 0x20, HDA_INPUT, 2 }, /* CD */
3591 { 0x20, HDA_INPUT, 4 }, /* Docking */
3592 { } /* end */
3594 #endif
3596 static const char * const ad1884_slave_vols[] = {
3597 "PCM Playback Volume",
3598 "Mic Playback Volume",
3599 "Mono Playback Volume",
3600 "Front Mic Playback Volume",
3601 "Mic Playback Volume",
3602 "CD Playback Volume",
3603 "Internal Mic Playback Volume",
3604 "Docking Mic Playback Volume",
3605 /* "Beep Playback Volume", */
3606 "IEC958 Playback Volume",
3607 NULL
3610 static int patch_ad1884(struct hda_codec *codec)
3612 struct ad198x_spec *spec;
3613 int err;
3615 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3616 if (spec == NULL)
3617 return -ENOMEM;
3619 codec->spec = spec;
3621 err = snd_hda_attach_beep_device(codec, 0x10);
3622 if (err < 0) {
3623 ad198x_free(codec);
3624 return err;
3626 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3628 spec->multiout.max_channels = 2;
3629 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3630 spec->multiout.dac_nids = ad1884_dac_nids;
3631 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3632 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3633 spec->adc_nids = ad1884_adc_nids;
3634 spec->capsrc_nids = ad1884_capsrc_nids;
3635 spec->input_mux = &ad1884_capture_source;
3636 spec->num_mixers = 1;
3637 spec->mixers[0] = ad1884_base_mixers;
3638 spec->num_init_verbs = 1;
3639 spec->init_verbs[0] = ad1884_init_verbs;
3640 spec->spdif_route = 0;
3641 #ifdef CONFIG_SND_HDA_POWER_SAVE
3642 spec->loopback.amplist = ad1884_loopbacks;
3643 #endif
3644 spec->vmaster_nid = 0x04;
3645 /* we need to cover all playback volumes */
3646 spec->slave_vols = ad1884_slave_vols;
3648 codec->patch_ops = ad198x_patch_ops;
3650 codec->no_trigger_sense = 1;
3651 codec->no_sticky_stream = 1;
3653 return 0;
3657 * Lenovo Thinkpad T61/X61
3659 static const struct hda_input_mux ad1984_thinkpad_capture_source = {
3660 .num_items = 4,
3661 .items = {
3662 { "Mic", 0x0 },
3663 { "Internal Mic", 0x1 },
3664 { "Mix", 0x3 },
3665 { "Docking-Station", 0x4 },
3671 * Dell Precision T3400
3673 static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
3674 .num_items = 3,
3675 .items = {
3676 { "Front Mic", 0x0 },
3677 { "Line-In", 0x1 },
3678 { "Mix", 0x3 },
3683 static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3684 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3685 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3686 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3687 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3688 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3689 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3690 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3691 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3692 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3693 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3694 HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3695 HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3696 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3697 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3698 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3699 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3700 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3701 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3702 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3704 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3705 /* The multiple "Capture Source" controls confuse alsamixer
3706 * So call somewhat different..
3708 /* .name = "Capture Source", */
3709 .name = "Input Source",
3710 .count = 2,
3711 .info = ad198x_mux_enum_info,
3712 .get = ad198x_mux_enum_get,
3713 .put = ad198x_mux_enum_put,
3715 /* SPDIF controls */
3716 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3718 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3719 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3720 /* identical with ad1983 */
3721 .info = ad1983_spdif_route_info,
3722 .get = ad1983_spdif_route_get,
3723 .put = ad1983_spdif_route_put,
3725 { } /* end */
3728 /* additional verbs */
3729 static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
3730 /* Port-E (docking station mic) pin */
3731 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3732 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3733 /* docking mic boost */
3734 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3735 /* Analog PC Beeper - allow firmware/ACPI beeps */
3736 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
3737 /* Analog mixer - docking mic; mute as default */
3738 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3739 /* enable EAPD bit */
3740 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3741 { } /* end */
3745 * Dell Precision T3400
3747 static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3748 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3749 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3750 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3751 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3752 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3753 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3754 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3755 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3756 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
3757 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
3758 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3759 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3760 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3761 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3762 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3764 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3765 /* The multiple "Capture Source" controls confuse alsamixer
3766 * So call somewhat different..
3768 /* .name = "Capture Source", */
3769 .name = "Input Source",
3770 .count = 2,
3771 .info = ad198x_mux_enum_info,
3772 .get = ad198x_mux_enum_get,
3773 .put = ad198x_mux_enum_put,
3775 { } /* end */
3778 /* Digial MIC ADC NID 0x05 + 0x06 */
3779 static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3780 struct hda_codec *codec,
3781 unsigned int stream_tag,
3782 unsigned int format,
3783 struct snd_pcm_substream *substream)
3785 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3786 stream_tag, 0, format);
3787 return 0;
3790 static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3791 struct hda_codec *codec,
3792 struct snd_pcm_substream *substream)
3794 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
3795 return 0;
3798 static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3799 .substreams = 2,
3800 .channels_min = 2,
3801 .channels_max = 2,
3802 .nid = 0x05,
3803 .ops = {
3804 .prepare = ad1984_pcm_dmic_prepare,
3805 .cleanup = ad1984_pcm_dmic_cleanup
3809 static int ad1984_build_pcms(struct hda_codec *codec)
3811 struct ad198x_spec *spec = codec->spec;
3812 struct hda_pcm *info;
3813 int err;
3815 err = ad198x_build_pcms(codec);
3816 if (err < 0)
3817 return err;
3819 info = spec->pcm_rec + codec->num_pcms;
3820 codec->num_pcms++;
3821 info->name = "AD1984 Digital Mic";
3822 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3823 return 0;
3826 /* models */
3827 enum {
3828 AD1984_BASIC,
3829 AD1984_THINKPAD,
3830 AD1984_DELL_DESKTOP,
3831 AD1984_MODELS
3834 static const char * const ad1984_models[AD1984_MODELS] = {
3835 [AD1984_BASIC] = "basic",
3836 [AD1984_THINKPAD] = "thinkpad",
3837 [AD1984_DELL_DESKTOP] = "dell_desktop",
3840 static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
3841 /* Lenovo Thinkpad T61/X61 */
3842 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
3843 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
3844 SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
3848 static int patch_ad1984(struct hda_codec *codec)
3850 struct ad198x_spec *spec;
3851 int board_config, err;
3853 err = patch_ad1884(codec);
3854 if (err < 0)
3855 return err;
3856 spec = codec->spec;
3857 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3858 ad1984_models, ad1984_cfg_tbl);
3859 switch (board_config) {
3860 case AD1984_BASIC:
3861 /* additional digital mics */
3862 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3863 codec->patch_ops.build_pcms = ad1984_build_pcms;
3864 break;
3865 case AD1984_THINKPAD:
3866 if (codec->subsystem_id == 0x17aa20fb) {
3867 /* Thinpad X300 does not have the ability to do SPDIF,
3868 or attach to docking station to use SPDIF */
3869 spec->multiout.dig_out_nid = 0;
3870 } else
3871 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3872 spec->input_mux = &ad1984_thinkpad_capture_source;
3873 spec->mixers[0] = ad1984_thinkpad_mixers;
3874 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
3875 spec->analog_beep = 1;
3876 break;
3877 case AD1984_DELL_DESKTOP:
3878 spec->multiout.dig_out_nid = 0;
3879 spec->input_mux = &ad1984_dell_desktop_capture_source;
3880 spec->mixers[0] = ad1984_dell_desktop_mixers;
3881 break;
3883 return 0;
3888 * AD1883 / AD1884A / AD1984A / AD1984B
3890 * port-B (0x14) - front mic-in
3891 * port-E (0x1c) - rear mic-in
3892 * port-F (0x16) - CD / ext out
3893 * port-C (0x15) - rear line-in
3894 * port-D (0x12) - rear line-out
3895 * port-A (0x11) - front hp-out
3897 * AD1984A = AD1884A + digital-mic
3898 * AD1883 = equivalent with AD1984A
3899 * AD1984B = AD1984A + extra SPDIF-out
3901 * FIXME:
3902 * We share the single DAC for both HP and line-outs (see AD1884/1984).
3905 static const hda_nid_t ad1884a_dac_nids[1] = {
3906 0x03,
3909 #define ad1884a_adc_nids ad1884_adc_nids
3910 #define ad1884a_capsrc_nids ad1884_capsrc_nids
3912 #define AD1884A_SPDIF_OUT 0x02
3914 static const struct hda_input_mux ad1884a_capture_source = {
3915 .num_items = 5,
3916 .items = {
3917 { "Front Mic", 0x0 },
3918 { "Mic", 0x4 },
3919 { "Line", 0x1 },
3920 { "CD", 0x2 },
3921 { "Mix", 0x3 },
3925 static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
3926 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3927 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3928 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3929 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3930 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3931 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3932 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3933 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3934 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3935 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3936 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3937 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3938 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3939 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3940 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3941 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3942 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3943 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
3944 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3945 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3946 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3947 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3948 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3950 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3951 /* The multiple "Capture Source" controls confuse alsamixer
3952 * So call somewhat different..
3954 /* .name = "Capture Source", */
3955 .name = "Input Source",
3956 .count = 2,
3957 .info = ad198x_mux_enum_info,
3958 .get = ad198x_mux_enum_get,
3959 .put = ad198x_mux_enum_put,
3961 /* SPDIF controls */
3962 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3964 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3965 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3966 /* identical with ad1983 */
3967 .info = ad1983_spdif_route_info,
3968 .get = ad1983_spdif_route_get,
3969 .put = ad1983_spdif_route_put,
3971 { } /* end */
3975 * initialization verbs
3977 static const struct hda_verb ad1884a_init_verbs[] = {
3978 /* DACs; unmute as default */
3979 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3980 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3981 /* Port-A (HP) mixer - route only from analog mixer */
3982 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3983 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3984 /* Port-A pin */
3985 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3986 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3987 /* Port-D (Line-out) mixer - route only from analog mixer */
3988 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3989 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3990 /* Port-D pin */
3991 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3992 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3993 /* Mono-out mixer - route only from analog mixer */
3994 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3995 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3996 /* Mono-out pin */
3997 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3998 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3999 /* Port-B (front mic) pin */
4000 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4001 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4002 /* Port-C (rear line-in) pin */
4003 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4004 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4005 /* Port-E (rear mic) pin */
4006 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4007 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4008 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
4009 /* Port-F (CD) pin */
4010 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4011 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4012 /* Analog mixer; mute as default */
4013 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4014 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4015 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4016 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4017 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
4018 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4019 /* Analog Mix output amp */
4020 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4021 /* capture sources */
4022 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
4023 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4024 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4025 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4026 /* SPDIF output amp */
4027 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4028 { } /* end */
4031 #ifdef CONFIG_SND_HDA_POWER_SAVE
4032 static const struct hda_amp_list ad1884a_loopbacks[] = {
4033 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4034 { 0x20, HDA_INPUT, 1 }, /* Mic */
4035 { 0x20, HDA_INPUT, 2 }, /* CD */
4036 { 0x20, HDA_INPUT, 4 }, /* Docking */
4037 { } /* end */
4039 #endif
4042 * Laptop model
4044 * Port A: Headphone jack
4045 * Port B: MIC jack
4046 * Port C: Internal MIC
4047 * Port D: Dock Line Out (if enabled)
4048 * Port E: Dock Line In (if enabled)
4049 * Port F: Internal speakers
4052 static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
4053 struct snd_ctl_elem_value *ucontrol)
4055 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4056 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
4057 int mute = (!ucontrol->value.integer.value[0] &&
4058 !ucontrol->value.integer.value[1]);
4059 /* toggle GPIO1 according to the mute state */
4060 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
4061 mute ? 0x02 : 0x0);
4062 return ret;
4065 static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
4066 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4068 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4069 .name = "Master Playback Switch",
4070 .subdevice = HDA_SUBDEV_AMP_FLAG,
4071 .info = snd_hda_mixer_amp_switch_info,
4072 .get = snd_hda_mixer_amp_switch_get,
4073 .put = ad1884a_mobile_master_sw_put,
4074 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4076 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4077 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4078 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4079 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4080 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4081 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4082 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4083 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4084 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4085 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4086 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
4087 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
4088 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4089 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4090 { } /* end */
4093 static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
4094 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4095 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4097 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4098 .name = "Master Playback Switch",
4099 .subdevice = HDA_SUBDEV_AMP_FLAG,
4100 .info = snd_hda_mixer_amp_switch_info,
4101 .get = snd_hda_mixer_amp_switch_get,
4102 .put = ad1884a_mobile_master_sw_put,
4103 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4105 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4106 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4107 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
4108 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
4109 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4110 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4111 { } /* end */
4114 /* mute internal speaker if HP is plugged */
4115 static void ad1884a_hp_automute(struct hda_codec *codec)
4117 unsigned int present;
4119 present = snd_hda_jack_detect(codec, 0x11);
4120 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4121 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4122 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4123 present ? 0x00 : 0x02);
4126 /* switch to external mic if plugged */
4127 static void ad1884a_hp_automic(struct hda_codec *codec)
4129 unsigned int present;
4131 present = snd_hda_jack_detect(codec, 0x14);
4132 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
4133 present ? 0 : 1);
4136 #define AD1884A_HP_EVENT 0x37
4137 #define AD1884A_MIC_EVENT 0x36
4139 /* unsolicited event for HP jack sensing */
4140 static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4142 switch (res >> 26) {
4143 case AD1884A_HP_EVENT:
4144 ad1884a_hp_automute(codec);
4145 break;
4146 case AD1884A_MIC_EVENT:
4147 ad1884a_hp_automic(codec);
4148 break;
4152 /* initialize jack-sensing, too */
4153 static int ad1884a_hp_init(struct hda_codec *codec)
4155 ad198x_init(codec);
4156 ad1884a_hp_automute(codec);
4157 ad1884a_hp_automic(codec);
4158 return 0;
4161 /* mute internal speaker if HP or docking HP is plugged */
4162 static void ad1884a_laptop_automute(struct hda_codec *codec)
4164 unsigned int present;
4166 present = snd_hda_jack_detect(codec, 0x11);
4167 if (!present)
4168 present = snd_hda_jack_detect(codec, 0x12);
4169 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4170 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4171 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4172 present ? 0x00 : 0x02);
4175 /* switch to external mic if plugged */
4176 static void ad1884a_laptop_automic(struct hda_codec *codec)
4178 unsigned int idx;
4180 if (snd_hda_jack_detect(codec, 0x14))
4181 idx = 0;
4182 else if (snd_hda_jack_detect(codec, 0x1c))
4183 idx = 4;
4184 else
4185 idx = 1;
4186 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
4189 /* unsolicited event for HP jack sensing */
4190 static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
4191 unsigned int res)
4193 switch (res >> 26) {
4194 case AD1884A_HP_EVENT:
4195 ad1884a_laptop_automute(codec);
4196 break;
4197 case AD1884A_MIC_EVENT:
4198 ad1884a_laptop_automic(codec);
4199 break;
4203 /* initialize jack-sensing, too */
4204 static int ad1884a_laptop_init(struct hda_codec *codec)
4206 ad198x_init(codec);
4207 ad1884a_laptop_automute(codec);
4208 ad1884a_laptop_automic(codec);
4209 return 0;
4212 /* additional verbs for laptop model */
4213 static const struct hda_verb ad1884a_laptop_verbs[] = {
4214 /* Port-A (HP) pin - always unmuted */
4215 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4216 /* Port-F (int speaker) mixer - route only from analog mixer */
4217 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4218 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4219 /* Port-F (int speaker) pin */
4220 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4221 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4222 /* required for compaq 6530s/6531s speaker output */
4223 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4224 /* Port-C pin - internal mic-in */
4225 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4226 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4227 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4228 /* Port-D (docking line-out) pin - default unmuted */
4229 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4230 /* analog mix */
4231 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4232 /* unsolicited event for pin-sense */
4233 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4234 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4235 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4236 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4237 /* allow to touch GPIO1 (for mute control) */
4238 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4239 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4240 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4241 { } /* end */
4244 static const struct hda_verb ad1884a_mobile_verbs[] = {
4245 /* DACs; unmute as default */
4246 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4247 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4248 /* Port-A (HP) mixer - route only from analog mixer */
4249 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4250 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4251 /* Port-A pin */
4252 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4253 /* Port-A (HP) pin - always unmuted */
4254 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4255 /* Port-B (mic jack) pin */
4256 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4257 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4258 /* Port-C (int mic) pin */
4259 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4260 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4261 /* Port-F (int speaker) mixer - route only from analog mixer */
4262 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4263 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4264 /* Port-F pin */
4265 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4266 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4267 /* Analog mixer; mute as default */
4268 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4269 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4270 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4271 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4272 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4273 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4274 /* Analog Mix output amp */
4275 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4276 /* capture sources */
4277 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4278 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4279 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4280 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4281 /* unsolicited event for pin-sense */
4282 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4283 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4284 /* allow to touch GPIO1 (for mute control) */
4285 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4286 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4287 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4288 { } /* end */
4292 * Thinkpad X300
4293 * 0x11 - HP
4294 * 0x12 - speaker
4295 * 0x14 - mic-in
4296 * 0x17 - built-in mic
4299 static const struct hda_verb ad1984a_thinkpad_verbs[] = {
4300 /* HP unmute */
4301 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4302 /* analog mix */
4303 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4304 /* turn on EAPD */
4305 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4306 /* unsolicited event for pin-sense */
4307 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4308 /* internal mic - dmic */
4309 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4310 /* set magic COEFs for dmic */
4311 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4312 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4313 { } /* end */
4316 static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
4317 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4318 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4319 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4320 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4321 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4322 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4323 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4324 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
4325 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4326 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4328 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4329 .name = "Capture Source",
4330 .info = ad198x_mux_enum_info,
4331 .get = ad198x_mux_enum_get,
4332 .put = ad198x_mux_enum_put,
4334 { } /* end */
4337 static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
4338 .num_items = 3,
4339 .items = {
4340 { "Mic", 0x0 },
4341 { "Internal Mic", 0x5 },
4342 { "Mix", 0x3 },
4346 /* mute internal speaker if HP is plugged */
4347 static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4349 unsigned int present;
4351 present = snd_hda_jack_detect(codec, 0x11);
4352 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4353 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4356 /* unsolicited event for HP jack sensing */
4357 static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4358 unsigned int res)
4360 if ((res >> 26) != AD1884A_HP_EVENT)
4361 return;
4362 ad1984a_thinkpad_automute(codec);
4365 /* initialize jack-sensing, too */
4366 static int ad1984a_thinkpad_init(struct hda_codec *codec)
4368 ad198x_init(codec);
4369 ad1984a_thinkpad_automute(codec);
4370 return 0;
4374 * Precision R5500
4375 * 0x12 - HP/line-out
4376 * 0x13 - speaker (mono)
4377 * 0x15 - mic-in
4380 static const struct hda_verb ad1984a_precision_verbs[] = {
4381 /* Unmute main output path */
4382 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4383 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */
4384 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */
4385 /* Analog mixer; mute as default */
4386 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4387 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4388 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4389 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4390 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4391 /* Select mic as input */
4392 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
4393 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */
4394 /* Configure as mic */
4395 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4396 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4397 /* HP unmute */
4398 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4399 /* turn on EAPD */
4400 {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4401 /* unsolicited event for pin-sense */
4402 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4403 { } /* end */
4406 static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
4407 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4408 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4409 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4410 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4411 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4412 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4413 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
4414 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4415 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT),
4416 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4417 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4418 { } /* end */
4422 /* mute internal speaker if HP is plugged */
4423 static void ad1984a_precision_automute(struct hda_codec *codec)
4425 unsigned int present;
4427 present = snd_hda_jack_detect(codec, 0x12);
4428 snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
4429 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4433 /* unsolicited event for HP jack sensing */
4434 static void ad1984a_precision_unsol_event(struct hda_codec *codec,
4435 unsigned int res)
4437 if ((res >> 26) != AD1884A_HP_EVENT)
4438 return;
4439 ad1984a_precision_automute(codec);
4442 /* initialize jack-sensing, too */
4443 static int ad1984a_precision_init(struct hda_codec *codec)
4445 ad198x_init(codec);
4446 ad1984a_precision_automute(codec);
4447 return 0;
4452 * HP Touchsmart
4453 * port-A (0x11) - front hp-out
4454 * port-B (0x14) - unused
4455 * port-C (0x15) - unused
4456 * port-D (0x12) - rear line out
4457 * port-E (0x1c) - front mic-in
4458 * port-F (0x16) - Internal speakers
4459 * digital-mic (0x17) - Internal mic
4462 static const struct hda_verb ad1984a_touchsmart_verbs[] = {
4463 /* DACs; unmute as default */
4464 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4465 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4466 /* Port-A (HP) mixer - route only from analog mixer */
4467 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4468 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4469 /* Port-A pin */
4470 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4471 /* Port-A (HP) pin - always unmuted */
4472 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4473 /* Port-E (int speaker) mixer - route only from analog mixer */
4474 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4475 /* Port-E pin */
4476 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4477 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4478 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4479 /* Port-F (int speaker) mixer - route only from analog mixer */
4480 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4481 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4482 /* Port-F pin */
4483 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4484 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4485 /* Analog mixer; mute as default */
4486 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4487 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4488 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4489 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4490 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4491 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4492 /* Analog Mix output amp */
4493 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4494 /* capture sources */
4495 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4496 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4497 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4498 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4499 /* unsolicited event for pin-sense */
4500 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4501 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4502 /* allow to touch GPIO1 (for mute control) */
4503 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4504 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4505 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4506 /* internal mic - dmic */
4507 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4508 /* set magic COEFs for dmic */
4509 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4510 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4511 { } /* end */
4514 static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
4515 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4516 /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4518 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4519 .subdevice = HDA_SUBDEV_AMP_FLAG,
4520 .name = "Master Playback Switch",
4521 .info = snd_hda_mixer_amp_switch_info,
4522 .get = snd_hda_mixer_amp_switch_get,
4523 .put = ad1884a_mobile_master_sw_put,
4524 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4526 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4527 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4528 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4529 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4530 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
4531 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
4532 { } /* end */
4535 /* switch to external mic if plugged */
4536 static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4538 if (snd_hda_jack_detect(codec, 0x1c))
4539 snd_hda_codec_write(codec, 0x0c, 0,
4540 AC_VERB_SET_CONNECT_SEL, 0x4);
4541 else
4542 snd_hda_codec_write(codec, 0x0c, 0,
4543 AC_VERB_SET_CONNECT_SEL, 0x5);
4547 /* unsolicited event for HP jack sensing */
4548 static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4549 unsigned int res)
4551 switch (res >> 26) {
4552 case AD1884A_HP_EVENT:
4553 ad1884a_hp_automute(codec);
4554 break;
4555 case AD1884A_MIC_EVENT:
4556 ad1984a_touchsmart_automic(codec);
4557 break;
4561 /* initialize jack-sensing, too */
4562 static int ad1984a_touchsmart_init(struct hda_codec *codec)
4564 ad198x_init(codec);
4565 ad1884a_hp_automute(codec);
4566 ad1984a_touchsmart_automic(codec);
4567 return 0;
4574 enum {
4575 AD1884A_DESKTOP,
4576 AD1884A_LAPTOP,
4577 AD1884A_MOBILE,
4578 AD1884A_THINKPAD,
4579 AD1984A_TOUCHSMART,
4580 AD1984A_PRECISION,
4581 AD1884A_MODELS
4584 static const char * const ad1884a_models[AD1884A_MODELS] = {
4585 [AD1884A_DESKTOP] = "desktop",
4586 [AD1884A_LAPTOP] = "laptop",
4587 [AD1884A_MOBILE] = "mobile",
4588 [AD1884A_THINKPAD] = "thinkpad",
4589 [AD1984A_TOUCHSMART] = "touchsmart",
4590 [AD1984A_PRECISION] = "precision",
4593 static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
4594 SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
4595 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
4596 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
4597 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
4598 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
4599 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
4600 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4601 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
4602 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
4603 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
4604 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
4608 static int patch_ad1884a(struct hda_codec *codec)
4610 struct ad198x_spec *spec;
4611 int err, board_config;
4613 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4614 if (spec == NULL)
4615 return -ENOMEM;
4617 codec->spec = spec;
4619 err = snd_hda_attach_beep_device(codec, 0x10);
4620 if (err < 0) {
4621 ad198x_free(codec);
4622 return err;
4624 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4626 spec->multiout.max_channels = 2;
4627 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4628 spec->multiout.dac_nids = ad1884a_dac_nids;
4629 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4630 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4631 spec->adc_nids = ad1884a_adc_nids;
4632 spec->capsrc_nids = ad1884a_capsrc_nids;
4633 spec->input_mux = &ad1884a_capture_source;
4634 spec->num_mixers = 1;
4635 spec->mixers[0] = ad1884a_base_mixers;
4636 spec->num_init_verbs = 1;
4637 spec->init_verbs[0] = ad1884a_init_verbs;
4638 spec->spdif_route = 0;
4639 #ifdef CONFIG_SND_HDA_POWER_SAVE
4640 spec->loopback.amplist = ad1884a_loopbacks;
4641 #endif
4642 codec->patch_ops = ad198x_patch_ops;
4644 /* override some parameters */
4645 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
4646 ad1884a_models,
4647 ad1884a_cfg_tbl);
4648 switch (board_config) {
4649 case AD1884A_LAPTOP:
4650 spec->mixers[0] = ad1884a_laptop_mixers;
4651 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4652 spec->multiout.dig_out_nid = 0;
4653 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4654 codec->patch_ops.init = ad1884a_laptop_init;
4655 /* set the upper-limit for mixer amp to 0dB for avoiding the
4656 * possible damage by overloading
4658 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4659 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4660 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4661 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4662 (1 << AC_AMPCAP_MUTE_SHIFT));
4663 break;
4664 case AD1884A_MOBILE:
4665 spec->mixers[0] = ad1884a_mobile_mixers;
4666 spec->init_verbs[0] = ad1884a_mobile_verbs;
4667 spec->multiout.dig_out_nid = 0;
4668 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4669 codec->patch_ops.init = ad1884a_hp_init;
4670 /* set the upper-limit for mixer amp to 0dB for avoiding the
4671 * possible damage by overloading
4673 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4674 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4675 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4676 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4677 (1 << AC_AMPCAP_MUTE_SHIFT));
4678 break;
4679 case AD1884A_THINKPAD:
4680 spec->mixers[0] = ad1984a_thinkpad_mixers;
4681 spec->init_verbs[spec->num_init_verbs++] =
4682 ad1984a_thinkpad_verbs;
4683 spec->multiout.dig_out_nid = 0;
4684 spec->input_mux = &ad1984a_thinkpad_capture_source;
4685 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4686 codec->patch_ops.init = ad1984a_thinkpad_init;
4687 break;
4688 case AD1984A_PRECISION:
4689 spec->mixers[0] = ad1984a_precision_mixers;
4690 spec->init_verbs[spec->num_init_verbs++] =
4691 ad1984a_precision_verbs;
4692 spec->multiout.dig_out_nid = 0;
4693 codec->patch_ops.unsol_event = ad1984a_precision_unsol_event;
4694 codec->patch_ops.init = ad1984a_precision_init;
4695 break;
4696 case AD1984A_TOUCHSMART:
4697 spec->mixers[0] = ad1984a_touchsmart_mixers;
4698 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4699 spec->multiout.dig_out_nid = 0;
4700 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4701 codec->patch_ops.init = ad1984a_touchsmart_init;
4702 /* set the upper-limit for mixer amp to 0dB for avoiding the
4703 * possible damage by overloading
4705 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4706 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4707 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4708 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4709 (1 << AC_AMPCAP_MUTE_SHIFT));
4710 break;
4713 codec->no_trigger_sense = 1;
4714 codec->no_sticky_stream = 1;
4716 return 0;
4721 * AD1882 / AD1882A
4723 * port-A - front hp-out
4724 * port-B - front mic-in
4725 * port-C - rear line-in, shared surr-out (3stack)
4726 * port-D - rear line-out
4727 * port-E - rear mic-in, shared clfe-out (3stack)
4728 * port-F - rear surr-out (6stack)
4729 * port-G - rear clfe-out (6stack)
4732 static const hda_nid_t ad1882_dac_nids[3] = {
4733 0x04, 0x03, 0x05
4736 static const hda_nid_t ad1882_adc_nids[2] = {
4737 0x08, 0x09,
4740 static const hda_nid_t ad1882_capsrc_nids[2] = {
4741 0x0c, 0x0d,
4744 #define AD1882_SPDIF_OUT 0x02
4746 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
4747 static const struct hda_input_mux ad1882_capture_source = {
4748 .num_items = 5,
4749 .items = {
4750 { "Front Mic", 0x1 },
4751 { "Mic", 0x4 },
4752 { "Line", 0x2 },
4753 { "CD", 0x3 },
4754 { "Mix", 0x7 },
4758 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
4759 static const struct hda_input_mux ad1882a_capture_source = {
4760 .num_items = 5,
4761 .items = {
4762 { "Front Mic", 0x1 },
4763 { "Mic", 0x4},
4764 { "Line", 0x2 },
4765 { "Digital Mic", 0x06 },
4766 { "Mix", 0x7 },
4770 static const struct snd_kcontrol_new ad1882_base_mixers[] = {
4771 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4772 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4773 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4774 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4775 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4776 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4777 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4778 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
4780 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
4781 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
4782 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
4783 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4784 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4785 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4786 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4788 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4789 /* The multiple "Capture Source" controls confuse alsamixer
4790 * So call somewhat different..
4792 /* .name = "Capture Source", */
4793 .name = "Input Source",
4794 .count = 2,
4795 .info = ad198x_mux_enum_info,
4796 .get = ad198x_mux_enum_get,
4797 .put = ad198x_mux_enum_put,
4799 /* SPDIF controls */
4800 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4802 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4803 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4804 /* identical with ad1983 */
4805 .info = ad1983_spdif_route_info,
4806 .get = ad1983_spdif_route_get,
4807 .put = ad1983_spdif_route_put,
4809 { } /* end */
4812 static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4813 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4814 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4815 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4816 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4817 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4818 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4819 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4820 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4821 { } /* end */
4824 static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4825 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4826 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4827 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4828 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4829 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4830 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4831 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4832 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4833 HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
4834 { } /* end */
4837 static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4838 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4839 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4840 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4842 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4843 .name = "Channel Mode",
4844 .info = ad198x_ch_mode_info,
4845 .get = ad198x_ch_mode_get,
4846 .put = ad198x_ch_mode_put,
4848 { } /* end */
4851 static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4852 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4853 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4854 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4855 { } /* end */
4858 static const struct hda_verb ad1882_ch2_init[] = {
4859 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4860 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4861 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4862 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4863 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4864 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4865 { } /* end */
4868 static const struct hda_verb ad1882_ch4_init[] = {
4869 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4870 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4871 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4872 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4873 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4874 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4875 { } /* end */
4878 static const struct hda_verb ad1882_ch6_init[] = {
4879 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4880 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4881 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4882 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4883 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4884 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4885 { } /* end */
4888 static const struct hda_channel_mode ad1882_modes[3] = {
4889 { 2, ad1882_ch2_init },
4890 { 4, ad1882_ch4_init },
4891 { 6, ad1882_ch6_init },
4895 * initialization verbs
4897 static const struct hda_verb ad1882_init_verbs[] = {
4898 /* DACs; mute as default */
4899 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4900 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4901 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4902 /* Port-A (HP) mixer */
4903 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4904 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4905 /* Port-A pin */
4906 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4907 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4908 /* HP selector - select DAC2 */
4909 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4910 /* Port-D (Line-out) mixer */
4911 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4912 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4913 /* Port-D pin */
4914 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4915 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4916 /* Mono-out mixer */
4917 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4918 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4919 /* Mono-out pin */
4920 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4921 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4922 /* Port-B (front mic) pin */
4923 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4924 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4925 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4926 /* Port-C (line-in) pin */
4927 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4928 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4929 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4930 /* Port-C mixer - mute as input */
4931 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4932 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4933 /* Port-E (mic-in) pin */
4934 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4935 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4936 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4937 /* Port-E mixer - mute as input */
4938 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4939 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4940 /* Port-F (surround) */
4941 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4942 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4943 /* Port-G (CLFE) */
4944 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4945 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4946 /* Analog mixer; mute as default */
4947 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
4948 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4949 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4950 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4951 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4952 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4953 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4954 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4955 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4956 /* Analog Mix output amp */
4957 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
4958 /* SPDIF output selector */
4959 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4960 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
4961 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4962 { } /* end */
4965 #ifdef CONFIG_SND_HDA_POWER_SAVE
4966 static const struct hda_amp_list ad1882_loopbacks[] = {
4967 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4968 { 0x20, HDA_INPUT, 1 }, /* Mic */
4969 { 0x20, HDA_INPUT, 4 }, /* Line */
4970 { 0x20, HDA_INPUT, 6 }, /* CD */
4971 { } /* end */
4973 #endif
4975 /* models */
4976 enum {
4977 AD1882_3STACK,
4978 AD1882_6STACK,
4979 AD1882_MODELS
4982 static const char * const ad1882_models[AD1986A_MODELS] = {
4983 [AD1882_3STACK] = "3stack",
4984 [AD1882_6STACK] = "6stack",
4988 static int patch_ad1882(struct hda_codec *codec)
4990 struct ad198x_spec *spec;
4991 int err, board_config;
4993 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4994 if (spec == NULL)
4995 return -ENOMEM;
4997 codec->spec = spec;
4999 err = snd_hda_attach_beep_device(codec, 0x10);
5000 if (err < 0) {
5001 ad198x_free(codec);
5002 return err;
5004 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
5006 spec->multiout.max_channels = 6;
5007 spec->multiout.num_dacs = 3;
5008 spec->multiout.dac_nids = ad1882_dac_nids;
5009 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
5010 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
5011 spec->adc_nids = ad1882_adc_nids;
5012 spec->capsrc_nids = ad1882_capsrc_nids;
5013 if (codec->vendor_id == 0x11d41882)
5014 spec->input_mux = &ad1882_capture_source;
5015 else
5016 spec->input_mux = &ad1882a_capture_source;
5017 spec->num_mixers = 2;
5018 spec->mixers[0] = ad1882_base_mixers;
5019 if (codec->vendor_id == 0x11d41882)
5020 spec->mixers[1] = ad1882_loopback_mixers;
5021 else
5022 spec->mixers[1] = ad1882a_loopback_mixers;
5023 spec->num_init_verbs = 1;
5024 spec->init_verbs[0] = ad1882_init_verbs;
5025 spec->spdif_route = 0;
5026 #ifdef CONFIG_SND_HDA_POWER_SAVE
5027 spec->loopback.amplist = ad1882_loopbacks;
5028 #endif
5029 spec->vmaster_nid = 0x04;
5031 codec->patch_ops = ad198x_patch_ops;
5033 /* override some parameters */
5034 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
5035 ad1882_models, NULL);
5036 switch (board_config) {
5037 default:
5038 case AD1882_3STACK:
5039 spec->num_mixers = 3;
5040 spec->mixers[2] = ad1882_3stack_mixers;
5041 spec->channel_mode = ad1882_modes;
5042 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
5043 spec->need_dac_fix = 1;
5044 spec->multiout.max_channels = 2;
5045 spec->multiout.num_dacs = 1;
5046 break;
5047 case AD1882_6STACK:
5048 spec->num_mixers = 3;
5049 spec->mixers[2] = ad1882_6stack_mixers;
5050 break;
5053 codec->no_trigger_sense = 1;
5054 codec->no_sticky_stream = 1;
5056 return 0;
5061 * patch entries
5063 static const struct hda_codec_preset snd_hda_preset_analog[] = {
5064 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
5065 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
5066 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
5067 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
5068 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
5069 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
5070 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
5071 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
5072 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
5073 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
5074 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
5075 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
5076 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
5077 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
5078 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
5079 {} /* terminator */
5082 MODULE_ALIAS("snd-hda-codec-id:11d4*");
5084 MODULE_LICENSE("GPL");
5085 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
5087 static struct hda_codec_preset_list analog_list = {
5088 .preset = snd_hda_preset_analog,
5089 .owner = THIS_MODULE,
5092 static int __init patch_analog_init(void)
5094 return snd_hda_add_codec_preset(&analog_list);
5097 static void __exit patch_analog_exit(void)
5099 snd_hda_delete_codec_preset(&analog_list);
5102 module_init(patch_analog_init)
5103 module_exit(patch_analog_exit)