Merge branch 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groec...
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / sound / pci / hda / patch_analog.c
blobf7ff3f7ccb8e938e7f074afea766495907bc7e1e
1 /*
2 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
3 * AD1986A, AD1988
5 * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
7 * This driver is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This driver is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <linux/init.h>
23 #include <linux/delay.h>
24 #include <linux/slab.h>
25 #include <linux/pci.h>
27 #include <sound/core.h>
28 #include "hda_codec.h"
29 #include "hda_local.h"
30 #include "hda_beep.h"
32 struct ad198x_spec {
33 struct snd_kcontrol_new *mixers[5];
34 int num_mixers;
35 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
36 const struct hda_verb *init_verbs[5]; /* initialization verbs
37 * don't forget NULL termination!
39 unsigned int num_init_verbs;
41 /* playback */
42 struct hda_multi_out multiout; /* playback set-up
43 * max_channels, dacs must be set
44 * dig_out_nid and hp_nid are optional
46 unsigned int cur_eapd;
47 unsigned int need_dac_fix;
49 /* capture */
50 unsigned int num_adc_nids;
51 hda_nid_t *adc_nids;
52 hda_nid_t dig_in_nid; /* digital-in NID; optional */
54 /* capture source */
55 const struct hda_input_mux *input_mux;
56 hda_nid_t *capsrc_nids;
57 unsigned int cur_mux[3];
59 /* channel model */
60 const struct hda_channel_mode *channel_mode;
61 int num_channel_mode;
63 /* PCM information */
64 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
66 unsigned int spdif_route;
68 /* dynamic controls, init_verbs and input_mux */
69 struct auto_pin_cfg autocfg;
70 struct snd_array kctls;
71 struct hda_input_mux private_imux;
72 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
74 unsigned int jack_present: 1;
75 unsigned int inv_jack_detect: 1;/* inverted jack-detection */
76 unsigned int inv_eapd: 1; /* inverted EAPD implementation */
77 unsigned int analog_beep: 1; /* analog beep input present */
79 #ifdef CONFIG_SND_HDA_POWER_SAVE
80 struct hda_loopback_check loopback;
81 #endif
82 /* for virtual master */
83 hda_nid_t vmaster_nid;
84 const char **slave_vols;
85 const char **slave_sws;
89 * input MUX handling (common part)
91 static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
93 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
94 struct ad198x_spec *spec = codec->spec;
96 return snd_hda_input_mux_info(spec->input_mux, uinfo);
99 static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
101 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
102 struct ad198x_spec *spec = codec->spec;
103 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
105 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
106 return 0;
109 static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
111 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
112 struct ad198x_spec *spec = codec->spec;
113 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
115 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
116 spec->capsrc_nids[adc_idx],
117 &spec->cur_mux[adc_idx]);
121 * initialization (common callbacks)
123 static int ad198x_init(struct hda_codec *codec)
125 struct ad198x_spec *spec = codec->spec;
126 int i;
128 for (i = 0; i < spec->num_init_verbs; i++)
129 snd_hda_sequence_write(codec, spec->init_verbs[i]);
130 return 0;
133 static const char *ad_slave_vols[] = {
134 "Front Playback Volume",
135 "Surround Playback Volume",
136 "Center Playback Volume",
137 "LFE Playback Volume",
138 "Side Playback Volume",
139 "Headphone Playback Volume",
140 "Mono Playback Volume",
141 "Speaker Playback Volume",
142 "IEC958 Playback Volume",
143 NULL
146 static const char *ad_slave_sws[] = {
147 "Front Playback Switch",
148 "Surround Playback Switch",
149 "Center Playback Switch",
150 "LFE Playback Switch",
151 "Side Playback Switch",
152 "Headphone Playback Switch",
153 "Mono Playback Switch",
154 "Speaker Playback Switch",
155 "IEC958 Playback Switch",
156 NULL
159 static void ad198x_free_kctls(struct hda_codec *codec);
161 #ifdef CONFIG_SND_HDA_INPUT_BEEP
162 /* additional beep mixers; the actual parameters are overwritten at build */
163 static struct snd_kcontrol_new ad_beep_mixer[] = {
164 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
165 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
166 { } /* end */
169 static struct snd_kcontrol_new ad_beep2_mixer[] = {
170 HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
171 HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
172 { } /* end */
175 #define set_beep_amp(spec, nid, idx, dir) \
176 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
177 #else
178 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
179 #endif
181 static int ad198x_build_controls(struct hda_codec *codec)
183 struct ad198x_spec *spec = codec->spec;
184 struct snd_kcontrol *kctl;
185 unsigned int i;
186 int err;
188 for (i = 0; i < spec->num_mixers; i++) {
189 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
190 if (err < 0)
191 return err;
193 if (spec->multiout.dig_out_nid) {
194 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
195 if (err < 0)
196 return err;
197 err = snd_hda_create_spdif_share_sw(codec,
198 &spec->multiout);
199 if (err < 0)
200 return err;
201 spec->multiout.share_spdif = 1;
203 if (spec->dig_in_nid) {
204 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
205 if (err < 0)
206 return err;
209 /* create beep controls if needed */
210 #ifdef CONFIG_SND_HDA_INPUT_BEEP
211 if (spec->beep_amp) {
212 struct snd_kcontrol_new *knew;
213 knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
214 for ( ; knew->name; knew++) {
215 struct snd_kcontrol *kctl;
216 kctl = snd_ctl_new1(knew, codec);
217 if (!kctl)
218 return -ENOMEM;
219 kctl->private_value = spec->beep_amp;
220 err = snd_hda_ctl_add(codec, 0, kctl);
221 if (err < 0)
222 return err;
225 #endif
227 /* if we have no master control, let's create it */
228 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
229 unsigned int vmaster_tlv[4];
230 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
231 HDA_OUTPUT, vmaster_tlv);
232 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
233 vmaster_tlv,
234 (spec->slave_vols ?
235 spec->slave_vols : ad_slave_vols));
236 if (err < 0)
237 return err;
239 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
240 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
241 NULL,
242 (spec->slave_sws ?
243 spec->slave_sws : ad_slave_sws));
244 if (err < 0)
245 return err;
248 ad198x_free_kctls(codec); /* no longer needed */
250 /* assign Capture Source enums to NID */
251 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
252 if (!kctl)
253 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
254 for (i = 0; kctl && i < kctl->count; i++) {
255 err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
256 if (err < 0)
257 return err;
260 /* assign IEC958 enums to NID */
261 kctl = snd_hda_find_mixer_ctl(codec,
262 SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
263 if (kctl) {
264 err = snd_hda_add_nid(codec, kctl, 0,
265 spec->multiout.dig_out_nid);
266 if (err < 0)
267 return err;
270 return 0;
273 #ifdef CONFIG_SND_HDA_POWER_SAVE
274 static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
276 struct ad198x_spec *spec = codec->spec;
277 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
279 #endif
282 * Analog playback callbacks
284 static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
285 struct hda_codec *codec,
286 struct snd_pcm_substream *substream)
288 struct ad198x_spec *spec = codec->spec;
289 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
290 hinfo);
293 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
294 struct hda_codec *codec,
295 unsigned int stream_tag,
296 unsigned int format,
297 struct snd_pcm_substream *substream)
299 struct ad198x_spec *spec = codec->spec;
300 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
301 format, substream);
304 static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
305 struct hda_codec *codec,
306 struct snd_pcm_substream *substream)
308 struct ad198x_spec *spec = codec->spec;
309 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
313 * Digital out
315 static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
316 struct hda_codec *codec,
317 struct snd_pcm_substream *substream)
319 struct ad198x_spec *spec = codec->spec;
320 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
323 static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
324 struct hda_codec *codec,
325 struct snd_pcm_substream *substream)
327 struct ad198x_spec *spec = codec->spec;
328 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
331 static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
332 struct hda_codec *codec,
333 unsigned int stream_tag,
334 unsigned int format,
335 struct snd_pcm_substream *substream)
337 struct ad198x_spec *spec = codec->spec;
338 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
339 format, substream);
342 static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
343 struct hda_codec *codec,
344 struct snd_pcm_substream *substream)
346 struct ad198x_spec *spec = codec->spec;
347 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
351 * Analog capture
353 static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
354 struct hda_codec *codec,
355 unsigned int stream_tag,
356 unsigned int format,
357 struct snd_pcm_substream *substream)
359 struct ad198x_spec *spec = codec->spec;
360 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
361 stream_tag, 0, format);
362 return 0;
365 static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
366 struct hda_codec *codec,
367 struct snd_pcm_substream *substream)
369 struct ad198x_spec *spec = codec->spec;
370 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
371 return 0;
377 static struct hda_pcm_stream ad198x_pcm_analog_playback = {
378 .substreams = 1,
379 .channels_min = 2,
380 .channels_max = 6, /* changed later */
381 .nid = 0, /* fill later */
382 .ops = {
383 .open = ad198x_playback_pcm_open,
384 .prepare = ad198x_playback_pcm_prepare,
385 .cleanup = ad198x_playback_pcm_cleanup
389 static struct hda_pcm_stream ad198x_pcm_analog_capture = {
390 .substreams = 1,
391 .channels_min = 2,
392 .channels_max = 2,
393 .nid = 0, /* fill later */
394 .ops = {
395 .prepare = ad198x_capture_pcm_prepare,
396 .cleanup = ad198x_capture_pcm_cleanup
400 static struct hda_pcm_stream ad198x_pcm_digital_playback = {
401 .substreams = 1,
402 .channels_min = 2,
403 .channels_max = 2,
404 .nid = 0, /* fill later */
405 .ops = {
406 .open = ad198x_dig_playback_pcm_open,
407 .close = ad198x_dig_playback_pcm_close,
408 .prepare = ad198x_dig_playback_pcm_prepare,
409 .cleanup = ad198x_dig_playback_pcm_cleanup
413 static struct hda_pcm_stream ad198x_pcm_digital_capture = {
414 .substreams = 1,
415 .channels_min = 2,
416 .channels_max = 2,
417 /* NID is set in alc_build_pcms */
420 static int ad198x_build_pcms(struct hda_codec *codec)
422 struct ad198x_spec *spec = codec->spec;
423 struct hda_pcm *info = spec->pcm_rec;
425 codec->num_pcms = 1;
426 codec->pcm_info = info;
428 info->name = "AD198x Analog";
429 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
430 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
431 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
432 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
433 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
434 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
436 if (spec->multiout.dig_out_nid) {
437 info++;
438 codec->num_pcms++;
439 info->name = "AD198x Digital";
440 info->pcm_type = HDA_PCM_TYPE_SPDIF;
441 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
442 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
443 if (spec->dig_in_nid) {
444 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
445 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
449 return 0;
452 static inline void ad198x_shutup(struct hda_codec *codec)
454 snd_hda_shutup_pins(codec);
457 static void ad198x_free_kctls(struct hda_codec *codec)
459 struct ad198x_spec *spec = codec->spec;
461 if (spec->kctls.list) {
462 struct snd_kcontrol_new *kctl = spec->kctls.list;
463 int i;
464 for (i = 0; i < spec->kctls.used; i++)
465 kfree(kctl[i].name);
467 snd_array_free(&spec->kctls);
470 static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
471 hda_nid_t hp)
473 struct ad198x_spec *spec = codec->spec;
474 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
475 !spec->inv_eapd ? 0x00 : 0x02);
476 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
477 !spec->inv_eapd ? 0x00 : 0x02);
480 static void ad198x_power_eapd(struct hda_codec *codec)
482 /* We currently only handle front, HP */
483 switch (codec->vendor_id) {
484 case 0x11d41882:
485 case 0x11d4882a:
486 case 0x11d41884:
487 case 0x11d41984:
488 case 0x11d41883:
489 case 0x11d4184a:
490 case 0x11d4194a:
491 case 0x11d4194b:
492 ad198x_power_eapd_write(codec, 0x12, 0x11);
493 break;
494 case 0x11d41981:
495 case 0x11d41983:
496 ad198x_power_eapd_write(codec, 0x05, 0x06);
497 break;
498 case 0x11d41986:
499 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
500 break;
501 case 0x11d41988:
502 case 0x11d4198b:
503 case 0x11d4989a:
504 case 0x11d4989b:
505 ad198x_power_eapd_write(codec, 0x29, 0x22);
506 break;
510 static void ad198x_free(struct hda_codec *codec)
512 struct ad198x_spec *spec = codec->spec;
514 if (!spec)
515 return;
517 ad198x_shutup(codec);
518 ad198x_free_kctls(codec);
519 kfree(spec);
520 snd_hda_detach_beep_device(codec);
523 #ifdef SND_HDA_NEEDS_RESUME
524 static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
526 ad198x_shutup(codec);
527 ad198x_power_eapd(codec);
528 return 0;
530 #endif
532 static struct hda_codec_ops ad198x_patch_ops = {
533 .build_controls = ad198x_build_controls,
534 .build_pcms = ad198x_build_pcms,
535 .init = ad198x_init,
536 .free = ad198x_free,
537 #ifdef CONFIG_SND_HDA_POWER_SAVE
538 .check_power_status = ad198x_check_power_status,
539 #endif
540 #ifdef SND_HDA_NEEDS_RESUME
541 .suspend = ad198x_suspend,
542 #endif
543 .reboot_notify = ad198x_shutup,
548 * EAPD control
549 * the private value = nid
551 #define ad198x_eapd_info snd_ctl_boolean_mono_info
553 static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
554 struct snd_ctl_elem_value *ucontrol)
556 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
557 struct ad198x_spec *spec = codec->spec;
558 if (spec->inv_eapd)
559 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
560 else
561 ucontrol->value.integer.value[0] = spec->cur_eapd;
562 return 0;
565 static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
566 struct snd_ctl_elem_value *ucontrol)
568 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
569 struct ad198x_spec *spec = codec->spec;
570 hda_nid_t nid = kcontrol->private_value & 0xff;
571 unsigned int eapd;
572 eapd = !!ucontrol->value.integer.value[0];
573 if (spec->inv_eapd)
574 eapd = !eapd;
575 if (eapd == spec->cur_eapd)
576 return 0;
577 spec->cur_eapd = eapd;
578 snd_hda_codec_write_cache(codec, nid,
579 0, AC_VERB_SET_EAPD_BTLENABLE,
580 eapd ? 0x02 : 0x00);
581 return 1;
584 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
585 struct snd_ctl_elem_info *uinfo);
586 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
587 struct snd_ctl_elem_value *ucontrol);
588 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
589 struct snd_ctl_elem_value *ucontrol);
593 * AD1986A specific
596 #define AD1986A_SPDIF_OUT 0x02
597 #define AD1986A_FRONT_DAC 0x03
598 #define AD1986A_SURR_DAC 0x04
599 #define AD1986A_CLFE_DAC 0x05
600 #define AD1986A_ADC 0x06
602 static hda_nid_t ad1986a_dac_nids[3] = {
603 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
605 static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
606 static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
608 static struct hda_input_mux ad1986a_capture_source = {
609 .num_items = 7,
610 .items = {
611 { "Mic", 0x0 },
612 { "CD", 0x1 },
613 { "Aux", 0x3 },
614 { "Line", 0x4 },
615 { "Mix", 0x5 },
616 { "Mono", 0x6 },
617 { "Phone", 0x7 },
622 static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
623 .ops = &snd_hda_bind_vol,
624 .values = {
625 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
626 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
627 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
632 static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
633 .ops = &snd_hda_bind_sw,
634 .values = {
635 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
636 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
637 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
643 * mixers
645 static struct snd_kcontrol_new ad1986a_mixers[] = {
647 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
649 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
650 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
651 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
652 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
653 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
654 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
655 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
656 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
657 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
658 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
659 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
660 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
661 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
662 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
663 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
664 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
665 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
666 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
667 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
668 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
669 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
670 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
671 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
672 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
673 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
675 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
676 .name = "Capture Source",
677 .info = ad198x_mux_enum_info,
678 .get = ad198x_mux_enum_get,
679 .put = ad198x_mux_enum_put,
681 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
682 { } /* end */
685 /* additional mixers for 3stack mode */
686 static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
688 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
689 .name = "Channel Mode",
690 .info = ad198x_ch_mode_info,
691 .get = ad198x_ch_mode_get,
692 .put = ad198x_ch_mode_put,
694 { } /* end */
697 /* laptop model - 2ch only */
698 static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
700 /* master controls both pins 0x1a and 0x1b */
701 static struct hda_bind_ctls ad1986a_laptop_master_vol = {
702 .ops = &snd_hda_bind_vol,
703 .values = {
704 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
705 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
710 static struct hda_bind_ctls ad1986a_laptop_master_sw = {
711 .ops = &snd_hda_bind_sw,
712 .values = {
713 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
714 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
719 static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
720 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
721 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
722 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
723 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
724 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
725 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
726 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
727 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
728 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
729 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
730 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
731 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
732 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
734 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
735 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
736 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
737 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
739 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
740 .name = "Capture Source",
741 .info = ad198x_mux_enum_info,
742 .get = ad198x_mux_enum_get,
743 .put = ad198x_mux_enum_put,
745 { } /* end */
748 /* laptop-eapd model - 2ch only */
750 static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
751 .num_items = 3,
752 .items = {
753 { "Mic", 0x0 },
754 { "Internal Mic", 0x4 },
755 { "Mix", 0x5 },
759 static struct hda_input_mux ad1986a_automic_capture_source = {
760 .num_items = 2,
761 .items = {
762 { "Mic", 0x0 },
763 { "Mix", 0x5 },
767 static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
768 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
769 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
770 { } /* end */
773 static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
774 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
775 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
776 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
777 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
778 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
779 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
780 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
782 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
783 .name = "Capture Source",
784 .info = ad198x_mux_enum_info,
785 .get = ad198x_mux_enum_get,
786 .put = ad198x_mux_enum_put,
789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
790 .name = "External Amplifier",
791 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
792 .info = ad198x_eapd_info,
793 .get = ad198x_eapd_get,
794 .put = ad198x_eapd_put,
795 .private_value = 0x1b, /* port-D */
797 { } /* end */
800 static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
801 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
802 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
803 { } /* end */
806 /* re-connect the mic boost input according to the jack sensing */
807 static void ad1986a_automic(struct hda_codec *codec)
809 unsigned int present;
810 present = snd_hda_jack_detect(codec, 0x1f);
811 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
812 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
813 present ? 0 : 2);
816 #define AD1986A_MIC_EVENT 0x36
818 static void ad1986a_automic_unsol_event(struct hda_codec *codec,
819 unsigned int res)
821 if ((res >> 26) != AD1986A_MIC_EVENT)
822 return;
823 ad1986a_automic(codec);
826 static int ad1986a_automic_init(struct hda_codec *codec)
828 ad198x_init(codec);
829 ad1986a_automic(codec);
830 return 0;
833 /* laptop-automute - 2ch only */
835 static void ad1986a_update_hp(struct hda_codec *codec)
837 struct ad198x_spec *spec = codec->spec;
838 unsigned int mute;
840 if (spec->jack_present)
841 mute = HDA_AMP_MUTE; /* mute internal speaker */
842 else
843 /* unmute internal speaker if necessary */
844 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
845 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
846 HDA_AMP_MUTE, mute);
849 static void ad1986a_hp_automute(struct hda_codec *codec)
851 struct ad198x_spec *spec = codec->spec;
853 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
854 if (spec->inv_jack_detect)
855 spec->jack_present = !spec->jack_present;
856 ad1986a_update_hp(codec);
859 #define AD1986A_HP_EVENT 0x37
861 static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
863 if ((res >> 26) != AD1986A_HP_EVENT)
864 return;
865 ad1986a_hp_automute(codec);
868 static int ad1986a_hp_init(struct hda_codec *codec)
870 ad198x_init(codec);
871 ad1986a_hp_automute(codec);
872 return 0;
875 /* bind hp and internal speaker mute (with plug check) */
876 static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
877 struct snd_ctl_elem_value *ucontrol)
879 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
880 long *valp = ucontrol->value.integer.value;
881 int change;
883 change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
884 HDA_AMP_MUTE,
885 valp[0] ? 0 : HDA_AMP_MUTE);
886 change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
887 HDA_AMP_MUTE,
888 valp[1] ? 0 : HDA_AMP_MUTE);
889 if (change)
890 ad1986a_update_hp(codec);
891 return change;
894 static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
895 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
897 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
898 .name = "Master Playback Switch",
899 .subdevice = HDA_SUBDEV_AMP_FLAG,
900 .info = snd_hda_mixer_amp_switch_info,
901 .get = snd_hda_mixer_amp_switch_get,
902 .put = ad1986a_hp_master_sw_put,
903 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
905 { } /* end */
910 * initialization verbs
912 static struct hda_verb ad1986a_init_verbs[] = {
913 /* Front, Surround, CLFE DAC; mute as default */
914 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
915 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
916 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
917 /* Downmix - off */
918 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
919 /* HP, Line-Out, Surround, CLFE selectors */
920 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
921 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
922 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
923 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
924 /* Mono selector */
925 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
926 /* Mic selector: Mic 1/2 pin */
927 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
928 /* Line-in selector: Line-in */
929 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
930 /* Mic 1/2 swap */
931 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
932 /* Record selector: mic */
933 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
934 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
935 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
936 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
937 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
938 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
939 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
940 /* PC beep */
941 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
942 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
943 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
944 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
945 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
946 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
947 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
948 /* HP Pin */
949 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
950 /* Front, Surround, CLFE Pins */
951 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
952 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
953 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
954 /* Mono Pin */
955 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
956 /* Mic Pin */
957 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
958 /* Line, Aux, CD, Beep-In Pin */
959 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
960 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
961 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
962 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
963 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
964 { } /* end */
967 static struct hda_verb ad1986a_ch2_init[] = {
968 /* Surround out -> Line In */
969 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
970 /* Line-in selectors */
971 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
972 /* CLFE -> Mic in */
973 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
974 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
975 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
976 { } /* end */
979 static struct hda_verb ad1986a_ch4_init[] = {
980 /* Surround out -> Surround */
981 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
982 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
983 /* CLFE -> Mic in */
984 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
985 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
986 { } /* end */
989 static struct hda_verb ad1986a_ch6_init[] = {
990 /* Surround out -> Surround out */
991 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
992 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
993 /* CLFE -> CLFE */
994 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
995 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
996 { } /* end */
999 static struct hda_channel_mode ad1986a_modes[3] = {
1000 { 2, ad1986a_ch2_init },
1001 { 4, ad1986a_ch4_init },
1002 { 6, ad1986a_ch6_init },
1005 /* eapd initialization */
1006 static struct hda_verb ad1986a_eapd_init_verbs[] = {
1007 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1011 static struct hda_verb ad1986a_automic_verbs[] = {
1012 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1013 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1014 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
1015 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1016 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
1020 /* Ultra initialization */
1021 static struct hda_verb ad1986a_ultra_init[] = {
1022 /* eapd initialization */
1023 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1024 /* CLFE -> Mic in */
1025 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
1026 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1027 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
1028 { } /* end */
1031 /* pin sensing on HP jack */
1032 static struct hda_verb ad1986a_hp_init_verbs[] = {
1033 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1037 static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
1038 unsigned int res)
1040 switch (res >> 26) {
1041 case AD1986A_HP_EVENT:
1042 ad1986a_hp_automute(codec);
1043 break;
1044 case AD1986A_MIC_EVENT:
1045 ad1986a_automic(codec);
1046 break;
1050 static int ad1986a_samsung_p50_init(struct hda_codec *codec)
1052 ad198x_init(codec);
1053 ad1986a_hp_automute(codec);
1054 ad1986a_automic(codec);
1055 return 0;
1059 /* models */
1060 enum {
1061 AD1986A_6STACK,
1062 AD1986A_3STACK,
1063 AD1986A_LAPTOP,
1064 AD1986A_LAPTOP_EAPD,
1065 AD1986A_LAPTOP_AUTOMUTE,
1066 AD1986A_ULTRA,
1067 AD1986A_SAMSUNG,
1068 AD1986A_SAMSUNG_P50,
1069 AD1986A_MODELS
1072 static const char *ad1986a_models[AD1986A_MODELS] = {
1073 [AD1986A_6STACK] = "6stack",
1074 [AD1986A_3STACK] = "3stack",
1075 [AD1986A_LAPTOP] = "laptop",
1076 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
1077 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
1078 [AD1986A_ULTRA] = "ultra",
1079 [AD1986A_SAMSUNG] = "samsung",
1080 [AD1986A_SAMSUNG_P50] = "samsung-p50",
1083 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
1084 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
1085 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
1086 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
1087 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
1088 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
1089 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
1090 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
1091 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
1092 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
1093 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
1094 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1095 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1096 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1097 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1098 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
1099 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
1100 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
1101 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
1102 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
1103 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
1104 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
1105 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
1106 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
1107 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
1108 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
1109 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
1110 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
1114 #ifdef CONFIG_SND_HDA_POWER_SAVE
1115 static struct hda_amp_list ad1986a_loopbacks[] = {
1116 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1117 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1118 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1119 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1120 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1121 { } /* end */
1123 #endif
1125 static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1127 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
1128 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1131 static int patch_ad1986a(struct hda_codec *codec)
1133 struct ad198x_spec *spec;
1134 int err, board_config;
1136 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1137 if (spec == NULL)
1138 return -ENOMEM;
1140 codec->spec = spec;
1142 err = snd_hda_attach_beep_device(codec, 0x19);
1143 if (err < 0) {
1144 ad198x_free(codec);
1145 return err;
1147 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1149 spec->multiout.max_channels = 6;
1150 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1151 spec->multiout.dac_nids = ad1986a_dac_nids;
1152 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
1153 spec->num_adc_nids = 1;
1154 spec->adc_nids = ad1986a_adc_nids;
1155 spec->capsrc_nids = ad1986a_capsrc_nids;
1156 spec->input_mux = &ad1986a_capture_source;
1157 spec->num_mixers = 1;
1158 spec->mixers[0] = ad1986a_mixers;
1159 spec->num_init_verbs = 1;
1160 spec->init_verbs[0] = ad1986a_init_verbs;
1161 #ifdef CONFIG_SND_HDA_POWER_SAVE
1162 spec->loopback.amplist = ad1986a_loopbacks;
1163 #endif
1164 spec->vmaster_nid = 0x1b;
1165 spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
1167 codec->patch_ops = ad198x_patch_ops;
1169 /* override some parameters */
1170 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1171 ad1986a_models,
1172 ad1986a_cfg_tbl);
1173 switch (board_config) {
1174 case AD1986A_3STACK:
1175 spec->num_mixers = 2;
1176 spec->mixers[1] = ad1986a_3st_mixers;
1177 spec->num_init_verbs = 2;
1178 spec->init_verbs[1] = ad1986a_ch2_init;
1179 spec->channel_mode = ad1986a_modes;
1180 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
1181 spec->need_dac_fix = 1;
1182 spec->multiout.max_channels = 2;
1183 spec->multiout.num_dacs = 1;
1184 break;
1185 case AD1986A_LAPTOP:
1186 spec->mixers[0] = ad1986a_laptop_mixers;
1187 spec->multiout.max_channels = 2;
1188 spec->multiout.num_dacs = 1;
1189 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1190 break;
1191 case AD1986A_LAPTOP_EAPD:
1192 spec->num_mixers = 3;
1193 spec->mixers[0] = ad1986a_laptop_master_mixers;
1194 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1195 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1196 spec->num_init_verbs = 2;
1197 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1198 spec->multiout.max_channels = 2;
1199 spec->multiout.num_dacs = 1;
1200 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1201 if (!is_jack_available(codec, 0x25))
1202 spec->multiout.dig_out_nid = 0;
1203 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1204 break;
1205 case AD1986A_SAMSUNG:
1206 spec->num_mixers = 2;
1207 spec->mixers[0] = ad1986a_laptop_master_mixers;
1208 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1209 spec->num_init_verbs = 3;
1210 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1211 spec->init_verbs[2] = ad1986a_automic_verbs;
1212 spec->multiout.max_channels = 2;
1213 spec->multiout.num_dacs = 1;
1214 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1215 if (!is_jack_available(codec, 0x25))
1216 spec->multiout.dig_out_nid = 0;
1217 spec->input_mux = &ad1986a_automic_capture_source;
1218 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1219 codec->patch_ops.init = ad1986a_automic_init;
1220 break;
1221 case AD1986A_SAMSUNG_P50:
1222 spec->num_mixers = 2;
1223 spec->mixers[0] = ad1986a_automute_master_mixers;
1224 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1225 spec->num_init_verbs = 4;
1226 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1227 spec->init_verbs[2] = ad1986a_automic_verbs;
1228 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1229 spec->multiout.max_channels = 2;
1230 spec->multiout.num_dacs = 1;
1231 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1232 if (!is_jack_available(codec, 0x25))
1233 spec->multiout.dig_out_nid = 0;
1234 spec->input_mux = &ad1986a_automic_capture_source;
1235 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1236 codec->patch_ops.init = ad1986a_samsung_p50_init;
1237 break;
1238 case AD1986A_LAPTOP_AUTOMUTE:
1239 spec->num_mixers = 3;
1240 spec->mixers[0] = ad1986a_automute_master_mixers;
1241 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1242 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1243 spec->num_init_verbs = 3;
1244 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1245 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1246 spec->multiout.max_channels = 2;
1247 spec->multiout.num_dacs = 1;
1248 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1249 if (!is_jack_available(codec, 0x25))
1250 spec->multiout.dig_out_nid = 0;
1251 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1252 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1253 codec->patch_ops.init = ad1986a_hp_init;
1254 /* Lenovo N100 seems to report the reversed bit
1255 * for HP jack-sensing
1257 spec->inv_jack_detect = 1;
1258 break;
1259 case AD1986A_ULTRA:
1260 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1261 spec->num_init_verbs = 2;
1262 spec->init_verbs[1] = ad1986a_ultra_init;
1263 spec->multiout.max_channels = 2;
1264 spec->multiout.num_dacs = 1;
1265 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1266 spec->multiout.dig_out_nid = 0;
1267 break;
1270 /* AD1986A has a hardware problem that it can't share a stream
1271 * with multiple output pins. The copy of front to surrounds
1272 * causes noisy or silent outputs at a certain timing, e.g.
1273 * changing the volume.
1274 * So, let's disable the shared stream.
1276 spec->multiout.no_share_stream = 1;
1278 codec->no_trigger_sense = 1;
1279 codec->no_sticky_stream = 1;
1281 return 0;
1285 * AD1983 specific
1288 #define AD1983_SPDIF_OUT 0x02
1289 #define AD1983_DAC 0x03
1290 #define AD1983_ADC 0x04
1292 static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
1293 static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
1294 static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
1296 static struct hda_input_mux ad1983_capture_source = {
1297 .num_items = 4,
1298 .items = {
1299 { "Mic", 0x0 },
1300 { "Line", 0x1 },
1301 { "Mix", 0x2 },
1302 { "Mix Mono", 0x3 },
1307 * SPDIF playback route
1309 static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1311 static char *texts[] = { "PCM", "ADC" };
1313 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1314 uinfo->count = 1;
1315 uinfo->value.enumerated.items = 2;
1316 if (uinfo->value.enumerated.item > 1)
1317 uinfo->value.enumerated.item = 1;
1318 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1319 return 0;
1322 static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1324 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1325 struct ad198x_spec *spec = codec->spec;
1327 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1328 return 0;
1331 static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1333 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1334 struct ad198x_spec *spec = codec->spec;
1336 if (ucontrol->value.enumerated.item[0] > 1)
1337 return -EINVAL;
1338 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1339 spec->spdif_route = ucontrol->value.enumerated.item[0];
1340 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1341 AC_VERB_SET_CONNECT_SEL,
1342 spec->spdif_route);
1343 return 1;
1345 return 0;
1348 static struct snd_kcontrol_new ad1983_mixers[] = {
1349 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1350 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1351 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1352 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1353 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1354 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1355 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1356 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1357 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1358 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1359 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1360 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1361 HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
1362 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1363 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1365 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1366 .name = "Capture Source",
1367 .info = ad198x_mux_enum_info,
1368 .get = ad198x_mux_enum_get,
1369 .put = ad198x_mux_enum_put,
1372 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1373 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1374 .info = ad1983_spdif_route_info,
1375 .get = ad1983_spdif_route_get,
1376 .put = ad1983_spdif_route_put,
1378 { } /* end */
1381 static struct hda_verb ad1983_init_verbs[] = {
1382 /* Front, HP, Mono; mute as default */
1383 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1384 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1385 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1386 /* Beep, PCM, Mic, Line-In: mute */
1387 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1388 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1389 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1390 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1391 /* Front, HP selectors; from Mix */
1392 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1393 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1394 /* Mono selector; from Mix */
1395 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1396 /* Mic selector; Mic */
1397 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1398 /* Line-in selector: Line-in */
1399 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1400 /* Mic boost: 0dB */
1401 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1402 /* Record selector: mic */
1403 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1404 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1405 /* SPDIF route: PCM */
1406 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1407 /* Front Pin */
1408 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1409 /* HP Pin */
1410 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1411 /* Mono Pin */
1412 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1413 /* Mic Pin */
1414 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1415 /* Line Pin */
1416 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1417 { } /* end */
1420 #ifdef CONFIG_SND_HDA_POWER_SAVE
1421 static struct hda_amp_list ad1983_loopbacks[] = {
1422 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
1423 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1424 { } /* end */
1426 #endif
1428 static int patch_ad1983(struct hda_codec *codec)
1430 struct ad198x_spec *spec;
1431 int err;
1433 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1434 if (spec == NULL)
1435 return -ENOMEM;
1437 codec->spec = spec;
1439 err = snd_hda_attach_beep_device(codec, 0x10);
1440 if (err < 0) {
1441 ad198x_free(codec);
1442 return err;
1444 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1446 spec->multiout.max_channels = 2;
1447 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1448 spec->multiout.dac_nids = ad1983_dac_nids;
1449 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
1450 spec->num_adc_nids = 1;
1451 spec->adc_nids = ad1983_adc_nids;
1452 spec->capsrc_nids = ad1983_capsrc_nids;
1453 spec->input_mux = &ad1983_capture_source;
1454 spec->num_mixers = 1;
1455 spec->mixers[0] = ad1983_mixers;
1456 spec->num_init_verbs = 1;
1457 spec->init_verbs[0] = ad1983_init_verbs;
1458 spec->spdif_route = 0;
1459 #ifdef CONFIG_SND_HDA_POWER_SAVE
1460 spec->loopback.amplist = ad1983_loopbacks;
1461 #endif
1462 spec->vmaster_nid = 0x05;
1464 codec->patch_ops = ad198x_patch_ops;
1466 codec->no_trigger_sense = 1;
1467 codec->no_sticky_stream = 1;
1469 return 0;
1474 * AD1981 HD specific
1477 #define AD1981_SPDIF_OUT 0x02
1478 #define AD1981_DAC 0x03
1479 #define AD1981_ADC 0x04
1481 static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
1482 static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
1483 static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
1485 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
1486 static struct hda_input_mux ad1981_capture_source = {
1487 .num_items = 7,
1488 .items = {
1489 { "Front Mic", 0x0 },
1490 { "Line", 0x1 },
1491 { "Mix", 0x2 },
1492 { "Mix Mono", 0x3 },
1493 { "CD", 0x4 },
1494 { "Mic", 0x6 },
1495 { "Aux", 0x7 },
1499 static struct snd_kcontrol_new ad1981_mixers[] = {
1500 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1501 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1502 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1503 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1504 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1505 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1506 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1507 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1508 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1509 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1510 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1511 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1512 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1513 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1514 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1515 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1516 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1517 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1518 HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
1519 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
1520 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1521 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1523 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1524 .name = "Capture Source",
1525 .info = ad198x_mux_enum_info,
1526 .get = ad198x_mux_enum_get,
1527 .put = ad198x_mux_enum_put,
1529 /* identical with AD1983 */
1531 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1532 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1533 .info = ad1983_spdif_route_info,
1534 .get = ad1983_spdif_route_get,
1535 .put = ad1983_spdif_route_put,
1537 { } /* end */
1540 static struct hda_verb ad1981_init_verbs[] = {
1541 /* Front, HP, Mono; mute as default */
1542 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1543 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1544 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1545 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1546 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1547 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1548 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1549 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1550 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1551 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1552 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1553 /* Front, HP selectors; from Mix */
1554 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1555 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1556 /* Mono selector; from Mix */
1557 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1558 /* Mic Mixer; select Front Mic */
1559 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1560 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1561 /* Mic boost: 0dB */
1562 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1563 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1564 /* Record selector: Front mic */
1565 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1566 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1567 /* SPDIF route: PCM */
1568 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1569 /* Front Pin */
1570 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1571 /* HP Pin */
1572 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1573 /* Mono Pin */
1574 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1575 /* Front & Rear Mic Pins */
1576 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1577 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1578 /* Line Pin */
1579 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1580 /* Digital Beep */
1581 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1582 /* Line-Out as Input: disabled */
1583 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1584 { } /* end */
1587 #ifdef CONFIG_SND_HDA_POWER_SAVE
1588 static struct hda_amp_list ad1981_loopbacks[] = {
1589 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1590 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1591 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1592 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1593 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1594 { } /* end */
1596 #endif
1599 * Patch for HP nx6320
1601 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
1602 * speaker output enabled _and_ mute-LED off.
1605 #define AD1981_HP_EVENT 0x37
1606 #define AD1981_MIC_EVENT 0x38
1608 static struct hda_verb ad1981_hp_init_verbs[] = {
1609 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1610 /* pin sensing on HP and Mic jacks */
1611 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1612 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1616 /* turn on/off EAPD (+ mute HP) as a master switch */
1617 static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1618 struct snd_ctl_elem_value *ucontrol)
1620 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1621 struct ad198x_spec *spec = codec->spec;
1623 if (! ad198x_eapd_put(kcontrol, ucontrol))
1624 return 0;
1625 /* change speaker pin appropriately */
1626 snd_hda_codec_write(codec, 0x05, 0,
1627 AC_VERB_SET_PIN_WIDGET_CONTROL,
1628 spec->cur_eapd ? PIN_OUT : 0);
1629 /* toggle HP mute appropriately */
1630 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1631 HDA_AMP_MUTE,
1632 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
1633 return 1;
1636 /* bind volumes of both NID 0x05 and 0x06 */
1637 static struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1638 .ops = &snd_hda_bind_vol,
1639 .values = {
1640 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1641 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1646 /* mute internal speaker if HP is plugged */
1647 static void ad1981_hp_automute(struct hda_codec *codec)
1649 unsigned int present;
1651 present = snd_hda_jack_detect(codec, 0x06);
1652 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1653 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1656 /* toggle input of built-in and mic jack appropriately */
1657 static void ad1981_hp_automic(struct hda_codec *codec)
1659 static struct hda_verb mic_jack_on[] = {
1660 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1661 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1664 static struct hda_verb mic_jack_off[] = {
1665 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1666 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1669 unsigned int present;
1671 present = snd_hda_jack_detect(codec, 0x08);
1672 if (present)
1673 snd_hda_sequence_write(codec, mic_jack_on);
1674 else
1675 snd_hda_sequence_write(codec, mic_jack_off);
1678 /* unsolicited event for HP jack sensing */
1679 static void ad1981_hp_unsol_event(struct hda_codec *codec,
1680 unsigned int res)
1682 res >>= 26;
1683 switch (res) {
1684 case AD1981_HP_EVENT:
1685 ad1981_hp_automute(codec);
1686 break;
1687 case AD1981_MIC_EVENT:
1688 ad1981_hp_automic(codec);
1689 break;
1693 static struct hda_input_mux ad1981_hp_capture_source = {
1694 .num_items = 3,
1695 .items = {
1696 { "Mic", 0x0 },
1697 { "Docking-Station", 0x1 },
1698 { "Mix", 0x2 },
1702 static struct snd_kcontrol_new ad1981_hp_mixers[] = {
1703 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
1705 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1706 .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
1707 .name = "Master Playback Switch",
1708 .info = ad198x_eapd_info,
1709 .get = ad198x_eapd_get,
1710 .put = ad1981_hp_master_sw_put,
1711 .private_value = 0x05,
1713 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1714 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1715 #if 0
1716 /* FIXME: analog mic/line loopback doesn't work with my tests...
1717 * (although recording is OK)
1719 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1720 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1721 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1722 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1723 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1724 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1725 /* FIXME: does this laptop have analog CD connection? */
1726 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1727 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1728 #endif
1729 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1730 HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
1731 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1732 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1734 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1735 .name = "Capture Source",
1736 .info = ad198x_mux_enum_info,
1737 .get = ad198x_mux_enum_get,
1738 .put = ad198x_mux_enum_put,
1740 { } /* end */
1743 /* initialize jack-sensing, too */
1744 static int ad1981_hp_init(struct hda_codec *codec)
1746 ad198x_init(codec);
1747 ad1981_hp_automute(codec);
1748 ad1981_hp_automic(codec);
1749 return 0;
1752 /* configuration for Toshiba Laptops */
1753 static struct hda_verb ad1981_toshiba_init_verbs[] = {
1754 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
1755 /* pin sensing on HP and Mic jacks */
1756 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1757 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1761 static struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1762 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1763 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1767 /* configuration for Lenovo Thinkpad T60 */
1768 static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1769 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1770 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1771 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1772 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1773 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1774 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1775 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1776 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1777 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1778 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1779 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1781 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1782 .name = "Capture Source",
1783 .info = ad198x_mux_enum_info,
1784 .get = ad198x_mux_enum_get,
1785 .put = ad198x_mux_enum_put,
1787 /* identical with AD1983 */
1789 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1790 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1791 .info = ad1983_spdif_route_info,
1792 .get = ad1983_spdif_route_get,
1793 .put = ad1983_spdif_route_put,
1795 { } /* end */
1798 static struct hda_input_mux ad1981_thinkpad_capture_source = {
1799 .num_items = 3,
1800 .items = {
1801 { "Mic", 0x0 },
1802 { "Mix", 0x2 },
1803 { "CD", 0x4 },
1807 /* models */
1808 enum {
1809 AD1981_BASIC,
1810 AD1981_HP,
1811 AD1981_THINKPAD,
1812 AD1981_TOSHIBA,
1813 AD1981_MODELS
1816 static const char *ad1981_models[AD1981_MODELS] = {
1817 [AD1981_HP] = "hp",
1818 [AD1981_THINKPAD] = "thinkpad",
1819 [AD1981_BASIC] = "basic",
1820 [AD1981_TOSHIBA] = "toshiba"
1823 static struct snd_pci_quirk ad1981_cfg_tbl[] = {
1824 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
1825 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
1826 /* All HP models */
1827 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
1828 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
1829 /* Lenovo Thinkpad T60/X60/Z6xx */
1830 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
1831 /* HP nx6320 (reversed SSID, H/W bug) */
1832 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
1836 static int patch_ad1981(struct hda_codec *codec)
1838 struct ad198x_spec *spec;
1839 int err, board_config;
1841 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1842 if (spec == NULL)
1843 return -ENOMEM;
1845 codec->spec = spec;
1847 err = snd_hda_attach_beep_device(codec, 0x10);
1848 if (err < 0) {
1849 ad198x_free(codec);
1850 return err;
1852 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
1854 spec->multiout.max_channels = 2;
1855 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
1856 spec->multiout.dac_nids = ad1981_dac_nids;
1857 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
1858 spec->num_adc_nids = 1;
1859 spec->adc_nids = ad1981_adc_nids;
1860 spec->capsrc_nids = ad1981_capsrc_nids;
1861 spec->input_mux = &ad1981_capture_source;
1862 spec->num_mixers = 1;
1863 spec->mixers[0] = ad1981_mixers;
1864 spec->num_init_verbs = 1;
1865 spec->init_verbs[0] = ad1981_init_verbs;
1866 spec->spdif_route = 0;
1867 #ifdef CONFIG_SND_HDA_POWER_SAVE
1868 spec->loopback.amplist = ad1981_loopbacks;
1869 #endif
1870 spec->vmaster_nid = 0x05;
1872 codec->patch_ops = ad198x_patch_ops;
1874 /* override some parameters */
1875 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
1876 ad1981_models,
1877 ad1981_cfg_tbl);
1878 switch (board_config) {
1879 case AD1981_HP:
1880 spec->mixers[0] = ad1981_hp_mixers;
1881 spec->num_init_verbs = 2;
1882 spec->init_verbs[1] = ad1981_hp_init_verbs;
1883 spec->multiout.dig_out_nid = 0;
1884 spec->input_mux = &ad1981_hp_capture_source;
1886 codec->patch_ops.init = ad1981_hp_init;
1887 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1888 /* set the upper-limit for mixer amp to 0dB for avoiding the
1889 * possible damage by overloading
1891 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
1892 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1893 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1894 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1895 (1 << AC_AMPCAP_MUTE_SHIFT));
1896 break;
1897 case AD1981_THINKPAD:
1898 spec->mixers[0] = ad1981_thinkpad_mixers;
1899 spec->input_mux = &ad1981_thinkpad_capture_source;
1900 /* set the upper-limit for mixer amp to 0dB for avoiding the
1901 * possible damage by overloading
1903 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
1904 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1905 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1906 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1907 (1 << AC_AMPCAP_MUTE_SHIFT));
1908 break;
1909 case AD1981_TOSHIBA:
1910 spec->mixers[0] = ad1981_hp_mixers;
1911 spec->mixers[1] = ad1981_toshiba_mixers;
1912 spec->num_init_verbs = 2;
1913 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
1914 spec->multiout.dig_out_nid = 0;
1915 spec->input_mux = &ad1981_hp_capture_source;
1916 codec->patch_ops.init = ad1981_hp_init;
1917 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1918 break;
1921 codec->no_trigger_sense = 1;
1922 codec->no_sticky_stream = 1;
1924 return 0;
1929 * AD1988
1931 * Output pins and routes
1933 * Pin Mix Sel DAC (*)
1934 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
1935 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
1936 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
1937 * port-D 0x12 (mute/hp) <- 0x29 <- 04
1938 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
1939 * port-F 0x16 (mute) <- 0x2a <- 06
1940 * port-G 0x24 (mute) <- 0x27 <- 05
1941 * port-H 0x25 (mute) <- 0x28 <- 0a
1942 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
1944 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
1945 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
1947 * Input pins and routes
1949 * pin boost mix input # / adc input #
1950 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
1951 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
1952 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
1953 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
1954 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
1955 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
1956 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
1957 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
1960 * DAC assignment
1961 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
1962 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
1964 * Inputs of Analog Mix (0x20)
1965 * 0:Port-B (front mic)
1966 * 1:Port-C/G/H (line-in)
1967 * 2:Port-A
1968 * 3:Port-D (line-in/2)
1969 * 4:Port-E/G/H (mic-in)
1970 * 5:Port-F (mic2-in)
1971 * 6:CD
1972 * 7:Beep
1974 * ADC selection
1975 * 0:Port-A
1976 * 1:Port-B (front mic-in)
1977 * 2:Port-C (line-in)
1978 * 3:Port-F (mic2-in)
1979 * 4:Port-E (mic-in)
1980 * 5:CD
1981 * 6:Port-G
1982 * 7:Port-H
1983 * 8:Port-D (line-in/2)
1984 * 9:Mix
1986 * Proposed pin assignments by the datasheet
1988 * 6-stack
1989 * Port-A front headphone
1990 * B front mic-in
1991 * C rear line-in
1992 * D rear front-out
1993 * E rear mic-in
1994 * F rear surround
1995 * G rear CLFE
1996 * H rear side
1998 * 3-stack
1999 * Port-A front headphone
2000 * B front mic
2001 * C rear line-in/surround
2002 * D rear front-out
2003 * E rear mic-in/CLFE
2005 * laptop
2006 * Port-A headphone
2007 * B mic-in
2008 * C docking station
2009 * D internal speaker (with EAPD)
2010 * E/F quad mic array
2014 /* models */
2015 enum {
2016 AD1988_6STACK,
2017 AD1988_6STACK_DIG,
2018 AD1988_3STACK,
2019 AD1988_3STACK_DIG,
2020 AD1988_LAPTOP,
2021 AD1988_LAPTOP_DIG,
2022 AD1988_AUTO,
2023 AD1988_MODEL_LAST,
2026 /* reivision id to check workarounds */
2027 #define AD1988A_REV2 0x100200
2029 #define is_rev2(codec) \
2030 ((codec)->vendor_id == 0x11d41988 && \
2031 (codec)->revision_id == AD1988A_REV2)
2034 * mixers
2037 static hda_nid_t ad1988_6stack_dac_nids[4] = {
2038 0x04, 0x06, 0x05, 0x0a
2041 static hda_nid_t ad1988_3stack_dac_nids[3] = {
2042 0x04, 0x05, 0x0a
2045 /* for AD1988A revision-2, DAC2-4 are swapped */
2046 static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
2047 0x04, 0x05, 0x0a, 0x06
2050 static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
2051 0x04, 0x0a, 0x06
2054 static hda_nid_t ad1988_adc_nids[3] = {
2055 0x08, 0x09, 0x0f
2058 static hda_nid_t ad1988_capsrc_nids[3] = {
2059 0x0c, 0x0d, 0x0e
2062 #define AD1988_SPDIF_OUT 0x02
2063 #define AD1988_SPDIF_OUT_HDMI 0x0b
2064 #define AD1988_SPDIF_IN 0x07
2066 static hda_nid_t ad1989b_slave_dig_outs[] = {
2067 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
2070 static struct hda_input_mux ad1988_6stack_capture_source = {
2071 .num_items = 5,
2072 .items = {
2073 { "Front Mic", 0x1 }, /* port-B */
2074 { "Line", 0x2 }, /* port-C */
2075 { "Mic", 0x4 }, /* port-E */
2076 { "CD", 0x5 },
2077 { "Mix", 0x9 },
2081 static struct hda_input_mux ad1988_laptop_capture_source = {
2082 .num_items = 3,
2083 .items = {
2084 { "Mic/Line", 0x1 }, /* port-B */
2085 { "CD", 0x5 },
2086 { "Mix", 0x9 },
2092 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
2093 struct snd_ctl_elem_info *uinfo)
2095 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2096 struct ad198x_spec *spec = codec->spec;
2097 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
2098 spec->num_channel_mode);
2101 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
2102 struct snd_ctl_elem_value *ucontrol)
2104 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2105 struct ad198x_spec *spec = codec->spec;
2106 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
2107 spec->num_channel_mode, spec->multiout.max_channels);
2110 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
2111 struct snd_ctl_elem_value *ucontrol)
2113 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2114 struct ad198x_spec *spec = codec->spec;
2115 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
2116 spec->num_channel_mode,
2117 &spec->multiout.max_channels);
2118 if (err >= 0 && spec->need_dac_fix)
2119 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2120 return err;
2123 /* 6-stack mode */
2124 static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
2125 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2126 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2127 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2128 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2129 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2130 { } /* end */
2133 static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
2134 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2135 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2136 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2137 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2138 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2139 { } /* end */
2142 static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
2143 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2144 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2145 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2146 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2147 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2148 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2149 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2151 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2152 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2153 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2154 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2155 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2156 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2157 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2158 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2160 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2161 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2163 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2164 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2166 { } /* end */
2169 /* 3-stack mode */
2170 static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
2171 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2172 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2173 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2174 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2175 { } /* end */
2178 static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2179 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2180 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2181 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2182 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
2183 { } /* end */
2186 static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
2187 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2188 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2189 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2190 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
2191 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2192 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2194 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2195 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2196 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2197 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2198 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2199 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2200 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2201 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2203 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2204 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2206 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2207 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2209 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2210 .name = "Channel Mode",
2211 .info = ad198x_ch_mode_info,
2212 .get = ad198x_ch_mode_get,
2213 .put = ad198x_ch_mode_put,
2216 { } /* end */
2219 /* laptop mode */
2220 static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2221 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2222 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2223 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2225 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2226 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2227 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2228 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2229 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2230 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2232 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2233 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2235 HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2238 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2239 .name = "External Amplifier",
2240 .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
2241 .info = ad198x_eapd_info,
2242 .get = ad198x_eapd_get,
2243 .put = ad198x_eapd_put,
2244 .private_value = 0x12, /* port-D */
2247 { } /* end */
2250 /* capture */
2251 static struct snd_kcontrol_new ad1988_capture_mixers[] = {
2252 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2253 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2254 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2255 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2256 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2257 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2259 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2260 /* The multiple "Capture Source" controls confuse alsamixer
2261 * So call somewhat different..
2263 /* .name = "Capture Source", */
2264 .name = "Input Source",
2265 .count = 3,
2266 .info = ad198x_mux_enum_info,
2267 .get = ad198x_mux_enum_get,
2268 .put = ad198x_mux_enum_put,
2270 { } /* end */
2273 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2274 struct snd_ctl_elem_info *uinfo)
2276 static char *texts[] = {
2277 "PCM", "ADC1", "ADC2", "ADC3"
2279 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2280 uinfo->count = 1;
2281 uinfo->value.enumerated.items = 4;
2282 if (uinfo->value.enumerated.item >= 4)
2283 uinfo->value.enumerated.item = 3;
2284 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2285 return 0;
2288 static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2289 struct snd_ctl_elem_value *ucontrol)
2291 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2292 unsigned int sel;
2294 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2295 AC_AMP_GET_INPUT);
2296 if (!(sel & 0x80))
2297 ucontrol->value.enumerated.item[0] = 0;
2298 else {
2299 sel = snd_hda_codec_read(codec, 0x0b, 0,
2300 AC_VERB_GET_CONNECT_SEL, 0);
2301 if (sel < 3)
2302 sel++;
2303 else
2304 sel = 0;
2305 ucontrol->value.enumerated.item[0] = sel;
2307 return 0;
2310 static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2311 struct snd_ctl_elem_value *ucontrol)
2313 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2314 unsigned int val, sel;
2315 int change;
2317 val = ucontrol->value.enumerated.item[0];
2318 if (val > 3)
2319 return -EINVAL;
2320 if (!val) {
2321 sel = snd_hda_codec_read(codec, 0x1d, 0,
2322 AC_VERB_GET_AMP_GAIN_MUTE,
2323 AC_AMP_GET_INPUT);
2324 change = sel & 0x80;
2325 if (change) {
2326 snd_hda_codec_write_cache(codec, 0x1d, 0,
2327 AC_VERB_SET_AMP_GAIN_MUTE,
2328 AMP_IN_UNMUTE(0));
2329 snd_hda_codec_write_cache(codec, 0x1d, 0,
2330 AC_VERB_SET_AMP_GAIN_MUTE,
2331 AMP_IN_MUTE(1));
2333 } else {
2334 sel = snd_hda_codec_read(codec, 0x1d, 0,
2335 AC_VERB_GET_AMP_GAIN_MUTE,
2336 AC_AMP_GET_INPUT | 0x01);
2337 change = sel & 0x80;
2338 if (change) {
2339 snd_hda_codec_write_cache(codec, 0x1d, 0,
2340 AC_VERB_SET_AMP_GAIN_MUTE,
2341 AMP_IN_MUTE(0));
2342 snd_hda_codec_write_cache(codec, 0x1d, 0,
2343 AC_VERB_SET_AMP_GAIN_MUTE,
2344 AMP_IN_UNMUTE(1));
2346 sel = snd_hda_codec_read(codec, 0x0b, 0,
2347 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2348 change |= sel != val;
2349 if (change)
2350 snd_hda_codec_write_cache(codec, 0x0b, 0,
2351 AC_VERB_SET_CONNECT_SEL,
2352 val - 1);
2354 return change;
2357 static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2358 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2360 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2361 .name = "IEC958 Playback Source",
2362 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
2363 .info = ad1988_spdif_playback_source_info,
2364 .get = ad1988_spdif_playback_source_get,
2365 .put = ad1988_spdif_playback_source_put,
2367 { } /* end */
2370 static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2371 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2372 { } /* end */
2375 static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2376 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2377 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2378 { } /* end */
2382 * initialization verbs
2386 * for 6-stack (+dig)
2388 static struct hda_verb ad1988_6stack_init_verbs[] = {
2389 /* Front, Surround, CLFE, side DAC; unmute as default */
2390 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2391 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2392 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2393 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2394 /* Port-A front headphon path */
2395 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2396 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2397 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2398 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2399 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2400 /* Port-D line-out path */
2401 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2402 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2403 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2404 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2405 /* Port-F surround path */
2406 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2407 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2408 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2409 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2410 /* Port-G CLFE path */
2411 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2412 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2413 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2414 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2415 /* Port-H side path */
2416 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2417 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2418 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2419 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2420 /* Mono out path */
2421 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2422 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2423 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2424 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2425 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2426 /* Port-B front mic-in path */
2427 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2428 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2429 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2430 /* Port-C line-in path */
2431 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2432 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2433 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2434 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2435 /* Port-E mic-in path */
2436 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2437 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2438 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2439 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2440 /* Analog CD Input */
2441 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2442 /* Analog Mix output amp */
2443 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2448 static struct hda_verb ad1988_capture_init_verbs[] = {
2449 /* mute analog mix */
2450 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2451 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2452 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2453 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2454 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2455 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2456 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2457 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2458 /* select ADCs - front-mic */
2459 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2460 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2461 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2466 static struct hda_verb ad1988_spdif_init_verbs[] = {
2467 /* SPDIF out sel */
2468 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2469 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2470 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2471 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2472 /* SPDIF out pin */
2473 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2478 static struct hda_verb ad1988_spdif_in_init_verbs[] = {
2479 /* unmute SPDIF input pin */
2480 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2484 /* AD1989 has no ADC -> SPDIF route */
2485 static struct hda_verb ad1989_spdif_init_verbs[] = {
2486 /* SPDIF-1 out pin */
2487 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2488 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2489 /* SPDIF-2/HDMI out pin */
2490 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2491 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2496 * verbs for 3stack (+dig)
2498 static struct hda_verb ad1988_3stack_ch2_init[] = {
2499 /* set port-C to line-in */
2500 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2501 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2502 /* set port-E to mic-in */
2503 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2504 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2505 { } /* end */
2508 static struct hda_verb ad1988_3stack_ch6_init[] = {
2509 /* set port-C to surround out */
2510 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2511 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2512 /* set port-E to CLFE out */
2513 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2514 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2515 { } /* end */
2518 static struct hda_channel_mode ad1988_3stack_modes[2] = {
2519 { 2, ad1988_3stack_ch2_init },
2520 { 6, ad1988_3stack_ch6_init },
2523 static struct hda_verb ad1988_3stack_init_verbs[] = {
2524 /* Front, Surround, CLFE, side DAC; unmute as default */
2525 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2526 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2527 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2528 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2529 /* Port-A front headphon path */
2530 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2531 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2532 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2533 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2534 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2535 /* Port-D line-out path */
2536 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2537 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2538 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2539 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2540 /* Mono out path */
2541 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2542 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2543 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2544 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2545 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2546 /* Port-B front mic-in path */
2547 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2548 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2549 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2550 /* Port-C line-in/surround path - 6ch mode as default */
2551 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2552 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2553 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2554 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
2555 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2556 /* Port-E mic-in/CLFE path - 6ch mode as default */
2557 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2558 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2559 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2560 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
2561 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2562 /* mute analog mix */
2563 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2564 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2565 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2566 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2567 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2568 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2569 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2570 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2571 /* select ADCs - front-mic */
2572 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2573 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2574 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2575 /* Analog Mix output amp */
2576 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2581 * verbs for laptop mode (+dig)
2583 static struct hda_verb ad1988_laptop_hp_on[] = {
2584 /* unmute port-A and mute port-D */
2585 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2586 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2587 { } /* end */
2589 static struct hda_verb ad1988_laptop_hp_off[] = {
2590 /* mute port-A and unmute port-D */
2591 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2592 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2593 { } /* end */
2596 #define AD1988_HP_EVENT 0x01
2598 static struct hda_verb ad1988_laptop_init_verbs[] = {
2599 /* Front, Surround, CLFE, side DAC; unmute as default */
2600 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2601 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2602 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2603 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2604 /* Port-A front headphon path */
2605 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2606 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2607 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2608 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2609 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2610 /* unsolicited event for pin-sense */
2611 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2612 /* Port-D line-out path + EAPD */
2613 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2614 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2615 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2616 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2617 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
2618 /* Mono out path */
2619 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2620 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2621 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2622 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2623 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2624 /* Port-B mic-in path */
2625 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2626 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2627 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2628 /* Port-C docking station - try to output */
2629 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2630 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2631 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2632 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2633 /* mute analog mix */
2634 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2635 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2636 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2637 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2638 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2639 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2640 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2641 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2642 /* select ADCs - mic */
2643 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2644 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2645 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2646 /* Analog Mix output amp */
2647 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2651 static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2653 if ((res >> 26) != AD1988_HP_EVENT)
2654 return;
2655 if (snd_hda_jack_detect(codec, 0x11))
2656 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2657 else
2658 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2661 #ifdef CONFIG_SND_HDA_POWER_SAVE
2662 static struct hda_amp_list ad1988_loopbacks[] = {
2663 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2664 { 0x20, HDA_INPUT, 1 }, /* Line */
2665 { 0x20, HDA_INPUT, 4 }, /* Mic */
2666 { 0x20, HDA_INPUT, 6 }, /* CD */
2667 { } /* end */
2669 #endif
2672 * Automatic parse of I/O pins from the BIOS configuration
2675 enum {
2676 AD_CTL_WIDGET_VOL,
2677 AD_CTL_WIDGET_MUTE,
2678 AD_CTL_BIND_MUTE,
2680 static struct snd_kcontrol_new ad1988_control_templates[] = {
2681 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2682 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2683 HDA_BIND_MUTE(NULL, 0, 0, 0),
2686 /* add dynamic controls */
2687 static int add_control(struct ad198x_spec *spec, int type, const char *name,
2688 unsigned long val)
2690 struct snd_kcontrol_new *knew;
2692 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2693 knew = snd_array_new(&spec->kctls);
2694 if (!knew)
2695 return -ENOMEM;
2696 *knew = ad1988_control_templates[type];
2697 knew->name = kstrdup(name, GFP_KERNEL);
2698 if (! knew->name)
2699 return -ENOMEM;
2700 if (get_amp_nid_(val))
2701 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2702 knew->private_value = val;
2703 return 0;
2706 #define AD1988_PIN_CD_NID 0x18
2707 #define AD1988_PIN_BEEP_NID 0x10
2709 static hda_nid_t ad1988_mixer_nids[8] = {
2710 /* A B C D E F G H */
2711 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
2714 static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
2716 static hda_nid_t idx_to_dac[8] = {
2717 /* A B C D E F G H */
2718 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
2720 static hda_nid_t idx_to_dac_rev2[8] = {
2721 /* A B C D E F G H */
2722 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
2724 if (is_rev2(codec))
2725 return idx_to_dac_rev2[idx];
2726 else
2727 return idx_to_dac[idx];
2730 static hda_nid_t ad1988_boost_nids[8] = {
2731 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
2734 static int ad1988_pin_idx(hda_nid_t nid)
2736 static hda_nid_t ad1988_io_pins[8] = {
2737 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
2739 int i;
2740 for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)
2741 if (ad1988_io_pins[i] == nid)
2742 return i;
2743 return 0; /* should be -1 */
2746 static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
2748 static int loopback_idx[8] = {
2749 2, 0, 1, 3, 4, 5, 1, 4
2751 switch (nid) {
2752 case AD1988_PIN_CD_NID:
2753 return 6;
2754 default:
2755 return loopback_idx[ad1988_pin_idx(nid)];
2759 static int ad1988_pin_to_adc_idx(hda_nid_t nid)
2761 static int adc_idx[8] = {
2762 0, 1, 2, 8, 4, 3, 6, 7
2764 switch (nid) {
2765 case AD1988_PIN_CD_NID:
2766 return 5;
2767 default:
2768 return adc_idx[ad1988_pin_idx(nid)];
2772 /* fill in the dac_nids table from the parsed pin configuration */
2773 static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
2774 const struct auto_pin_cfg *cfg)
2776 struct ad198x_spec *spec = codec->spec;
2777 int i, idx;
2779 spec->multiout.dac_nids = spec->private_dac_nids;
2781 /* check the pins hardwired to audio widget */
2782 for (i = 0; i < cfg->line_outs; i++) {
2783 idx = ad1988_pin_idx(cfg->line_out_pins[i]);
2784 spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx);
2786 spec->multiout.num_dacs = cfg->line_outs;
2787 return 0;
2790 /* add playback controls from the parsed DAC table */
2791 static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
2792 const struct auto_pin_cfg *cfg)
2794 char name[32];
2795 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
2796 hda_nid_t nid;
2797 int i, err;
2799 for (i = 0; i < cfg->line_outs; i++) {
2800 hda_nid_t dac = spec->multiout.dac_nids[i];
2801 if (! dac)
2802 continue;
2803 nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];
2804 if (i == 2) {
2805 /* Center/LFE */
2806 err = add_control(spec, AD_CTL_WIDGET_VOL,
2807 "Center Playback Volume",
2808 HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));
2809 if (err < 0)
2810 return err;
2811 err = add_control(spec, AD_CTL_WIDGET_VOL,
2812 "LFE Playback Volume",
2813 HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));
2814 if (err < 0)
2815 return err;
2816 err = add_control(spec, AD_CTL_BIND_MUTE,
2817 "Center Playback Switch",
2818 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
2819 if (err < 0)
2820 return err;
2821 err = add_control(spec, AD_CTL_BIND_MUTE,
2822 "LFE Playback Switch",
2823 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
2824 if (err < 0)
2825 return err;
2826 } else {
2827 sprintf(name, "%s Playback Volume", chname[i]);
2828 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2829 HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));
2830 if (err < 0)
2831 return err;
2832 sprintf(name, "%s Playback Switch", chname[i]);
2833 err = add_control(spec, AD_CTL_BIND_MUTE, name,
2834 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
2835 if (err < 0)
2836 return err;
2839 return 0;
2842 /* add playback controls for speaker and HP outputs */
2843 static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
2844 const char *pfx)
2846 struct ad198x_spec *spec = codec->spec;
2847 hda_nid_t nid;
2848 int i, idx, err;
2849 char name[32];
2851 if (! pin)
2852 return 0;
2854 idx = ad1988_pin_idx(pin);
2855 nid = ad1988_idx_to_dac(codec, idx);
2856 /* check whether the corresponding DAC was already taken */
2857 for (i = 0; i < spec->autocfg.line_outs; i++) {
2858 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2859 hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
2860 if (dac == nid)
2861 break;
2863 if (i >= spec->autocfg.line_outs) {
2864 /* specify the DAC as the extra output */
2865 if (!spec->multiout.hp_nid)
2866 spec->multiout.hp_nid = nid;
2867 else
2868 spec->multiout.extra_out_nid[0] = nid;
2869 /* control HP volume/switch on the output mixer amp */
2870 sprintf(name, "%s Playback Volume", pfx);
2871 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2872 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2873 if (err < 0)
2874 return err;
2876 nid = ad1988_mixer_nids[idx];
2877 sprintf(name, "%s Playback Switch", pfx);
2878 if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
2879 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2880 return err;
2881 return 0;
2884 /* create input playback/capture controls for the given pin */
2885 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
2886 const char *ctlname, int ctlidx, int boost)
2888 char name[32];
2889 int err, idx;
2891 sprintf(name, "%s Playback Volume", ctlname);
2892 idx = ad1988_pin_to_loopback_idx(pin);
2893 if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2894 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2895 return err;
2896 sprintf(name, "%s Playback Switch", ctlname);
2897 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,
2898 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2899 return err;
2900 if (boost) {
2901 hda_nid_t bnid;
2902 idx = ad1988_pin_idx(pin);
2903 bnid = ad1988_boost_nids[idx];
2904 if (bnid) {
2905 sprintf(name, "%s Boost", ctlname);
2906 return add_control(spec, AD_CTL_WIDGET_VOL, name,
2907 HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
2911 return 0;
2914 /* create playback/capture controls for input pins */
2915 static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
2916 const struct auto_pin_cfg *cfg)
2918 struct ad198x_spec *spec = codec->spec;
2919 struct hda_input_mux *imux = &spec->private_imux;
2920 int i, err, type, type_idx;
2922 for (i = 0; i < cfg->num_inputs; i++) {
2923 const char *label;
2924 type = cfg->inputs[i].type;
2925 label = hda_get_autocfg_input_label(codec, cfg, i);
2926 snd_hda_add_imux_item(imux, label,
2927 ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
2928 &type_idx);
2929 err = new_analog_input(spec, cfg->inputs[i].pin,
2930 label, type_idx,
2931 type == AUTO_PIN_MIC);
2932 if (err < 0)
2933 return err;
2935 snd_hda_add_imux_item(imux, "Mix", 9, NULL);
2937 if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
2938 "Analog Mix Playback Volume",
2939 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2940 return err;
2941 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,
2942 "Analog Mix Playback Switch",
2943 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2944 return err;
2946 return 0;
2949 static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
2950 hda_nid_t nid, int pin_type,
2951 int dac_idx)
2953 /* set as output */
2954 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2955 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2956 switch (nid) {
2957 case 0x11: /* port-A - DAC 04 */
2958 snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2959 break;
2960 case 0x14: /* port-B - DAC 06 */
2961 snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
2962 break;
2963 case 0x15: /* port-C - DAC 05 */
2964 snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
2965 break;
2966 case 0x17: /* port-E - DAC 0a */
2967 snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2968 break;
2969 case 0x13: /* mono - DAC 04 */
2970 snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2971 break;
2975 static void ad1988_auto_init_multi_out(struct hda_codec *codec)
2977 struct ad198x_spec *spec = codec->spec;
2978 int i;
2980 for (i = 0; i < spec->autocfg.line_outs; i++) {
2981 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2982 ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
2986 static void ad1988_auto_init_extra_out(struct hda_codec *codec)
2988 struct ad198x_spec *spec = codec->spec;
2989 hda_nid_t pin;
2991 pin = spec->autocfg.speaker_pins[0];
2992 if (pin) /* connect to front */
2993 ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
2994 pin = spec->autocfg.hp_pins[0];
2995 if (pin) /* connect to front */
2996 ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
2999 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
3001 struct ad198x_spec *spec = codec->spec;
3002 const struct auto_pin_cfg *cfg = &spec->autocfg;
3003 int i, idx;
3005 for (i = 0; i < cfg->num_inputs; i++) {
3006 hda_nid_t nid = cfg->inputs[i].pin;
3007 switch (nid) {
3008 case 0x15: /* port-C */
3009 snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3010 break;
3011 case 0x17: /* port-E */
3012 snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3013 break;
3015 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3016 i == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
3017 if (nid != AD1988_PIN_CD_NID)
3018 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3019 AMP_OUT_MUTE);
3020 idx = ad1988_pin_idx(nid);
3021 if (ad1988_boost_nids[idx])
3022 snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,
3023 AC_VERB_SET_AMP_GAIN_MUTE,
3024 AMP_OUT_ZERO);
3028 /* parse the BIOS configuration and set up the alc_spec */
3029 /* return 1 if successful, 0 if the proper config is not found, or a negative error code */
3030 static int ad1988_parse_auto_config(struct hda_codec *codec)
3032 struct ad198x_spec *spec = codec->spec;
3033 int err;
3035 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
3036 return err;
3037 if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3038 return err;
3039 if (! spec->autocfg.line_outs)
3040 return 0; /* can't find valid BIOS pin config */
3041 if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
3042 (err = ad1988_auto_create_extra_out(codec,
3043 spec->autocfg.speaker_pins[0],
3044 "Speaker")) < 0 ||
3045 (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
3046 "Headphone")) < 0 ||
3047 (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3048 return err;
3050 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3052 if (spec->autocfg.dig_outs)
3053 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3054 if (spec->autocfg.dig_in_pin)
3055 spec->dig_in_nid = AD1988_SPDIF_IN;
3057 if (spec->kctls.list)
3058 spec->mixers[spec->num_mixers++] = spec->kctls.list;
3060 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
3062 spec->input_mux = &spec->private_imux;
3064 return 1;
3067 /* init callback for auto-configuration model -- overriding the default init */
3068 static int ad1988_auto_init(struct hda_codec *codec)
3070 ad198x_init(codec);
3071 ad1988_auto_init_multi_out(codec);
3072 ad1988_auto_init_extra_out(codec);
3073 ad1988_auto_init_analog_input(codec);
3074 return 0;
3081 static const char *ad1988_models[AD1988_MODEL_LAST] = {
3082 [AD1988_6STACK] = "6stack",
3083 [AD1988_6STACK_DIG] = "6stack-dig",
3084 [AD1988_3STACK] = "3stack",
3085 [AD1988_3STACK_DIG] = "3stack-dig",
3086 [AD1988_LAPTOP] = "laptop",
3087 [AD1988_LAPTOP_DIG] = "laptop-dig",
3088 [AD1988_AUTO] = "auto",
3091 static struct snd_pci_quirk ad1988_cfg_tbl[] = {
3092 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
3093 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
3094 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
3095 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
3099 static int patch_ad1988(struct hda_codec *codec)
3101 struct ad198x_spec *spec;
3102 int err, board_config;
3104 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3105 if (spec == NULL)
3106 return -ENOMEM;
3108 codec->spec = spec;
3110 if (is_rev2(codec))
3111 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
3113 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
3114 ad1988_models, ad1988_cfg_tbl);
3115 if (board_config < 0) {
3116 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3117 codec->chip_name);
3118 board_config = AD1988_AUTO;
3121 if (board_config == AD1988_AUTO) {
3122 /* automatic parse from the BIOS config */
3123 err = ad1988_parse_auto_config(codec);
3124 if (err < 0) {
3125 ad198x_free(codec);
3126 return err;
3127 } else if (! err) {
3128 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n");
3129 board_config = AD1988_6STACK;
3133 err = snd_hda_attach_beep_device(codec, 0x10);
3134 if (err < 0) {
3135 ad198x_free(codec);
3136 return err;
3138 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3140 switch (board_config) {
3141 case AD1988_6STACK:
3142 case AD1988_6STACK_DIG:
3143 spec->multiout.max_channels = 8;
3144 spec->multiout.num_dacs = 4;
3145 if (is_rev2(codec))
3146 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3147 else
3148 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
3149 spec->input_mux = &ad1988_6stack_capture_source;
3150 spec->num_mixers = 2;
3151 if (is_rev2(codec))
3152 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3153 else
3154 spec->mixers[0] = ad1988_6stack_mixers1;
3155 spec->mixers[1] = ad1988_6stack_mixers2;
3156 spec->num_init_verbs = 1;
3157 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3158 if (board_config == AD1988_6STACK_DIG) {
3159 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3160 spec->dig_in_nid = AD1988_SPDIF_IN;
3162 break;
3163 case AD1988_3STACK:
3164 case AD1988_3STACK_DIG:
3165 spec->multiout.max_channels = 6;
3166 spec->multiout.num_dacs = 3;
3167 if (is_rev2(codec))
3168 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3169 else
3170 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3171 spec->input_mux = &ad1988_6stack_capture_source;
3172 spec->channel_mode = ad1988_3stack_modes;
3173 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
3174 spec->num_mixers = 2;
3175 if (is_rev2(codec))
3176 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3177 else
3178 spec->mixers[0] = ad1988_3stack_mixers1;
3179 spec->mixers[1] = ad1988_3stack_mixers2;
3180 spec->num_init_verbs = 1;
3181 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3182 if (board_config == AD1988_3STACK_DIG)
3183 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3184 break;
3185 case AD1988_LAPTOP:
3186 case AD1988_LAPTOP_DIG:
3187 spec->multiout.max_channels = 2;
3188 spec->multiout.num_dacs = 1;
3189 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3190 spec->input_mux = &ad1988_laptop_capture_source;
3191 spec->num_mixers = 1;
3192 spec->mixers[0] = ad1988_laptop_mixers;
3193 spec->inv_eapd = 1; /* inverted EAPD */
3194 spec->num_init_verbs = 1;
3195 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3196 if (board_config == AD1988_LAPTOP_DIG)
3197 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3198 break;
3201 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3202 spec->adc_nids = ad1988_adc_nids;
3203 spec->capsrc_nids = ad1988_capsrc_nids;
3204 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3205 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3206 if (spec->multiout.dig_out_nid) {
3207 if (codec->vendor_id >= 0x11d4989a) {
3208 spec->mixers[spec->num_mixers++] =
3209 ad1989_spdif_out_mixers;
3210 spec->init_verbs[spec->num_init_verbs++] =
3211 ad1989_spdif_init_verbs;
3212 codec->slave_dig_outs = ad1989b_slave_dig_outs;
3213 } else {
3214 spec->mixers[spec->num_mixers++] =
3215 ad1988_spdif_out_mixers;
3216 spec->init_verbs[spec->num_init_verbs++] =
3217 ad1988_spdif_init_verbs;
3220 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
3221 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
3222 spec->init_verbs[spec->num_init_verbs++] =
3223 ad1988_spdif_in_init_verbs;
3226 codec->patch_ops = ad198x_patch_ops;
3227 switch (board_config) {
3228 case AD1988_AUTO:
3229 codec->patch_ops.init = ad1988_auto_init;
3230 break;
3231 case AD1988_LAPTOP:
3232 case AD1988_LAPTOP_DIG:
3233 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3234 break;
3236 #ifdef CONFIG_SND_HDA_POWER_SAVE
3237 spec->loopback.amplist = ad1988_loopbacks;
3238 #endif
3239 spec->vmaster_nid = 0x04;
3241 codec->no_trigger_sense = 1;
3242 codec->no_sticky_stream = 1;
3244 return 0;
3249 * AD1884 / AD1984
3251 * port-B - front line/mic-in
3252 * port-E - aux in/out
3253 * port-F - aux in/out
3254 * port-C - rear line/mic-in
3255 * port-D - rear line/hp-out
3256 * port-A - front line/hp-out
3258 * AD1984 = AD1884 + two digital mic-ins
3260 * FIXME:
3261 * For simplicity, we share the single DAC for both HP and line-outs
3262 * right now. The inidividual playbacks could be easily implemented,
3263 * but no build-up framework is given, so far.
3266 static hda_nid_t ad1884_dac_nids[1] = {
3267 0x04,
3270 static hda_nid_t ad1884_adc_nids[2] = {
3271 0x08, 0x09,
3274 static hda_nid_t ad1884_capsrc_nids[2] = {
3275 0x0c, 0x0d,
3278 #define AD1884_SPDIF_OUT 0x02
3280 static struct hda_input_mux ad1884_capture_source = {
3281 .num_items = 4,
3282 .items = {
3283 { "Front Mic", 0x0 },
3284 { "Mic", 0x1 },
3285 { "CD", 0x2 },
3286 { "Mix", 0x3 },
3290 static struct snd_kcontrol_new ad1884_base_mixers[] = {
3291 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3292 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3293 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3294 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3295 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3296 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3297 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3298 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3299 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3300 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3301 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3302 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3303 HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
3304 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3305 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3306 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3307 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3308 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3310 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3311 /* The multiple "Capture Source" controls confuse alsamixer
3312 * So call somewhat different..
3314 /* .name = "Capture Source", */
3315 .name = "Input Source",
3316 .count = 2,
3317 .info = ad198x_mux_enum_info,
3318 .get = ad198x_mux_enum_get,
3319 .put = ad198x_mux_enum_put,
3321 /* SPDIF controls */
3322 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3324 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3325 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3326 /* identical with ad1983 */
3327 .info = ad1983_spdif_route_info,
3328 .get = ad1983_spdif_route_get,
3329 .put = ad1983_spdif_route_put,
3331 { } /* end */
3334 static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3335 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3336 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3337 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
3338 HDA_INPUT),
3339 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
3340 HDA_INPUT),
3341 { } /* end */
3345 * initialization verbs
3347 static struct hda_verb ad1884_init_verbs[] = {
3348 /* DACs; mute as default */
3349 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3350 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3351 /* Port-A (HP) mixer */
3352 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3353 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3354 /* Port-A pin */
3355 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3356 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3357 /* HP selector - select DAC2 */
3358 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3359 /* Port-D (Line-out) mixer */
3360 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3361 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3362 /* Port-D pin */
3363 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3364 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3365 /* Mono-out mixer */
3366 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3367 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3368 /* Mono-out pin */
3369 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3370 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3371 /* Mono selector */
3372 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3373 /* Port-B (front mic) pin */
3374 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3375 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3376 /* Port-C (rear mic) pin */
3377 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3378 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3379 /* Analog mixer; mute as default */
3380 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3381 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3382 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3383 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3384 /* Analog Mix output amp */
3385 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3386 /* SPDIF output selector */
3387 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3388 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3389 { } /* end */
3392 #ifdef CONFIG_SND_HDA_POWER_SAVE
3393 static struct hda_amp_list ad1884_loopbacks[] = {
3394 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3395 { 0x20, HDA_INPUT, 1 }, /* Mic */
3396 { 0x20, HDA_INPUT, 2 }, /* CD */
3397 { 0x20, HDA_INPUT, 4 }, /* Docking */
3398 { } /* end */
3400 #endif
3402 static const char *ad1884_slave_vols[] = {
3403 "PCM Playback Volume",
3404 "Mic Playback Volume",
3405 "Mono Playback Volume",
3406 "Front Mic Playback Volume",
3407 "Mic Playback Volume",
3408 "CD Playback Volume",
3409 "Internal Mic Playback Volume",
3410 "Docking Mic Playback Volume",
3411 /* "Beep Playback Volume", */
3412 "IEC958 Playback Volume",
3413 NULL
3416 static int patch_ad1884(struct hda_codec *codec)
3418 struct ad198x_spec *spec;
3419 int err;
3421 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3422 if (spec == NULL)
3423 return -ENOMEM;
3425 codec->spec = spec;
3427 err = snd_hda_attach_beep_device(codec, 0x10);
3428 if (err < 0) {
3429 ad198x_free(codec);
3430 return err;
3432 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3434 spec->multiout.max_channels = 2;
3435 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3436 spec->multiout.dac_nids = ad1884_dac_nids;
3437 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3438 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3439 spec->adc_nids = ad1884_adc_nids;
3440 spec->capsrc_nids = ad1884_capsrc_nids;
3441 spec->input_mux = &ad1884_capture_source;
3442 spec->num_mixers = 1;
3443 spec->mixers[0] = ad1884_base_mixers;
3444 spec->num_init_verbs = 1;
3445 spec->init_verbs[0] = ad1884_init_verbs;
3446 spec->spdif_route = 0;
3447 #ifdef CONFIG_SND_HDA_POWER_SAVE
3448 spec->loopback.amplist = ad1884_loopbacks;
3449 #endif
3450 spec->vmaster_nid = 0x04;
3451 /* we need to cover all playback volumes */
3452 spec->slave_vols = ad1884_slave_vols;
3454 codec->patch_ops = ad198x_patch_ops;
3456 codec->no_trigger_sense = 1;
3457 codec->no_sticky_stream = 1;
3459 return 0;
3463 * Lenovo Thinkpad T61/X61
3465 static struct hda_input_mux ad1984_thinkpad_capture_source = {
3466 .num_items = 4,
3467 .items = {
3468 { "Mic", 0x0 },
3469 { "Internal Mic", 0x1 },
3470 { "Mix", 0x3 },
3471 { "Docking-Station", 0x4 },
3477 * Dell Precision T3400
3479 static struct hda_input_mux ad1984_dell_desktop_capture_source = {
3480 .num_items = 3,
3481 .items = {
3482 { "Front Mic", 0x0 },
3483 { "Line-In", 0x1 },
3484 { "Mix", 0x3 },
3489 static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3490 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3491 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3492 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3493 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3494 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3495 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3496 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3497 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3498 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3499 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3500 HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3501 HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3502 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3503 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
3504 HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3505 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3506 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3507 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3508 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3510 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3511 /* The multiple "Capture Source" controls confuse alsamixer
3512 * So call somewhat different..
3514 /* .name = "Capture Source", */
3515 .name = "Input Source",
3516 .count = 2,
3517 .info = ad198x_mux_enum_info,
3518 .get = ad198x_mux_enum_get,
3519 .put = ad198x_mux_enum_put,
3521 /* SPDIF controls */
3522 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3524 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3525 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3526 /* identical with ad1983 */
3527 .info = ad1983_spdif_route_info,
3528 .get = ad1983_spdif_route_get,
3529 .put = ad1983_spdif_route_put,
3531 { } /* end */
3534 /* additional verbs */
3535 static struct hda_verb ad1984_thinkpad_init_verbs[] = {
3536 /* Port-E (docking station mic) pin */
3537 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3538 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3539 /* docking mic boost */
3540 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3541 /* Analog PC Beeper - allow firmware/ACPI beeps */
3542 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
3543 /* Analog mixer - docking mic; mute as default */
3544 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3545 /* enable EAPD bit */
3546 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3547 { } /* end */
3551 * Dell Precision T3400
3553 static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3554 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3555 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3556 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3557 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3558 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3559 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3560 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3561 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3562 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
3563 HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
3564 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3565 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3566 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3567 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3568 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3570 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3571 /* The multiple "Capture Source" controls confuse alsamixer
3572 * So call somewhat different..
3574 /* .name = "Capture Source", */
3575 .name = "Input Source",
3576 .count = 2,
3577 .info = ad198x_mux_enum_info,
3578 .get = ad198x_mux_enum_get,
3579 .put = ad198x_mux_enum_put,
3581 { } /* end */
3584 /* Digial MIC ADC NID 0x05 + 0x06 */
3585 static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3586 struct hda_codec *codec,
3587 unsigned int stream_tag,
3588 unsigned int format,
3589 struct snd_pcm_substream *substream)
3591 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3592 stream_tag, 0, format);
3593 return 0;
3596 static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3597 struct hda_codec *codec,
3598 struct snd_pcm_substream *substream)
3600 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
3601 return 0;
3604 static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3605 .substreams = 2,
3606 .channels_min = 2,
3607 .channels_max = 2,
3608 .nid = 0x05,
3609 .ops = {
3610 .prepare = ad1984_pcm_dmic_prepare,
3611 .cleanup = ad1984_pcm_dmic_cleanup
3615 static int ad1984_build_pcms(struct hda_codec *codec)
3617 struct ad198x_spec *spec = codec->spec;
3618 struct hda_pcm *info;
3619 int err;
3621 err = ad198x_build_pcms(codec);
3622 if (err < 0)
3623 return err;
3625 info = spec->pcm_rec + codec->num_pcms;
3626 codec->num_pcms++;
3627 info->name = "AD1984 Digital Mic";
3628 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3629 return 0;
3632 /* models */
3633 enum {
3634 AD1984_BASIC,
3635 AD1984_THINKPAD,
3636 AD1984_DELL_DESKTOP,
3637 AD1984_MODELS
3640 static const char *ad1984_models[AD1984_MODELS] = {
3641 [AD1984_BASIC] = "basic",
3642 [AD1984_THINKPAD] = "thinkpad",
3643 [AD1984_DELL_DESKTOP] = "dell_desktop",
3646 static struct snd_pci_quirk ad1984_cfg_tbl[] = {
3647 /* Lenovo Thinkpad T61/X61 */
3648 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
3649 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
3650 SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
3654 static int patch_ad1984(struct hda_codec *codec)
3656 struct ad198x_spec *spec;
3657 int board_config, err;
3659 err = patch_ad1884(codec);
3660 if (err < 0)
3661 return err;
3662 spec = codec->spec;
3663 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3664 ad1984_models, ad1984_cfg_tbl);
3665 switch (board_config) {
3666 case AD1984_BASIC:
3667 /* additional digital mics */
3668 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3669 codec->patch_ops.build_pcms = ad1984_build_pcms;
3670 break;
3671 case AD1984_THINKPAD:
3672 if (codec->subsystem_id == 0x17aa20fb) {
3673 /* Thinpad X300 does not have the ability to do SPDIF,
3674 or attach to docking station to use SPDIF */
3675 spec->multiout.dig_out_nid = 0;
3676 } else
3677 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3678 spec->input_mux = &ad1984_thinkpad_capture_source;
3679 spec->mixers[0] = ad1984_thinkpad_mixers;
3680 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
3681 spec->analog_beep = 1;
3682 break;
3683 case AD1984_DELL_DESKTOP:
3684 spec->multiout.dig_out_nid = 0;
3685 spec->input_mux = &ad1984_dell_desktop_capture_source;
3686 spec->mixers[0] = ad1984_dell_desktop_mixers;
3687 break;
3689 return 0;
3694 * AD1883 / AD1884A / AD1984A / AD1984B
3696 * port-B (0x14) - front mic-in
3697 * port-E (0x1c) - rear mic-in
3698 * port-F (0x16) - CD / ext out
3699 * port-C (0x15) - rear line-in
3700 * port-D (0x12) - rear line-out
3701 * port-A (0x11) - front hp-out
3703 * AD1984A = AD1884A + digital-mic
3704 * AD1883 = equivalent with AD1984A
3705 * AD1984B = AD1984A + extra SPDIF-out
3707 * FIXME:
3708 * We share the single DAC for both HP and line-outs (see AD1884/1984).
3711 static hda_nid_t ad1884a_dac_nids[1] = {
3712 0x03,
3715 #define ad1884a_adc_nids ad1884_adc_nids
3716 #define ad1884a_capsrc_nids ad1884_capsrc_nids
3718 #define AD1884A_SPDIF_OUT 0x02
3720 static struct hda_input_mux ad1884a_capture_source = {
3721 .num_items = 5,
3722 .items = {
3723 { "Front Mic", 0x0 },
3724 { "Mic", 0x4 },
3725 { "Line", 0x1 },
3726 { "CD", 0x2 },
3727 { "Mix", 0x3 },
3731 static struct snd_kcontrol_new ad1884a_base_mixers[] = {
3732 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3733 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3734 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3735 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3736 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3737 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3738 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3739 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3740 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3741 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3742 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3743 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3744 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3745 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3746 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3747 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3748 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3749 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
3750 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3751 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3752 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3753 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3754 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3756 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3757 /* The multiple "Capture Source" controls confuse alsamixer
3758 * So call somewhat different..
3760 /* .name = "Capture Source", */
3761 .name = "Input Source",
3762 .count = 2,
3763 .info = ad198x_mux_enum_info,
3764 .get = ad198x_mux_enum_get,
3765 .put = ad198x_mux_enum_put,
3767 /* SPDIF controls */
3768 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3770 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3771 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3772 /* identical with ad1983 */
3773 .info = ad1983_spdif_route_info,
3774 .get = ad1983_spdif_route_get,
3775 .put = ad1983_spdif_route_put,
3777 { } /* end */
3781 * initialization verbs
3783 static struct hda_verb ad1884a_init_verbs[] = {
3784 /* DACs; unmute as default */
3785 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3786 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3787 /* Port-A (HP) mixer - route only from analog mixer */
3788 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3789 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3790 /* Port-A pin */
3791 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3792 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3793 /* Port-D (Line-out) mixer - route only from analog mixer */
3794 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3795 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3796 /* Port-D pin */
3797 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3798 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3799 /* Mono-out mixer - route only from analog mixer */
3800 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3801 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3802 /* Mono-out pin */
3803 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3804 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3805 /* Port-B (front mic) pin */
3806 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3807 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3808 /* Port-C (rear line-in) pin */
3809 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3810 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3811 /* Port-E (rear mic) pin */
3812 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3813 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3814 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
3815 /* Port-F (CD) pin */
3816 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3817 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3818 /* Analog mixer; mute as default */
3819 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3820 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3821 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3822 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3823 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
3824 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3825 /* Analog Mix output amp */
3826 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3827 /* capture sources */
3828 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
3829 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3830 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
3831 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3832 /* SPDIF output amp */
3833 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3834 { } /* end */
3837 #ifdef CONFIG_SND_HDA_POWER_SAVE
3838 static struct hda_amp_list ad1884a_loopbacks[] = {
3839 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3840 { 0x20, HDA_INPUT, 1 }, /* Mic */
3841 { 0x20, HDA_INPUT, 2 }, /* CD */
3842 { 0x20, HDA_INPUT, 4 }, /* Docking */
3843 { } /* end */
3845 #endif
3848 * Laptop model
3850 * Port A: Headphone jack
3851 * Port B: MIC jack
3852 * Port C: Internal MIC
3853 * Port D: Dock Line Out (if enabled)
3854 * Port E: Dock Line In (if enabled)
3855 * Port F: Internal speakers
3858 static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
3859 struct snd_ctl_elem_value *ucontrol)
3861 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3862 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3863 int mute = (!ucontrol->value.integer.value[0] &&
3864 !ucontrol->value.integer.value[1]);
3865 /* toggle GPIO1 according to the mute state */
3866 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
3867 mute ? 0x02 : 0x0);
3868 return ret;
3871 static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
3872 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3874 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3875 .name = "Master Playback Switch",
3876 .subdevice = HDA_SUBDEV_AMP_FLAG,
3877 .info = snd_hda_mixer_amp_switch_info,
3878 .get = snd_hda_mixer_amp_switch_get,
3879 .put = ad1884a_mobile_master_sw_put,
3880 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3882 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3883 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3884 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3885 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3886 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3887 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3888 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3889 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3890 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3891 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3892 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
3893 HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3894 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3895 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3896 { } /* end */
3899 static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
3900 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3901 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
3903 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3904 .name = "Master Playback Switch",
3905 .subdevice = HDA_SUBDEV_AMP_FLAG,
3906 .info = snd_hda_mixer_amp_switch_info,
3907 .get = snd_hda_mixer_amp_switch_get,
3908 .put = ad1884a_mobile_master_sw_put,
3909 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3911 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3912 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3913 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
3914 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
3915 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3916 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3917 { } /* end */
3920 /* mute internal speaker if HP is plugged */
3921 static void ad1884a_hp_automute(struct hda_codec *codec)
3923 unsigned int present;
3925 present = snd_hda_jack_detect(codec, 0x11);
3926 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3927 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3928 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3929 present ? 0x00 : 0x02);
3932 /* switch to external mic if plugged */
3933 static void ad1884a_hp_automic(struct hda_codec *codec)
3935 unsigned int present;
3937 present = snd_hda_jack_detect(codec, 0x14);
3938 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
3939 present ? 0 : 1);
3942 #define AD1884A_HP_EVENT 0x37
3943 #define AD1884A_MIC_EVENT 0x36
3945 /* unsolicited event for HP jack sensing */
3946 static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3948 switch (res >> 26) {
3949 case AD1884A_HP_EVENT:
3950 ad1884a_hp_automute(codec);
3951 break;
3952 case AD1884A_MIC_EVENT:
3953 ad1884a_hp_automic(codec);
3954 break;
3958 /* initialize jack-sensing, too */
3959 static int ad1884a_hp_init(struct hda_codec *codec)
3961 ad198x_init(codec);
3962 ad1884a_hp_automute(codec);
3963 ad1884a_hp_automic(codec);
3964 return 0;
3967 /* mute internal speaker if HP or docking HP is plugged */
3968 static void ad1884a_laptop_automute(struct hda_codec *codec)
3970 unsigned int present;
3972 present = snd_hda_jack_detect(codec, 0x11);
3973 if (!present)
3974 present = snd_hda_jack_detect(codec, 0x12);
3975 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3976 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3977 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3978 present ? 0x00 : 0x02);
3981 /* switch to external mic if plugged */
3982 static void ad1884a_laptop_automic(struct hda_codec *codec)
3984 unsigned int idx;
3986 if (snd_hda_jack_detect(codec, 0x14))
3987 idx = 0;
3988 else if (snd_hda_jack_detect(codec, 0x1c))
3989 idx = 4;
3990 else
3991 idx = 1;
3992 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
3995 /* unsolicited event for HP jack sensing */
3996 static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
3997 unsigned int res)
3999 switch (res >> 26) {
4000 case AD1884A_HP_EVENT:
4001 ad1884a_laptop_automute(codec);
4002 break;
4003 case AD1884A_MIC_EVENT:
4004 ad1884a_laptop_automic(codec);
4005 break;
4009 /* initialize jack-sensing, too */
4010 static int ad1884a_laptop_init(struct hda_codec *codec)
4012 ad198x_init(codec);
4013 ad1884a_laptop_automute(codec);
4014 ad1884a_laptop_automic(codec);
4015 return 0;
4018 /* additional verbs for laptop model */
4019 static struct hda_verb ad1884a_laptop_verbs[] = {
4020 /* Port-A (HP) pin - always unmuted */
4021 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4022 /* Port-F (int speaker) mixer - route only from analog mixer */
4023 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4024 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4025 /* Port-F (int speaker) pin */
4026 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4027 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4028 /* required for compaq 6530s/6531s speaker output */
4029 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4030 /* Port-C pin - internal mic-in */
4031 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4032 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4033 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4034 /* Port-D (docking line-out) pin - default unmuted */
4035 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4036 /* analog mix */
4037 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4038 /* unsolicited event for pin-sense */
4039 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4040 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4041 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4042 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4043 /* allow to touch GPIO1 (for mute control) */
4044 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4045 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4046 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4047 { } /* end */
4050 static struct hda_verb ad1884a_mobile_verbs[] = {
4051 /* DACs; unmute as default */
4052 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4053 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4054 /* Port-A (HP) mixer - route only from analog mixer */
4055 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4056 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4057 /* Port-A pin */
4058 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4059 /* Port-A (HP) pin - always unmuted */
4060 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4061 /* Port-B (mic jack) pin */
4062 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4063 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4064 /* Port-C (int mic) pin */
4065 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4066 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4067 /* Port-F (int speaker) mixer - route only from analog mixer */
4068 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4069 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4070 /* Port-F pin */
4071 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4072 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4073 /* Analog mixer; mute as default */
4074 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4075 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4076 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4077 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4078 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4079 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4080 /* Analog Mix output amp */
4081 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4082 /* capture sources */
4083 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4084 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4085 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4086 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4087 /* unsolicited event for pin-sense */
4088 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4089 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4090 /* allow to touch GPIO1 (for mute control) */
4091 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4092 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4093 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4094 { } /* end */
4098 * Thinkpad X300
4099 * 0x11 - HP
4100 * 0x12 - speaker
4101 * 0x14 - mic-in
4102 * 0x17 - built-in mic
4105 static struct hda_verb ad1984a_thinkpad_verbs[] = {
4106 /* HP unmute */
4107 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4108 /* analog mix */
4109 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4110 /* turn on EAPD */
4111 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4112 /* unsolicited event for pin-sense */
4113 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4114 /* internal mic - dmic */
4115 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4116 /* set magic COEFs for dmic */
4117 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4118 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4119 { } /* end */
4122 static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
4123 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4124 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4125 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4126 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4127 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4128 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4129 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
4130 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
4131 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4132 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4134 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4135 .name = "Capture Source",
4136 .info = ad198x_mux_enum_info,
4137 .get = ad198x_mux_enum_get,
4138 .put = ad198x_mux_enum_put,
4140 { } /* end */
4143 static struct hda_input_mux ad1984a_thinkpad_capture_source = {
4144 .num_items = 3,
4145 .items = {
4146 { "Mic", 0x0 },
4147 { "Internal Mic", 0x5 },
4148 { "Mix", 0x3 },
4152 /* mute internal speaker if HP is plugged */
4153 static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4155 unsigned int present;
4157 present = snd_hda_jack_detect(codec, 0x11);
4158 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4159 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4162 /* unsolicited event for HP jack sensing */
4163 static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4164 unsigned int res)
4166 if ((res >> 26) != AD1884A_HP_EVENT)
4167 return;
4168 ad1984a_thinkpad_automute(codec);
4171 /* initialize jack-sensing, too */
4172 static int ad1984a_thinkpad_init(struct hda_codec *codec)
4174 ad198x_init(codec);
4175 ad1984a_thinkpad_automute(codec);
4176 return 0;
4180 * HP Touchsmart
4181 * port-A (0x11) - front hp-out
4182 * port-B (0x14) - unused
4183 * port-C (0x15) - unused
4184 * port-D (0x12) - rear line out
4185 * port-E (0x1c) - front mic-in
4186 * port-F (0x16) - Internal speakers
4187 * digital-mic (0x17) - Internal mic
4190 static struct hda_verb ad1984a_touchsmart_verbs[] = {
4191 /* DACs; unmute as default */
4192 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4193 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4194 /* Port-A (HP) mixer - route only from analog mixer */
4195 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4196 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4197 /* Port-A pin */
4198 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4199 /* Port-A (HP) pin - always unmuted */
4200 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4201 /* Port-E (int speaker) mixer - route only from analog mixer */
4202 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4203 /* Port-E pin */
4204 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4205 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4206 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4207 /* Port-F (int speaker) mixer - route only from analog mixer */
4208 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4209 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4210 /* Port-F pin */
4211 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4212 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4213 /* Analog mixer; mute as default */
4214 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4215 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4216 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4217 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4218 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4219 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4220 /* Analog Mix output amp */
4221 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4222 /* capture sources */
4223 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4224 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4225 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4226 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4227 /* unsolicited event for pin-sense */
4228 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4229 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4230 /* allow to touch GPIO1 (for mute control) */
4231 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4232 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4233 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4234 /* internal mic - dmic */
4235 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4236 /* set magic COEFs for dmic */
4237 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4238 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4239 { } /* end */
4242 static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
4243 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4244 /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4246 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4247 .subdevice = HDA_SUBDEV_AMP_FLAG,
4248 .name = "Master Playback Switch",
4249 .info = snd_hda_mixer_amp_switch_info,
4250 .get = snd_hda_mixer_amp_switch_get,
4251 .put = ad1884a_mobile_master_sw_put,
4252 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4254 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4255 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4256 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4257 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4258 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
4259 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
4260 { } /* end */
4263 /* switch to external mic if plugged */
4264 static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4266 if (snd_hda_jack_detect(codec, 0x1c))
4267 snd_hda_codec_write(codec, 0x0c, 0,
4268 AC_VERB_SET_CONNECT_SEL, 0x4);
4269 else
4270 snd_hda_codec_write(codec, 0x0c, 0,
4271 AC_VERB_SET_CONNECT_SEL, 0x5);
4275 /* unsolicited event for HP jack sensing */
4276 static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4277 unsigned int res)
4279 switch (res >> 26) {
4280 case AD1884A_HP_EVENT:
4281 ad1884a_hp_automute(codec);
4282 break;
4283 case AD1884A_MIC_EVENT:
4284 ad1984a_touchsmart_automic(codec);
4285 break;
4289 /* initialize jack-sensing, too */
4290 static int ad1984a_touchsmart_init(struct hda_codec *codec)
4292 ad198x_init(codec);
4293 ad1884a_hp_automute(codec);
4294 ad1984a_touchsmart_automic(codec);
4295 return 0;
4302 enum {
4303 AD1884A_DESKTOP,
4304 AD1884A_LAPTOP,
4305 AD1884A_MOBILE,
4306 AD1884A_THINKPAD,
4307 AD1984A_TOUCHSMART,
4308 AD1884A_MODELS
4311 static const char *ad1884a_models[AD1884A_MODELS] = {
4312 [AD1884A_DESKTOP] = "desktop",
4313 [AD1884A_LAPTOP] = "laptop",
4314 [AD1884A_MOBILE] = "mobile",
4315 [AD1884A_THINKPAD] = "thinkpad",
4316 [AD1984A_TOUCHSMART] = "touchsmart",
4319 static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
4320 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
4321 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
4322 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
4323 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
4324 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
4325 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4326 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
4327 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
4328 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
4329 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
4333 static int patch_ad1884a(struct hda_codec *codec)
4335 struct ad198x_spec *spec;
4336 int err, board_config;
4338 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4339 if (spec == NULL)
4340 return -ENOMEM;
4342 codec->spec = spec;
4344 err = snd_hda_attach_beep_device(codec, 0x10);
4345 if (err < 0) {
4346 ad198x_free(codec);
4347 return err;
4349 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4351 spec->multiout.max_channels = 2;
4352 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4353 spec->multiout.dac_nids = ad1884a_dac_nids;
4354 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4355 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4356 spec->adc_nids = ad1884a_adc_nids;
4357 spec->capsrc_nids = ad1884a_capsrc_nids;
4358 spec->input_mux = &ad1884a_capture_source;
4359 spec->num_mixers = 1;
4360 spec->mixers[0] = ad1884a_base_mixers;
4361 spec->num_init_verbs = 1;
4362 spec->init_verbs[0] = ad1884a_init_verbs;
4363 spec->spdif_route = 0;
4364 #ifdef CONFIG_SND_HDA_POWER_SAVE
4365 spec->loopback.amplist = ad1884a_loopbacks;
4366 #endif
4367 codec->patch_ops = ad198x_patch_ops;
4369 /* override some parameters */
4370 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
4371 ad1884a_models,
4372 ad1884a_cfg_tbl);
4373 switch (board_config) {
4374 case AD1884A_LAPTOP:
4375 spec->mixers[0] = ad1884a_laptop_mixers;
4376 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4377 spec->multiout.dig_out_nid = 0;
4378 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4379 codec->patch_ops.init = ad1884a_laptop_init;
4380 /* set the upper-limit for mixer amp to 0dB for avoiding the
4381 * possible damage by overloading
4383 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4384 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4385 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4386 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4387 (1 << AC_AMPCAP_MUTE_SHIFT));
4388 break;
4389 case AD1884A_MOBILE:
4390 spec->mixers[0] = ad1884a_mobile_mixers;
4391 spec->init_verbs[0] = ad1884a_mobile_verbs;
4392 spec->multiout.dig_out_nid = 0;
4393 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4394 codec->patch_ops.init = ad1884a_hp_init;
4395 /* set the upper-limit for mixer amp to 0dB for avoiding the
4396 * possible damage by overloading
4398 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4399 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4400 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4401 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4402 (1 << AC_AMPCAP_MUTE_SHIFT));
4403 break;
4404 case AD1884A_THINKPAD:
4405 spec->mixers[0] = ad1984a_thinkpad_mixers;
4406 spec->init_verbs[spec->num_init_verbs++] =
4407 ad1984a_thinkpad_verbs;
4408 spec->multiout.dig_out_nid = 0;
4409 spec->input_mux = &ad1984a_thinkpad_capture_source;
4410 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4411 codec->patch_ops.init = ad1984a_thinkpad_init;
4412 break;
4413 case AD1984A_TOUCHSMART:
4414 spec->mixers[0] = ad1984a_touchsmart_mixers;
4415 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4416 spec->multiout.dig_out_nid = 0;
4417 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4418 codec->patch_ops.init = ad1984a_touchsmart_init;
4419 /* set the upper-limit for mixer amp to 0dB for avoiding the
4420 * possible damage by overloading
4422 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4423 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4424 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4425 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4426 (1 << AC_AMPCAP_MUTE_SHIFT));
4427 break;
4430 codec->no_trigger_sense = 1;
4431 codec->no_sticky_stream = 1;
4433 return 0;
4438 * AD1882 / AD1882A
4440 * port-A - front hp-out
4441 * port-B - front mic-in
4442 * port-C - rear line-in, shared surr-out (3stack)
4443 * port-D - rear line-out
4444 * port-E - rear mic-in, shared clfe-out (3stack)
4445 * port-F - rear surr-out (6stack)
4446 * port-G - rear clfe-out (6stack)
4449 static hda_nid_t ad1882_dac_nids[3] = {
4450 0x04, 0x03, 0x05
4453 static hda_nid_t ad1882_adc_nids[2] = {
4454 0x08, 0x09,
4457 static hda_nid_t ad1882_capsrc_nids[2] = {
4458 0x0c, 0x0d,
4461 #define AD1882_SPDIF_OUT 0x02
4463 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
4464 static struct hda_input_mux ad1882_capture_source = {
4465 .num_items = 5,
4466 .items = {
4467 { "Front Mic", 0x1 },
4468 { "Mic", 0x4 },
4469 { "Line", 0x2 },
4470 { "CD", 0x3 },
4471 { "Mix", 0x7 },
4475 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
4476 static struct hda_input_mux ad1882a_capture_source = {
4477 .num_items = 5,
4478 .items = {
4479 { "Front Mic", 0x1 },
4480 { "Mic", 0x4},
4481 { "Line", 0x2 },
4482 { "Digital Mic", 0x06 },
4483 { "Mix", 0x7 },
4487 static struct snd_kcontrol_new ad1882_base_mixers[] = {
4488 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4489 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4490 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4491 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4492 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4493 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4494 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4495 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
4497 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
4498 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
4499 HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
4500 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4501 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4502 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4503 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4505 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4506 /* The multiple "Capture Source" controls confuse alsamixer
4507 * So call somewhat different..
4509 /* .name = "Capture Source", */
4510 .name = "Input Source",
4511 .count = 2,
4512 .info = ad198x_mux_enum_info,
4513 .get = ad198x_mux_enum_get,
4514 .put = ad198x_mux_enum_put,
4516 /* SPDIF controls */
4517 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4519 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4520 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4521 /* identical with ad1983 */
4522 .info = ad1983_spdif_route_info,
4523 .get = ad1983_spdif_route_get,
4524 .put = ad1983_spdif_route_put,
4526 { } /* end */
4529 static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4530 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4531 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4532 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4533 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4534 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4535 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4536 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4537 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4538 { } /* end */
4541 static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4542 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4543 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4544 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4545 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4546 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4547 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4548 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4549 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4550 HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
4551 { } /* end */
4554 static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4555 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4556 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4557 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4559 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4560 .name = "Channel Mode",
4561 .info = ad198x_ch_mode_info,
4562 .get = ad198x_ch_mode_get,
4563 .put = ad198x_ch_mode_put,
4565 { } /* end */
4568 static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4569 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4570 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4571 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4572 { } /* end */
4575 static struct hda_verb ad1882_ch2_init[] = {
4576 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4577 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4578 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4579 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4580 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4581 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4582 { } /* end */
4585 static struct hda_verb ad1882_ch4_init[] = {
4586 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4587 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4588 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4589 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4590 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4591 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4592 { } /* end */
4595 static struct hda_verb ad1882_ch6_init[] = {
4596 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4597 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4598 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4599 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4600 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4601 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4602 { } /* end */
4605 static struct hda_channel_mode ad1882_modes[3] = {
4606 { 2, ad1882_ch2_init },
4607 { 4, ad1882_ch4_init },
4608 { 6, ad1882_ch6_init },
4612 * initialization verbs
4614 static struct hda_verb ad1882_init_verbs[] = {
4615 /* DACs; mute as default */
4616 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4617 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4618 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4619 /* Port-A (HP) mixer */
4620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4621 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4622 /* Port-A pin */
4623 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4624 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4625 /* HP selector - select DAC2 */
4626 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4627 /* Port-D (Line-out) mixer */
4628 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4629 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4630 /* Port-D pin */
4631 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4632 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4633 /* Mono-out mixer */
4634 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4635 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4636 /* Mono-out pin */
4637 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4638 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4639 /* Port-B (front mic) pin */
4640 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4641 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4642 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4643 /* Port-C (line-in) pin */
4644 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4645 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4646 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4647 /* Port-C mixer - mute as input */
4648 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4649 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4650 /* Port-E (mic-in) pin */
4651 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4652 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4653 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4654 /* Port-E mixer - mute as input */
4655 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4656 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4657 /* Port-F (surround) */
4658 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4659 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4660 /* Port-G (CLFE) */
4661 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4662 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4663 /* Analog mixer; mute as default */
4664 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
4665 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4666 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4667 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4668 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4669 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4670 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4671 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4672 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4673 /* Analog Mix output amp */
4674 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
4675 /* SPDIF output selector */
4676 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4677 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
4678 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4679 { } /* end */
4682 #ifdef CONFIG_SND_HDA_POWER_SAVE
4683 static struct hda_amp_list ad1882_loopbacks[] = {
4684 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4685 { 0x20, HDA_INPUT, 1 }, /* Mic */
4686 { 0x20, HDA_INPUT, 4 }, /* Line */
4687 { 0x20, HDA_INPUT, 6 }, /* CD */
4688 { } /* end */
4690 #endif
4692 /* models */
4693 enum {
4694 AD1882_3STACK,
4695 AD1882_6STACK,
4696 AD1882_MODELS
4699 static const char *ad1882_models[AD1986A_MODELS] = {
4700 [AD1882_3STACK] = "3stack",
4701 [AD1882_6STACK] = "6stack",
4705 static int patch_ad1882(struct hda_codec *codec)
4707 struct ad198x_spec *spec;
4708 int err, board_config;
4710 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4711 if (spec == NULL)
4712 return -ENOMEM;
4714 codec->spec = spec;
4716 err = snd_hda_attach_beep_device(codec, 0x10);
4717 if (err < 0) {
4718 ad198x_free(codec);
4719 return err;
4721 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4723 spec->multiout.max_channels = 6;
4724 spec->multiout.num_dacs = 3;
4725 spec->multiout.dac_nids = ad1882_dac_nids;
4726 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
4727 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
4728 spec->adc_nids = ad1882_adc_nids;
4729 spec->capsrc_nids = ad1882_capsrc_nids;
4730 if (codec->vendor_id == 0x11d41882)
4731 spec->input_mux = &ad1882_capture_source;
4732 else
4733 spec->input_mux = &ad1882a_capture_source;
4734 spec->num_mixers = 2;
4735 spec->mixers[0] = ad1882_base_mixers;
4736 if (codec->vendor_id == 0x11d41882)
4737 spec->mixers[1] = ad1882_loopback_mixers;
4738 else
4739 spec->mixers[1] = ad1882a_loopback_mixers;
4740 spec->num_init_verbs = 1;
4741 spec->init_verbs[0] = ad1882_init_verbs;
4742 spec->spdif_route = 0;
4743 #ifdef CONFIG_SND_HDA_POWER_SAVE
4744 spec->loopback.amplist = ad1882_loopbacks;
4745 #endif
4746 spec->vmaster_nid = 0x04;
4748 codec->patch_ops = ad198x_patch_ops;
4750 /* override some parameters */
4751 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
4752 ad1882_models, NULL);
4753 switch (board_config) {
4754 default:
4755 case AD1882_3STACK:
4756 spec->num_mixers = 3;
4757 spec->mixers[2] = ad1882_3stack_mixers;
4758 spec->channel_mode = ad1882_modes;
4759 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
4760 spec->need_dac_fix = 1;
4761 spec->multiout.max_channels = 2;
4762 spec->multiout.num_dacs = 1;
4763 break;
4764 case AD1882_6STACK:
4765 spec->num_mixers = 3;
4766 spec->mixers[2] = ad1882_6stack_mixers;
4767 break;
4770 codec->no_trigger_sense = 1;
4771 codec->no_sticky_stream = 1;
4773 return 0;
4778 * patch entries
4780 static struct hda_codec_preset snd_hda_preset_analog[] = {
4781 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
4782 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
4783 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
4784 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
4785 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
4786 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
4787 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
4788 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
4789 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
4790 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
4791 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
4792 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
4793 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
4794 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
4795 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
4796 {} /* terminator */
4799 MODULE_ALIAS("snd-hda-codec-id:11d4*");
4801 MODULE_LICENSE("GPL");
4802 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
4804 static struct hda_codec_preset_list analog_list = {
4805 .preset = snd_hda_preset_analog,
4806 .owner = THIS_MODULE,
4809 static int __init patch_analog_init(void)
4811 return snd_hda_add_codec_preset(&analog_list);
4814 static void __exit patch_analog_exit(void)
4816 snd_hda_delete_codec_preset(&analog_list);
4819 module_init(patch_analog_init)
4820 module_exit(patch_analog_exit)