ALSA: fix jazz16 compile (udelay)
[firewire-audio.git] / sound / pci / hda / patch_analog.c
blob214301d568faa9850402912da2d05f3c77fd57f7
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 */
78 #ifdef CONFIG_SND_HDA_POWER_SAVE
79 struct hda_loopback_check loopback;
80 #endif
81 /* for virtual master */
82 hda_nid_t vmaster_nid;
83 const char **slave_vols;
84 const char **slave_sws;
88 * input MUX handling (common part)
90 static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
92 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
93 struct ad198x_spec *spec = codec->spec;
95 return snd_hda_input_mux_info(spec->input_mux, uinfo);
98 static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
100 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
101 struct ad198x_spec *spec = codec->spec;
102 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
104 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
105 return 0;
108 static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
110 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
111 struct ad198x_spec *spec = codec->spec;
112 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
114 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
115 spec->capsrc_nids[adc_idx],
116 &spec->cur_mux[adc_idx]);
120 * initialization (common callbacks)
122 static int ad198x_init(struct hda_codec *codec)
124 struct ad198x_spec *spec = codec->spec;
125 int i;
127 for (i = 0; i < spec->num_init_verbs; i++)
128 snd_hda_sequence_write(codec, spec->init_verbs[i]);
129 return 0;
132 static const char *ad_slave_vols[] = {
133 "Front Playback Volume",
134 "Surround Playback Volume",
135 "Center Playback Volume",
136 "LFE Playback Volume",
137 "Side Playback Volume",
138 "Headphone Playback Volume",
139 "Mono Playback Volume",
140 "Speaker Playback Volume",
141 "IEC958 Playback Volume",
142 NULL
145 static const char *ad_slave_sws[] = {
146 "Front Playback Switch",
147 "Surround Playback Switch",
148 "Center Playback Switch",
149 "LFE Playback Switch",
150 "Side Playback Switch",
151 "Headphone Playback Switch",
152 "Mono Playback Switch",
153 "Speaker Playback Switch",
154 "IEC958 Playback Switch",
155 NULL
158 static void ad198x_free_kctls(struct hda_codec *codec);
160 #ifdef CONFIG_SND_HDA_INPUT_BEEP
161 /* additional beep mixers; the actual parameters are overwritten at build */
162 static struct snd_kcontrol_new ad_beep_mixer[] = {
163 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
164 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
165 { } /* end */
168 #define set_beep_amp(spec, nid, idx, dir) \
169 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
170 #else
171 #define set_beep_amp(spec, nid, idx, dir) /* NOP */
172 #endif
174 static int ad198x_build_controls(struct hda_codec *codec)
176 struct ad198x_spec *spec = codec->spec;
177 struct snd_kcontrol *kctl;
178 unsigned int i;
179 int err;
181 for (i = 0; i < spec->num_mixers; i++) {
182 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
183 if (err < 0)
184 return err;
186 if (spec->multiout.dig_out_nid) {
187 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
188 if (err < 0)
189 return err;
190 err = snd_hda_create_spdif_share_sw(codec,
191 &spec->multiout);
192 if (err < 0)
193 return err;
194 spec->multiout.share_spdif = 1;
196 if (spec->dig_in_nid) {
197 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
198 if (err < 0)
199 return err;
202 /* create beep controls if needed */
203 #ifdef CONFIG_SND_HDA_INPUT_BEEP
204 if (spec->beep_amp) {
205 struct snd_kcontrol_new *knew;
206 for (knew = ad_beep_mixer; knew->name; knew++) {
207 struct snd_kcontrol *kctl;
208 kctl = snd_ctl_new1(knew, codec);
209 if (!kctl)
210 return -ENOMEM;
211 kctl->private_value = spec->beep_amp;
212 err = snd_hda_ctl_add(codec, 0, kctl);
213 if (err < 0)
214 return err;
217 #endif
219 /* if we have no master control, let's create it */
220 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
221 unsigned int vmaster_tlv[4];
222 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
223 HDA_OUTPUT, vmaster_tlv);
224 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
225 vmaster_tlv,
226 (spec->slave_vols ?
227 spec->slave_vols : ad_slave_vols));
228 if (err < 0)
229 return err;
231 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
232 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
233 NULL,
234 (spec->slave_sws ?
235 spec->slave_sws : ad_slave_sws));
236 if (err < 0)
237 return err;
240 ad198x_free_kctls(codec); /* no longer needed */
242 /* assign Capture Source enums to NID */
243 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
244 if (!kctl)
245 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
246 for (i = 0; kctl && i < kctl->count; i++) {
247 err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
248 if (err < 0)
249 return err;
252 /* assign IEC958 enums to NID */
253 kctl = snd_hda_find_mixer_ctl(codec,
254 SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
255 if (kctl) {
256 err = snd_hda_add_nid(codec, kctl, 0,
257 spec->multiout.dig_out_nid);
258 if (err < 0)
259 return err;
262 return 0;
265 #ifdef CONFIG_SND_HDA_POWER_SAVE
266 static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
268 struct ad198x_spec *spec = codec->spec;
269 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
271 #endif
274 * Analog playback callbacks
276 static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
277 struct hda_codec *codec,
278 struct snd_pcm_substream *substream)
280 struct ad198x_spec *spec = codec->spec;
281 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
282 hinfo);
285 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
286 struct hda_codec *codec,
287 unsigned int stream_tag,
288 unsigned int format,
289 struct snd_pcm_substream *substream)
291 struct ad198x_spec *spec = codec->spec;
292 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
293 format, substream);
296 static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
297 struct hda_codec *codec,
298 struct snd_pcm_substream *substream)
300 struct ad198x_spec *spec = codec->spec;
301 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
305 * Digital out
307 static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
308 struct hda_codec *codec,
309 struct snd_pcm_substream *substream)
311 struct ad198x_spec *spec = codec->spec;
312 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
315 static int ad198x_dig_playback_pcm_close(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_close(codec, &spec->multiout);
323 static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
324 struct hda_codec *codec,
325 unsigned int stream_tag,
326 unsigned int format,
327 struct snd_pcm_substream *substream)
329 struct ad198x_spec *spec = codec->spec;
330 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
331 format, substream);
334 static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
335 struct hda_codec *codec,
336 struct snd_pcm_substream *substream)
338 struct ad198x_spec *spec = codec->spec;
339 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
343 * Analog capture
345 static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
346 struct hda_codec *codec,
347 unsigned int stream_tag,
348 unsigned int format,
349 struct snd_pcm_substream *substream)
351 struct ad198x_spec *spec = codec->spec;
352 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
353 stream_tag, 0, format);
354 return 0;
357 static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
358 struct hda_codec *codec,
359 struct snd_pcm_substream *substream)
361 struct ad198x_spec *spec = codec->spec;
362 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
363 return 0;
369 static struct hda_pcm_stream ad198x_pcm_analog_playback = {
370 .substreams = 1,
371 .channels_min = 2,
372 .channels_max = 6, /* changed later */
373 .nid = 0, /* fill later */
374 .ops = {
375 .open = ad198x_playback_pcm_open,
376 .prepare = ad198x_playback_pcm_prepare,
377 .cleanup = ad198x_playback_pcm_cleanup
381 static struct hda_pcm_stream ad198x_pcm_analog_capture = {
382 .substreams = 1,
383 .channels_min = 2,
384 .channels_max = 2,
385 .nid = 0, /* fill later */
386 .ops = {
387 .prepare = ad198x_capture_pcm_prepare,
388 .cleanup = ad198x_capture_pcm_cleanup
392 static struct hda_pcm_stream ad198x_pcm_digital_playback = {
393 .substreams = 1,
394 .channels_min = 2,
395 .channels_max = 2,
396 .nid = 0, /* fill later */
397 .ops = {
398 .open = ad198x_dig_playback_pcm_open,
399 .close = ad198x_dig_playback_pcm_close,
400 .prepare = ad198x_dig_playback_pcm_prepare,
401 .cleanup = ad198x_dig_playback_pcm_cleanup
405 static struct hda_pcm_stream ad198x_pcm_digital_capture = {
406 .substreams = 1,
407 .channels_min = 2,
408 .channels_max = 2,
409 /* NID is set in alc_build_pcms */
412 static int ad198x_build_pcms(struct hda_codec *codec)
414 struct ad198x_spec *spec = codec->spec;
415 struct hda_pcm *info = spec->pcm_rec;
417 codec->num_pcms = 1;
418 codec->pcm_info = info;
420 info->name = "AD198x Analog";
421 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
422 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
423 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
424 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
425 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
426 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
428 if (spec->multiout.dig_out_nid) {
429 info++;
430 codec->num_pcms++;
431 info->name = "AD198x Digital";
432 info->pcm_type = HDA_PCM_TYPE_SPDIF;
433 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
434 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
435 if (spec->dig_in_nid) {
436 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
437 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
441 return 0;
444 static inline void ad198x_shutup(struct hda_codec *codec)
446 snd_hda_shutup_pins(codec);
449 static void ad198x_free_kctls(struct hda_codec *codec)
451 struct ad198x_spec *spec = codec->spec;
453 if (spec->kctls.list) {
454 struct snd_kcontrol_new *kctl = spec->kctls.list;
455 int i;
456 for (i = 0; i < spec->kctls.used; i++)
457 kfree(kctl[i].name);
459 snd_array_free(&spec->kctls);
462 static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
463 hda_nid_t hp)
465 struct ad198x_spec *spec = codec->spec;
466 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
467 !spec->inv_eapd ? 0x00 : 0x02);
468 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
469 !spec->inv_eapd ? 0x00 : 0x02);
472 static void ad198x_power_eapd(struct hda_codec *codec)
474 /* We currently only handle front, HP */
475 switch (codec->vendor_id) {
476 case 0x11d41882:
477 case 0x11d4882a:
478 case 0x11d41884:
479 case 0x11d41984:
480 case 0x11d41883:
481 case 0x11d4184a:
482 case 0x11d4194a:
483 case 0x11d4194b:
484 ad198x_power_eapd_write(codec, 0x12, 0x11);
485 break;
486 case 0x11d41981:
487 case 0x11d41983:
488 ad198x_power_eapd_write(codec, 0x05, 0x06);
489 break;
490 case 0x11d41986:
491 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
492 break;
493 case 0x11d41988:
494 case 0x11d4198b:
495 case 0x11d4989a:
496 case 0x11d4989b:
497 ad198x_power_eapd_write(codec, 0x29, 0x22);
498 break;
502 static void ad198x_free(struct hda_codec *codec)
504 struct ad198x_spec *spec = codec->spec;
506 if (!spec)
507 return;
509 ad198x_shutup(codec);
510 ad198x_free_kctls(codec);
511 kfree(spec);
512 snd_hda_detach_beep_device(codec);
515 #ifdef SND_HDA_NEEDS_RESUME
516 static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
518 ad198x_shutup(codec);
519 ad198x_power_eapd(codec);
520 return 0;
523 static int ad198x_resume(struct hda_codec *codec)
525 ad198x_init(codec);
526 snd_hda_codec_resume_amp(codec);
527 snd_hda_codec_resume_cache(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 .resume = ad198x_resume,
543 #endif
544 .reboot_notify = ad198x_shutup,
549 * EAPD control
550 * the private value = nid
552 #define ad198x_eapd_info snd_ctl_boolean_mono_info
554 static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
555 struct snd_ctl_elem_value *ucontrol)
557 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
558 struct ad198x_spec *spec = codec->spec;
559 if (spec->inv_eapd)
560 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
561 else
562 ucontrol->value.integer.value[0] = spec->cur_eapd;
563 return 0;
566 static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
567 struct snd_ctl_elem_value *ucontrol)
569 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
570 struct ad198x_spec *spec = codec->spec;
571 hda_nid_t nid = kcontrol->private_value & 0xff;
572 unsigned int eapd;
573 eapd = !!ucontrol->value.integer.value[0];
574 if (spec->inv_eapd)
575 eapd = !eapd;
576 if (eapd == spec->cur_eapd)
577 return 0;
578 spec->cur_eapd = eapd;
579 snd_hda_codec_write_cache(codec, nid,
580 0, AC_VERB_SET_EAPD_BTLENABLE,
581 eapd ? 0x02 : 0x00);
582 return 1;
585 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
586 struct snd_ctl_elem_info *uinfo);
587 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
588 struct snd_ctl_elem_value *ucontrol);
589 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
590 struct snd_ctl_elem_value *ucontrol);
594 * AD1986A specific
597 #define AD1986A_SPDIF_OUT 0x02
598 #define AD1986A_FRONT_DAC 0x03
599 #define AD1986A_SURR_DAC 0x04
600 #define AD1986A_CLFE_DAC 0x05
601 #define AD1986A_ADC 0x06
603 static hda_nid_t ad1986a_dac_nids[3] = {
604 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
606 static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
607 static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
609 static struct hda_input_mux ad1986a_capture_source = {
610 .num_items = 7,
611 .items = {
612 { "Mic", 0x0 },
613 { "CD", 0x1 },
614 { "Aux", 0x3 },
615 { "Line", 0x4 },
616 { "Mix", 0x5 },
617 { "Mono", 0x6 },
618 { "Phone", 0x7 },
623 static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
624 .ops = &snd_hda_bind_vol,
625 .values = {
626 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
627 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
628 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
633 static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
634 .ops = &snd_hda_bind_sw,
635 .values = {
636 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
637 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
638 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
644 * mixers
646 static struct snd_kcontrol_new ad1986a_mixers[] = {
648 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
650 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
651 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
652 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
653 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
654 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
655 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
656 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
657 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
658 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
659 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
660 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
661 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
662 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
663 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
664 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
665 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
666 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
667 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
668 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
669 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
670 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
671 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
672 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
673 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
674 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
676 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
677 .name = "Capture Source",
678 .info = ad198x_mux_enum_info,
679 .get = ad198x_mux_enum_get,
680 .put = ad198x_mux_enum_put,
682 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
683 { } /* end */
686 /* additional mixers for 3stack mode */
687 static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
689 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
690 .name = "Channel Mode",
691 .info = ad198x_ch_mode_info,
692 .get = ad198x_ch_mode_get,
693 .put = ad198x_ch_mode_put,
695 { } /* end */
698 /* laptop model - 2ch only */
699 static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
701 /* master controls both pins 0x1a and 0x1b */
702 static struct hda_bind_ctls ad1986a_laptop_master_vol = {
703 .ops = &snd_hda_bind_vol,
704 .values = {
705 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
706 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
711 static struct hda_bind_ctls ad1986a_laptop_master_sw = {
712 .ops = &snd_hda_bind_sw,
713 .values = {
714 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
715 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
720 static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
721 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
722 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
723 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
724 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
725 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
726 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
727 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
728 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
729 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
730 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
731 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
732 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
733 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
735 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
736 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
737 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
738 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
740 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
741 .name = "Capture Source",
742 .info = ad198x_mux_enum_info,
743 .get = ad198x_mux_enum_get,
744 .put = ad198x_mux_enum_put,
746 { } /* end */
749 /* laptop-eapd model - 2ch only */
751 static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
752 .num_items = 3,
753 .items = {
754 { "Mic", 0x0 },
755 { "Internal Mic", 0x4 },
756 { "Mix", 0x5 },
760 static struct hda_input_mux ad1986a_automic_capture_source = {
761 .num_items = 2,
762 .items = {
763 { "Mic", 0x0 },
764 { "Mix", 0x5 },
768 static struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
769 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
770 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
771 { } /* end */
774 static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
775 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
776 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
777 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
778 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
779 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
780 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
781 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
783 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
784 .name = "Capture Source",
785 .info = ad198x_mux_enum_info,
786 .get = ad198x_mux_enum_get,
787 .put = ad198x_mux_enum_put,
790 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
791 .name = "External Amplifier",
792 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
793 .info = ad198x_eapd_info,
794 .get = ad198x_eapd_get,
795 .put = ad198x_eapd_put,
796 .private_value = 0x1b, /* port-D */
798 { } /* end */
801 static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
802 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
803 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
804 { } /* end */
807 /* re-connect the mic boost input according to the jack sensing */
808 static void ad1986a_automic(struct hda_codec *codec)
810 unsigned int present;
811 present = snd_hda_jack_detect(codec, 0x1f);
812 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
813 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
814 present ? 0 : 2);
817 #define AD1986A_MIC_EVENT 0x36
819 static void ad1986a_automic_unsol_event(struct hda_codec *codec,
820 unsigned int res)
822 if ((res >> 26) != AD1986A_MIC_EVENT)
823 return;
824 ad1986a_automic(codec);
827 static int ad1986a_automic_init(struct hda_codec *codec)
829 ad198x_init(codec);
830 ad1986a_automic(codec);
831 return 0;
834 /* laptop-automute - 2ch only */
836 static void ad1986a_update_hp(struct hda_codec *codec)
838 struct ad198x_spec *spec = codec->spec;
839 unsigned int mute;
841 if (spec->jack_present)
842 mute = HDA_AMP_MUTE; /* mute internal speaker */
843 else
844 /* unmute internal speaker if necessary */
845 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
846 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
847 HDA_AMP_MUTE, mute);
850 static void ad1986a_hp_automute(struct hda_codec *codec)
852 struct ad198x_spec *spec = codec->spec;
854 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
855 if (spec->inv_jack_detect)
856 spec->jack_present = !spec->jack_present;
857 ad1986a_update_hp(codec);
860 #define AD1986A_HP_EVENT 0x37
862 static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
864 if ((res >> 26) != AD1986A_HP_EVENT)
865 return;
866 ad1986a_hp_automute(codec);
869 static int ad1986a_hp_init(struct hda_codec *codec)
871 ad198x_init(codec);
872 ad1986a_hp_automute(codec);
873 return 0;
876 /* bind hp and internal speaker mute (with plug check) */
877 static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
878 struct snd_ctl_elem_value *ucontrol)
880 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
881 long *valp = ucontrol->value.integer.value;
882 int change;
884 change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
885 HDA_AMP_MUTE,
886 valp[0] ? 0 : HDA_AMP_MUTE);
887 change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
888 HDA_AMP_MUTE,
889 valp[1] ? 0 : HDA_AMP_MUTE);
890 if (change)
891 ad1986a_update_hp(codec);
892 return change;
895 static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
896 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
898 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
899 .name = "Master Playback Switch",
900 .subdevice = HDA_SUBDEV_AMP_FLAG,
901 .info = snd_hda_mixer_amp_switch_info,
902 .get = snd_hda_mixer_amp_switch_get,
903 .put = ad1986a_hp_master_sw_put,
904 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
906 { } /* end */
911 * initialization verbs
913 static struct hda_verb ad1986a_init_verbs[] = {
914 /* Front, Surround, CLFE DAC; mute as default */
915 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
916 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
917 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
918 /* Downmix - off */
919 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
920 /* HP, Line-Out, Surround, CLFE selectors */
921 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
922 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
923 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
924 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
925 /* Mono selector */
926 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
927 /* Mic selector: Mic 1/2 pin */
928 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
929 /* Line-in selector: Line-in */
930 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
931 /* Mic 1/2 swap */
932 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
933 /* Record selector: mic */
934 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
935 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
936 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
937 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
938 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
939 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
940 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
941 /* PC beep */
942 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
943 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
944 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
945 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
946 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
947 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
948 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
949 /* HP Pin */
950 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
951 /* Front, Surround, CLFE Pins */
952 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
953 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
954 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
955 /* Mono Pin */
956 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
957 /* Mic Pin */
958 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
959 /* Line, Aux, CD, Beep-In Pin */
960 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
961 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
962 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
963 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
964 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
965 { } /* end */
968 static struct hda_verb ad1986a_ch2_init[] = {
969 /* Surround out -> Line In */
970 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
971 /* Line-in selectors */
972 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
973 /* CLFE -> Mic in */
974 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
975 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
976 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
977 { } /* end */
980 static struct hda_verb ad1986a_ch4_init[] = {
981 /* Surround out -> Surround */
982 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
983 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
984 /* CLFE -> Mic in */
985 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
986 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
987 { } /* end */
990 static struct hda_verb ad1986a_ch6_init[] = {
991 /* Surround out -> Surround out */
992 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
993 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
994 /* CLFE -> CLFE */
995 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
996 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
997 { } /* end */
1000 static struct hda_channel_mode ad1986a_modes[3] = {
1001 { 2, ad1986a_ch2_init },
1002 { 4, ad1986a_ch4_init },
1003 { 6, ad1986a_ch6_init },
1006 /* eapd initialization */
1007 static struct hda_verb ad1986a_eapd_init_verbs[] = {
1008 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1012 static struct hda_verb ad1986a_automic_verbs[] = {
1013 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1014 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1015 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
1016 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1017 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
1021 /* Ultra initialization */
1022 static struct hda_verb ad1986a_ultra_init[] = {
1023 /* eapd initialization */
1024 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1025 /* CLFE -> Mic in */
1026 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
1027 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1028 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
1029 { } /* end */
1032 /* pin sensing on HP jack */
1033 static struct hda_verb ad1986a_hp_init_verbs[] = {
1034 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1038 static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
1039 unsigned int res)
1041 switch (res >> 26) {
1042 case AD1986A_HP_EVENT:
1043 ad1986a_hp_automute(codec);
1044 break;
1045 case AD1986A_MIC_EVENT:
1046 ad1986a_automic(codec);
1047 break;
1051 static int ad1986a_samsung_p50_init(struct hda_codec *codec)
1053 ad198x_init(codec);
1054 ad1986a_hp_automute(codec);
1055 ad1986a_automic(codec);
1056 return 0;
1060 /* models */
1061 enum {
1062 AD1986A_6STACK,
1063 AD1986A_3STACK,
1064 AD1986A_LAPTOP,
1065 AD1986A_LAPTOP_EAPD,
1066 AD1986A_LAPTOP_AUTOMUTE,
1067 AD1986A_ULTRA,
1068 AD1986A_SAMSUNG,
1069 AD1986A_SAMSUNG_P50,
1070 AD1986A_MODELS
1073 static const char *ad1986a_models[AD1986A_MODELS] = {
1074 [AD1986A_6STACK] = "6stack",
1075 [AD1986A_3STACK] = "3stack",
1076 [AD1986A_LAPTOP] = "laptop",
1077 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
1078 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
1079 [AD1986A_ULTRA] = "ultra",
1080 [AD1986A_SAMSUNG] = "samsung",
1081 [AD1986A_SAMSUNG_P50] = "samsung-p50",
1084 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
1085 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
1086 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
1087 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
1088 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
1089 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
1090 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
1091 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
1092 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
1093 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
1094 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
1095 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1096 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1097 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1098 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1099 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
1100 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
1101 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
1102 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
1103 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
1104 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
1105 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
1106 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
1107 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
1108 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
1109 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
1110 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
1111 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
1115 #ifdef CONFIG_SND_HDA_POWER_SAVE
1116 static struct hda_amp_list ad1986a_loopbacks[] = {
1117 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1118 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1119 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1120 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1121 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1122 { } /* end */
1124 #endif
1126 static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1128 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
1129 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1132 static int patch_ad1986a(struct hda_codec *codec)
1134 struct ad198x_spec *spec;
1135 int err, board_config;
1137 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1138 if (spec == NULL)
1139 return -ENOMEM;
1141 codec->spec = spec;
1143 err = snd_hda_attach_beep_device(codec, 0x19);
1144 if (err < 0) {
1145 ad198x_free(codec);
1146 return err;
1148 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1150 spec->multiout.max_channels = 6;
1151 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1152 spec->multiout.dac_nids = ad1986a_dac_nids;
1153 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
1154 spec->num_adc_nids = 1;
1155 spec->adc_nids = ad1986a_adc_nids;
1156 spec->capsrc_nids = ad1986a_capsrc_nids;
1157 spec->input_mux = &ad1986a_capture_source;
1158 spec->num_mixers = 1;
1159 spec->mixers[0] = ad1986a_mixers;
1160 spec->num_init_verbs = 1;
1161 spec->init_verbs[0] = ad1986a_init_verbs;
1162 #ifdef CONFIG_SND_HDA_POWER_SAVE
1163 spec->loopback.amplist = ad1986a_loopbacks;
1164 #endif
1165 spec->vmaster_nid = 0x1b;
1166 spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */
1168 codec->patch_ops = ad198x_patch_ops;
1170 /* override some parameters */
1171 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1172 ad1986a_models,
1173 ad1986a_cfg_tbl);
1174 switch (board_config) {
1175 case AD1986A_3STACK:
1176 spec->num_mixers = 2;
1177 spec->mixers[1] = ad1986a_3st_mixers;
1178 spec->num_init_verbs = 2;
1179 spec->init_verbs[1] = ad1986a_ch2_init;
1180 spec->channel_mode = ad1986a_modes;
1181 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
1182 spec->need_dac_fix = 1;
1183 spec->multiout.max_channels = 2;
1184 spec->multiout.num_dacs = 1;
1185 break;
1186 case AD1986A_LAPTOP:
1187 spec->mixers[0] = ad1986a_laptop_mixers;
1188 spec->multiout.max_channels = 2;
1189 spec->multiout.num_dacs = 1;
1190 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1191 break;
1192 case AD1986A_LAPTOP_EAPD:
1193 spec->num_mixers = 3;
1194 spec->mixers[0] = ad1986a_laptop_master_mixers;
1195 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1196 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1197 spec->num_init_verbs = 2;
1198 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1199 spec->multiout.max_channels = 2;
1200 spec->multiout.num_dacs = 1;
1201 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1202 if (!is_jack_available(codec, 0x25))
1203 spec->multiout.dig_out_nid = 0;
1204 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1205 break;
1206 case AD1986A_SAMSUNG:
1207 spec->num_mixers = 2;
1208 spec->mixers[0] = ad1986a_laptop_master_mixers;
1209 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1210 spec->num_init_verbs = 3;
1211 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1212 spec->init_verbs[2] = ad1986a_automic_verbs;
1213 spec->multiout.max_channels = 2;
1214 spec->multiout.num_dacs = 1;
1215 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1216 if (!is_jack_available(codec, 0x25))
1217 spec->multiout.dig_out_nid = 0;
1218 spec->input_mux = &ad1986a_automic_capture_source;
1219 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1220 codec->patch_ops.init = ad1986a_automic_init;
1221 break;
1222 case AD1986A_SAMSUNG_P50:
1223 spec->num_mixers = 2;
1224 spec->mixers[0] = ad1986a_automute_master_mixers;
1225 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1226 spec->num_init_verbs = 4;
1227 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1228 spec->init_verbs[2] = ad1986a_automic_verbs;
1229 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1230 spec->multiout.max_channels = 2;
1231 spec->multiout.num_dacs = 1;
1232 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1233 if (!is_jack_available(codec, 0x25))
1234 spec->multiout.dig_out_nid = 0;
1235 spec->input_mux = &ad1986a_automic_capture_source;
1236 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1237 codec->patch_ops.init = ad1986a_samsung_p50_init;
1238 break;
1239 case AD1986A_LAPTOP_AUTOMUTE:
1240 spec->num_mixers = 3;
1241 spec->mixers[0] = ad1986a_automute_master_mixers;
1242 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1243 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1244 spec->num_init_verbs = 3;
1245 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1246 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1247 spec->multiout.max_channels = 2;
1248 spec->multiout.num_dacs = 1;
1249 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1250 if (!is_jack_available(codec, 0x25))
1251 spec->multiout.dig_out_nid = 0;
1252 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1253 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1254 codec->patch_ops.init = ad1986a_hp_init;
1255 /* Lenovo N100 seems to report the reversed bit
1256 * for HP jack-sensing
1258 spec->inv_jack_detect = 1;
1259 break;
1260 case AD1986A_ULTRA:
1261 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1262 spec->num_init_verbs = 2;
1263 spec->init_verbs[1] = ad1986a_ultra_init;
1264 spec->multiout.max_channels = 2;
1265 spec->multiout.num_dacs = 1;
1266 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1267 spec->multiout.dig_out_nid = 0;
1268 break;
1271 /* AD1986A has a hardware problem that it can't share a stream
1272 * with multiple output pins. The copy of front to surrounds
1273 * causes noisy or silent outputs at a certain timing, e.g.
1274 * changing the volume.
1275 * So, let's disable the shared stream.
1277 spec->multiout.no_share_stream = 1;
1279 codec->no_trigger_sense = 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;
1468 return 0;
1473 * AD1981 HD specific
1476 #define AD1981_SPDIF_OUT 0x02
1477 #define AD1981_DAC 0x03
1478 #define AD1981_ADC 0x04
1480 static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
1481 static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
1482 static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
1484 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
1485 static struct hda_input_mux ad1981_capture_source = {
1486 .num_items = 7,
1487 .items = {
1488 { "Front Mic", 0x0 },
1489 { "Line", 0x1 },
1490 { "Mix", 0x2 },
1491 { "Mix Mono", 0x3 },
1492 { "CD", 0x4 },
1493 { "Mic", 0x6 },
1494 { "Aux", 0x7 },
1498 static struct snd_kcontrol_new ad1981_mixers[] = {
1499 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1500 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1501 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1502 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1503 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1504 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1505 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1506 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1507 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1508 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1509 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1510 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1511 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1512 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1513 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1514 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1515 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1516 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1517 HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
1518 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
1519 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1520 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1522 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1523 .name = "Capture Source",
1524 .info = ad198x_mux_enum_info,
1525 .get = ad198x_mux_enum_get,
1526 .put = ad198x_mux_enum_put,
1528 /* identical with AD1983 */
1530 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1531 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1532 .info = ad1983_spdif_route_info,
1533 .get = ad1983_spdif_route_get,
1534 .put = ad1983_spdif_route_put,
1536 { } /* end */
1539 static struct hda_verb ad1981_init_verbs[] = {
1540 /* Front, HP, Mono; mute as default */
1541 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1542 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1543 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1544 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1545 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1546 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1547 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1548 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1549 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1550 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1551 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1552 /* Front, HP selectors; from Mix */
1553 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1554 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1555 /* Mono selector; from Mix */
1556 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1557 /* Mic Mixer; select Front Mic */
1558 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1559 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1560 /* Mic boost: 0dB */
1561 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1562 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1563 /* Record selector: Front mic */
1564 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1565 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1566 /* SPDIF route: PCM */
1567 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1568 /* Front Pin */
1569 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1570 /* HP Pin */
1571 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1572 /* Mono Pin */
1573 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1574 /* Front & Rear Mic Pins */
1575 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1576 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1577 /* Line Pin */
1578 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1579 /* Digital Beep */
1580 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1581 /* Line-Out as Input: disabled */
1582 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1583 { } /* end */
1586 #ifdef CONFIG_SND_HDA_POWER_SAVE
1587 static struct hda_amp_list ad1981_loopbacks[] = {
1588 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1589 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1590 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1591 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1592 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1593 { } /* end */
1595 #endif
1598 * Patch for HP nx6320
1600 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
1601 * speaker output enabled _and_ mute-LED off.
1604 #define AD1981_HP_EVENT 0x37
1605 #define AD1981_MIC_EVENT 0x38
1607 static struct hda_verb ad1981_hp_init_verbs[] = {
1608 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1609 /* pin sensing on HP and Mic jacks */
1610 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1611 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1615 /* turn on/off EAPD (+ mute HP) as a master switch */
1616 static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1617 struct snd_ctl_elem_value *ucontrol)
1619 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1620 struct ad198x_spec *spec = codec->spec;
1622 if (! ad198x_eapd_put(kcontrol, ucontrol))
1623 return 0;
1624 /* change speaker pin appropriately */
1625 snd_hda_codec_write(codec, 0x05, 0,
1626 AC_VERB_SET_PIN_WIDGET_CONTROL,
1627 spec->cur_eapd ? PIN_OUT : 0);
1628 /* toggle HP mute appropriately */
1629 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1630 HDA_AMP_MUTE,
1631 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
1632 return 1;
1635 /* bind volumes of both NID 0x05 and 0x06 */
1636 static struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1637 .ops = &snd_hda_bind_vol,
1638 .values = {
1639 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1640 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1645 /* mute internal speaker if HP is plugged */
1646 static void ad1981_hp_automute(struct hda_codec *codec)
1648 unsigned int present;
1650 present = snd_hda_jack_detect(codec, 0x06);
1651 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1652 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1655 /* toggle input of built-in and mic jack appropriately */
1656 static void ad1981_hp_automic(struct hda_codec *codec)
1658 static struct hda_verb mic_jack_on[] = {
1659 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1660 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1663 static struct hda_verb mic_jack_off[] = {
1664 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1665 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1668 unsigned int present;
1670 present = snd_hda_jack_detect(codec, 0x08);
1671 if (present)
1672 snd_hda_sequence_write(codec, mic_jack_on);
1673 else
1674 snd_hda_sequence_write(codec, mic_jack_off);
1677 /* unsolicited event for HP jack sensing */
1678 static void ad1981_hp_unsol_event(struct hda_codec *codec,
1679 unsigned int res)
1681 res >>= 26;
1682 switch (res) {
1683 case AD1981_HP_EVENT:
1684 ad1981_hp_automute(codec);
1685 break;
1686 case AD1981_MIC_EVENT:
1687 ad1981_hp_automic(codec);
1688 break;
1692 static struct hda_input_mux ad1981_hp_capture_source = {
1693 .num_items = 3,
1694 .items = {
1695 { "Mic", 0x0 },
1696 { "Docking-Station", 0x1 },
1697 { "Mix", 0x2 },
1701 static struct snd_kcontrol_new ad1981_hp_mixers[] = {
1702 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
1704 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1705 .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
1706 .name = "Master Playback Switch",
1707 .info = ad198x_eapd_info,
1708 .get = ad198x_eapd_get,
1709 .put = ad1981_hp_master_sw_put,
1710 .private_value = 0x05,
1712 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1713 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1714 #if 0
1715 /* FIXME: analog mic/line loopback doesn't work with my tests...
1716 * (although recording is OK)
1718 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1719 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1720 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1721 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1722 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1723 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1724 /* FIXME: does this laptop have analog CD connection? */
1725 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1726 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1727 #endif
1728 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1729 HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
1730 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1731 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1733 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1734 .name = "Capture Source",
1735 .info = ad198x_mux_enum_info,
1736 .get = ad198x_mux_enum_get,
1737 .put = ad198x_mux_enum_put,
1739 { } /* end */
1742 /* initialize jack-sensing, too */
1743 static int ad1981_hp_init(struct hda_codec *codec)
1745 ad198x_init(codec);
1746 ad1981_hp_automute(codec);
1747 ad1981_hp_automic(codec);
1748 return 0;
1751 /* configuration for Toshiba Laptops */
1752 static struct hda_verb ad1981_toshiba_init_verbs[] = {
1753 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
1754 /* pin sensing on HP and Mic jacks */
1755 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1756 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1760 static struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1761 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1762 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1766 /* configuration for Lenovo Thinkpad T60 */
1767 static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1768 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1769 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1770 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1771 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1772 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1773 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1774 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1775 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1776 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1777 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1778 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1780 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1781 .name = "Capture Source",
1782 .info = ad198x_mux_enum_info,
1783 .get = ad198x_mux_enum_get,
1784 .put = ad198x_mux_enum_put,
1786 /* identical with AD1983 */
1788 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1789 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1790 .info = ad1983_spdif_route_info,
1791 .get = ad1983_spdif_route_get,
1792 .put = ad1983_spdif_route_put,
1794 { } /* end */
1797 static struct hda_input_mux ad1981_thinkpad_capture_source = {
1798 .num_items = 3,
1799 .items = {
1800 { "Mic", 0x0 },
1801 { "Mix", 0x2 },
1802 { "CD", 0x4 },
1806 /* models */
1807 enum {
1808 AD1981_BASIC,
1809 AD1981_HP,
1810 AD1981_THINKPAD,
1811 AD1981_TOSHIBA,
1812 AD1981_MODELS
1815 static const char *ad1981_models[AD1981_MODELS] = {
1816 [AD1981_HP] = "hp",
1817 [AD1981_THINKPAD] = "thinkpad",
1818 [AD1981_BASIC] = "basic",
1819 [AD1981_TOSHIBA] = "toshiba"
1822 static struct snd_pci_quirk ad1981_cfg_tbl[] = {
1823 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
1824 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
1825 /* All HP models */
1826 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
1827 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
1828 /* Lenovo Thinkpad T60/X60/Z6xx */
1829 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
1830 /* HP nx6320 (reversed SSID, H/W bug) */
1831 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
1835 static int patch_ad1981(struct hda_codec *codec)
1837 struct ad198x_spec *spec;
1838 int err, board_config;
1840 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1841 if (spec == NULL)
1842 return -ENOMEM;
1844 codec->spec = spec;
1846 err = snd_hda_attach_beep_device(codec, 0x10);
1847 if (err < 0) {
1848 ad198x_free(codec);
1849 return err;
1851 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
1853 spec->multiout.max_channels = 2;
1854 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
1855 spec->multiout.dac_nids = ad1981_dac_nids;
1856 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
1857 spec->num_adc_nids = 1;
1858 spec->adc_nids = ad1981_adc_nids;
1859 spec->capsrc_nids = ad1981_capsrc_nids;
1860 spec->input_mux = &ad1981_capture_source;
1861 spec->num_mixers = 1;
1862 spec->mixers[0] = ad1981_mixers;
1863 spec->num_init_verbs = 1;
1864 spec->init_verbs[0] = ad1981_init_verbs;
1865 spec->spdif_route = 0;
1866 #ifdef CONFIG_SND_HDA_POWER_SAVE
1867 spec->loopback.amplist = ad1981_loopbacks;
1868 #endif
1869 spec->vmaster_nid = 0x05;
1871 codec->patch_ops = ad198x_patch_ops;
1873 /* override some parameters */
1874 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
1875 ad1981_models,
1876 ad1981_cfg_tbl);
1877 switch (board_config) {
1878 case AD1981_HP:
1879 spec->mixers[0] = ad1981_hp_mixers;
1880 spec->num_init_verbs = 2;
1881 spec->init_verbs[1] = ad1981_hp_init_verbs;
1882 spec->multiout.dig_out_nid = 0;
1883 spec->input_mux = &ad1981_hp_capture_source;
1885 codec->patch_ops.init = ad1981_hp_init;
1886 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1887 /* set the upper-limit for mixer amp to 0dB for avoiding the
1888 * possible damage by overloading
1890 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
1891 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1892 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1893 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1894 (1 << AC_AMPCAP_MUTE_SHIFT));
1895 break;
1896 case AD1981_THINKPAD:
1897 spec->mixers[0] = ad1981_thinkpad_mixers;
1898 spec->input_mux = &ad1981_thinkpad_capture_source;
1899 break;
1900 case AD1981_TOSHIBA:
1901 spec->mixers[0] = ad1981_hp_mixers;
1902 spec->mixers[1] = ad1981_toshiba_mixers;
1903 spec->num_init_verbs = 2;
1904 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
1905 spec->multiout.dig_out_nid = 0;
1906 spec->input_mux = &ad1981_hp_capture_source;
1907 codec->patch_ops.init = ad1981_hp_init;
1908 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1909 break;
1912 codec->no_trigger_sense = 1;
1914 return 0;
1919 * AD1988
1921 * Output pins and routes
1923 * Pin Mix Sel DAC (*)
1924 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
1925 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
1926 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
1927 * port-D 0x12 (mute/hp) <- 0x29 <- 04
1928 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
1929 * port-F 0x16 (mute) <- 0x2a <- 06
1930 * port-G 0x24 (mute) <- 0x27 <- 05
1931 * port-H 0x25 (mute) <- 0x28 <- 0a
1932 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
1934 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
1935 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
1937 * Input pins and routes
1939 * pin boost mix input # / adc input #
1940 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
1941 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
1942 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
1943 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
1944 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
1945 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
1946 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
1947 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
1950 * DAC assignment
1951 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
1952 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
1954 * Inputs of Analog Mix (0x20)
1955 * 0:Port-B (front mic)
1956 * 1:Port-C/G/H (line-in)
1957 * 2:Port-A
1958 * 3:Port-D (line-in/2)
1959 * 4:Port-E/G/H (mic-in)
1960 * 5:Port-F (mic2-in)
1961 * 6:CD
1962 * 7:Beep
1964 * ADC selection
1965 * 0:Port-A
1966 * 1:Port-B (front mic-in)
1967 * 2:Port-C (line-in)
1968 * 3:Port-F (mic2-in)
1969 * 4:Port-E (mic-in)
1970 * 5:CD
1971 * 6:Port-G
1972 * 7:Port-H
1973 * 8:Port-D (line-in/2)
1974 * 9:Mix
1976 * Proposed pin assignments by the datasheet
1978 * 6-stack
1979 * Port-A front headphone
1980 * B front mic-in
1981 * C rear line-in
1982 * D rear front-out
1983 * E rear mic-in
1984 * F rear surround
1985 * G rear CLFE
1986 * H rear side
1988 * 3-stack
1989 * Port-A front headphone
1990 * B front mic
1991 * C rear line-in/surround
1992 * D rear front-out
1993 * E rear mic-in/CLFE
1995 * laptop
1996 * Port-A headphone
1997 * B mic-in
1998 * C docking station
1999 * D internal speaker (with EAPD)
2000 * E/F quad mic array
2004 /* models */
2005 enum {
2006 AD1988_6STACK,
2007 AD1988_6STACK_DIG,
2008 AD1988_3STACK,
2009 AD1988_3STACK_DIG,
2010 AD1988_LAPTOP,
2011 AD1988_LAPTOP_DIG,
2012 AD1988_AUTO,
2013 AD1988_MODEL_LAST,
2016 /* reivision id to check workarounds */
2017 #define AD1988A_REV2 0x100200
2019 #define is_rev2(codec) \
2020 ((codec)->vendor_id == 0x11d41988 && \
2021 (codec)->revision_id == AD1988A_REV2)
2024 * mixers
2027 static hda_nid_t ad1988_6stack_dac_nids[4] = {
2028 0x04, 0x06, 0x05, 0x0a
2031 static hda_nid_t ad1988_3stack_dac_nids[3] = {
2032 0x04, 0x05, 0x0a
2035 /* for AD1988A revision-2, DAC2-4 are swapped */
2036 static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
2037 0x04, 0x05, 0x0a, 0x06
2040 static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
2041 0x04, 0x0a, 0x06
2044 static hda_nid_t ad1988_adc_nids[3] = {
2045 0x08, 0x09, 0x0f
2048 static hda_nid_t ad1988_capsrc_nids[3] = {
2049 0x0c, 0x0d, 0x0e
2052 #define AD1988_SPDIF_OUT 0x02
2053 #define AD1988_SPDIF_OUT_HDMI 0x0b
2054 #define AD1988_SPDIF_IN 0x07
2056 static hda_nid_t ad1989b_slave_dig_outs[] = {
2057 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
2060 static struct hda_input_mux ad1988_6stack_capture_source = {
2061 .num_items = 5,
2062 .items = {
2063 { "Front Mic", 0x1 }, /* port-B */
2064 { "Line", 0x2 }, /* port-C */
2065 { "Mic", 0x4 }, /* port-E */
2066 { "CD", 0x5 },
2067 { "Mix", 0x9 },
2071 static struct hda_input_mux ad1988_laptop_capture_source = {
2072 .num_items = 3,
2073 .items = {
2074 { "Mic/Line", 0x1 }, /* port-B */
2075 { "CD", 0x5 },
2076 { "Mix", 0x9 },
2082 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
2083 struct snd_ctl_elem_info *uinfo)
2085 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2086 struct ad198x_spec *spec = codec->spec;
2087 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
2088 spec->num_channel_mode);
2091 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
2092 struct snd_ctl_elem_value *ucontrol)
2094 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2095 struct ad198x_spec *spec = codec->spec;
2096 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
2097 spec->num_channel_mode, spec->multiout.max_channels);
2100 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
2101 struct snd_ctl_elem_value *ucontrol)
2103 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2104 struct ad198x_spec *spec = codec->spec;
2105 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
2106 spec->num_channel_mode,
2107 &spec->multiout.max_channels);
2108 if (err >= 0 && spec->need_dac_fix)
2109 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2110 return err;
2113 /* 6-stack mode */
2114 static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
2115 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2116 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2117 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2118 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2119 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2120 { } /* end */
2123 static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
2124 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2125 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2126 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2127 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2128 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2129 { } /* end */
2132 static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
2133 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2134 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2135 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2136 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2137 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2138 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2139 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2141 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2142 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2143 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2144 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2145 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2146 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2147 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2148 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2150 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2151 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2153 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2154 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2156 { } /* end */
2159 /* 3-stack mode */
2160 static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
2161 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2162 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2163 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2164 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2165 { } /* end */
2168 static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2169 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2170 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2171 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2172 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
2173 { } /* end */
2176 static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
2177 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2178 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2179 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2180 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
2181 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2182 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2184 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2185 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2186 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2187 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2188 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2189 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2190 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2191 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2193 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2194 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2196 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2197 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2199 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2200 .name = "Channel Mode",
2201 .info = ad198x_ch_mode_info,
2202 .get = ad198x_ch_mode_get,
2203 .put = ad198x_ch_mode_put,
2206 { } /* end */
2209 /* laptop mode */
2210 static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2211 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2212 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2213 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2215 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2216 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2217 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2218 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2219 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2220 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2222 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2223 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2225 HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2228 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2229 .name = "External Amplifier",
2230 .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
2231 .info = ad198x_eapd_info,
2232 .get = ad198x_eapd_get,
2233 .put = ad198x_eapd_put,
2234 .private_value = 0x12, /* port-D */
2237 { } /* end */
2240 /* capture */
2241 static struct snd_kcontrol_new ad1988_capture_mixers[] = {
2242 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2243 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2244 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2245 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2246 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2247 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2249 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2250 /* The multiple "Capture Source" controls confuse alsamixer
2251 * So call somewhat different..
2253 /* .name = "Capture Source", */
2254 .name = "Input Source",
2255 .count = 3,
2256 .info = ad198x_mux_enum_info,
2257 .get = ad198x_mux_enum_get,
2258 .put = ad198x_mux_enum_put,
2260 { } /* end */
2263 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2264 struct snd_ctl_elem_info *uinfo)
2266 static char *texts[] = {
2267 "PCM", "ADC1", "ADC2", "ADC3"
2269 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2270 uinfo->count = 1;
2271 uinfo->value.enumerated.items = 4;
2272 if (uinfo->value.enumerated.item >= 4)
2273 uinfo->value.enumerated.item = 3;
2274 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2275 return 0;
2278 static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2279 struct snd_ctl_elem_value *ucontrol)
2281 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2282 unsigned int sel;
2284 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2285 AC_AMP_GET_INPUT);
2286 if (!(sel & 0x80))
2287 ucontrol->value.enumerated.item[0] = 0;
2288 else {
2289 sel = snd_hda_codec_read(codec, 0x0b, 0,
2290 AC_VERB_GET_CONNECT_SEL, 0);
2291 if (sel < 3)
2292 sel++;
2293 else
2294 sel = 0;
2295 ucontrol->value.enumerated.item[0] = sel;
2297 return 0;
2300 static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2301 struct snd_ctl_elem_value *ucontrol)
2303 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2304 unsigned int val, sel;
2305 int change;
2307 val = ucontrol->value.enumerated.item[0];
2308 if (val > 3)
2309 return -EINVAL;
2310 if (!val) {
2311 sel = snd_hda_codec_read(codec, 0x1d, 0,
2312 AC_VERB_GET_AMP_GAIN_MUTE,
2313 AC_AMP_GET_INPUT);
2314 change = sel & 0x80;
2315 if (change) {
2316 snd_hda_codec_write_cache(codec, 0x1d, 0,
2317 AC_VERB_SET_AMP_GAIN_MUTE,
2318 AMP_IN_UNMUTE(0));
2319 snd_hda_codec_write_cache(codec, 0x1d, 0,
2320 AC_VERB_SET_AMP_GAIN_MUTE,
2321 AMP_IN_MUTE(1));
2323 } else {
2324 sel = snd_hda_codec_read(codec, 0x1d, 0,
2325 AC_VERB_GET_AMP_GAIN_MUTE,
2326 AC_AMP_GET_INPUT | 0x01);
2327 change = sel & 0x80;
2328 if (change) {
2329 snd_hda_codec_write_cache(codec, 0x1d, 0,
2330 AC_VERB_SET_AMP_GAIN_MUTE,
2331 AMP_IN_MUTE(0));
2332 snd_hda_codec_write_cache(codec, 0x1d, 0,
2333 AC_VERB_SET_AMP_GAIN_MUTE,
2334 AMP_IN_UNMUTE(1));
2336 sel = snd_hda_codec_read(codec, 0x0b, 0,
2337 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2338 change |= sel != val;
2339 if (change)
2340 snd_hda_codec_write_cache(codec, 0x0b, 0,
2341 AC_VERB_SET_CONNECT_SEL,
2342 val - 1);
2344 return change;
2347 static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2348 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2350 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2351 .name = "IEC958 Playback Source",
2352 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
2353 .info = ad1988_spdif_playback_source_info,
2354 .get = ad1988_spdif_playback_source_get,
2355 .put = ad1988_spdif_playback_source_put,
2357 { } /* end */
2360 static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2361 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2362 { } /* end */
2365 static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2366 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2367 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2368 { } /* end */
2372 * initialization verbs
2376 * for 6-stack (+dig)
2378 static struct hda_verb ad1988_6stack_init_verbs[] = {
2379 /* Front, Surround, CLFE, side DAC; unmute as default */
2380 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2381 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2382 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2383 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2384 /* Port-A front headphon path */
2385 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2386 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2387 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2388 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2389 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2390 /* Port-D line-out path */
2391 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2392 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2393 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2394 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2395 /* Port-F surround path */
2396 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2397 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2398 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2399 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2400 /* Port-G CLFE path */
2401 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2402 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2403 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2404 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2405 /* Port-H side path */
2406 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2407 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2408 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2409 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2410 /* Mono out path */
2411 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2412 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2413 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2414 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2415 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2416 /* Port-B front mic-in path */
2417 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2418 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2419 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2420 /* Port-C line-in path */
2421 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2422 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2423 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2424 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2425 /* Port-E mic-in path */
2426 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2427 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2428 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2429 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2430 /* Analog CD Input */
2431 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2432 /* Analog Mix output amp */
2433 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2438 static struct hda_verb ad1988_capture_init_verbs[] = {
2439 /* mute analog mix */
2440 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2441 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2442 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2443 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2444 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2445 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2446 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2447 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2448 /* select ADCs - front-mic */
2449 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2450 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2451 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2456 static struct hda_verb ad1988_spdif_init_verbs[] = {
2457 /* SPDIF out sel */
2458 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2459 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2460 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2461 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2462 /* SPDIF out pin */
2463 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2468 static struct hda_verb ad1988_spdif_in_init_verbs[] = {
2469 /* unmute SPDIF input pin */
2470 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2474 /* AD1989 has no ADC -> SPDIF route */
2475 static struct hda_verb ad1989_spdif_init_verbs[] = {
2476 /* SPDIF-1 out pin */
2477 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2478 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2479 /* SPDIF-2/HDMI out pin */
2480 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2481 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2486 * verbs for 3stack (+dig)
2488 static struct hda_verb ad1988_3stack_ch2_init[] = {
2489 /* set port-C to line-in */
2490 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2491 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2492 /* set port-E to mic-in */
2493 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2494 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2495 { } /* end */
2498 static struct hda_verb ad1988_3stack_ch6_init[] = {
2499 /* set port-C to surround out */
2500 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2501 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2502 /* set port-E to CLFE out */
2503 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2504 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2505 { } /* end */
2508 static struct hda_channel_mode ad1988_3stack_modes[2] = {
2509 { 2, ad1988_3stack_ch2_init },
2510 { 6, ad1988_3stack_ch6_init },
2513 static struct hda_verb ad1988_3stack_init_verbs[] = {
2514 /* Front, Surround, CLFE, side DAC; unmute as default */
2515 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2516 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2517 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2518 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2519 /* Port-A front headphon path */
2520 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2521 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2522 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2523 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2524 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2525 /* Port-D line-out path */
2526 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2527 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2528 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2529 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2530 /* Mono out path */
2531 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2532 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2533 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2534 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2535 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2536 /* Port-B front mic-in path */
2537 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2538 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2539 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2540 /* Port-C line-in/surround path - 6ch mode as default */
2541 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2542 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2543 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2544 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
2545 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2546 /* Port-E mic-in/CLFE path - 6ch mode as default */
2547 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2548 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2549 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2550 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
2551 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2552 /* mute analog mix */
2553 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2554 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2555 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2556 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2557 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2558 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2559 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2560 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2561 /* select ADCs - front-mic */
2562 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2563 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2564 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2565 /* Analog Mix output amp */
2566 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2571 * verbs for laptop mode (+dig)
2573 static struct hda_verb ad1988_laptop_hp_on[] = {
2574 /* unmute port-A and mute port-D */
2575 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2576 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2577 { } /* end */
2579 static struct hda_verb ad1988_laptop_hp_off[] = {
2580 /* mute port-A and unmute port-D */
2581 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2582 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2583 { } /* end */
2586 #define AD1988_HP_EVENT 0x01
2588 static struct hda_verb ad1988_laptop_init_verbs[] = {
2589 /* Front, Surround, CLFE, side DAC; unmute as default */
2590 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2591 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2592 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2593 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2594 /* Port-A front headphon path */
2595 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2596 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2597 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2598 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2599 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2600 /* unsolicited event for pin-sense */
2601 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2602 /* Port-D line-out path + EAPD */
2603 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2604 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2605 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2606 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2607 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
2608 /* Mono out path */
2609 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2610 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2611 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2612 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2613 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2614 /* Port-B mic-in path */
2615 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2616 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2617 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2618 /* Port-C docking station - try to output */
2619 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2620 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2621 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2622 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2623 /* mute analog mix */
2624 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2625 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2626 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2627 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2628 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2629 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2630 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2631 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2632 /* select ADCs - mic */
2633 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2634 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2635 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2636 /* Analog Mix output amp */
2637 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2641 static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2643 if ((res >> 26) != AD1988_HP_EVENT)
2644 return;
2645 if (snd_hda_jack_detect(codec, 0x11))
2646 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2647 else
2648 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2651 #ifdef CONFIG_SND_HDA_POWER_SAVE
2652 static struct hda_amp_list ad1988_loopbacks[] = {
2653 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2654 { 0x20, HDA_INPUT, 1 }, /* Line */
2655 { 0x20, HDA_INPUT, 4 }, /* Mic */
2656 { 0x20, HDA_INPUT, 6 }, /* CD */
2657 { } /* end */
2659 #endif
2662 * Automatic parse of I/O pins from the BIOS configuration
2665 enum {
2666 AD_CTL_WIDGET_VOL,
2667 AD_CTL_WIDGET_MUTE,
2668 AD_CTL_BIND_MUTE,
2670 static struct snd_kcontrol_new ad1988_control_templates[] = {
2671 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2672 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2673 HDA_BIND_MUTE(NULL, 0, 0, 0),
2676 /* add dynamic controls */
2677 static int add_control(struct ad198x_spec *spec, int type, const char *name,
2678 unsigned long val)
2680 struct snd_kcontrol_new *knew;
2682 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2683 knew = snd_array_new(&spec->kctls);
2684 if (!knew)
2685 return -ENOMEM;
2686 *knew = ad1988_control_templates[type];
2687 knew->name = kstrdup(name, GFP_KERNEL);
2688 if (! knew->name)
2689 return -ENOMEM;
2690 if (get_amp_nid_(val))
2691 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2692 knew->private_value = val;
2693 return 0;
2696 #define AD1988_PIN_CD_NID 0x18
2697 #define AD1988_PIN_BEEP_NID 0x10
2699 static hda_nid_t ad1988_mixer_nids[8] = {
2700 /* A B C D E F G H */
2701 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
2704 static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
2706 static hda_nid_t idx_to_dac[8] = {
2707 /* A B C D E F G H */
2708 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
2710 static hda_nid_t idx_to_dac_rev2[8] = {
2711 /* A B C D E F G H */
2712 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
2714 if (is_rev2(codec))
2715 return idx_to_dac_rev2[idx];
2716 else
2717 return idx_to_dac[idx];
2720 static hda_nid_t ad1988_boost_nids[8] = {
2721 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
2724 static int ad1988_pin_idx(hda_nid_t nid)
2726 static hda_nid_t ad1988_io_pins[8] = {
2727 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
2729 int i;
2730 for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)
2731 if (ad1988_io_pins[i] == nid)
2732 return i;
2733 return 0; /* should be -1 */
2736 static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
2738 static int loopback_idx[8] = {
2739 2, 0, 1, 3, 4, 5, 1, 4
2741 switch (nid) {
2742 case AD1988_PIN_CD_NID:
2743 return 6;
2744 default:
2745 return loopback_idx[ad1988_pin_idx(nid)];
2749 static int ad1988_pin_to_adc_idx(hda_nid_t nid)
2751 static int adc_idx[8] = {
2752 0, 1, 2, 8, 4, 3, 6, 7
2754 switch (nid) {
2755 case AD1988_PIN_CD_NID:
2756 return 5;
2757 default:
2758 return adc_idx[ad1988_pin_idx(nid)];
2762 /* fill in the dac_nids table from the parsed pin configuration */
2763 static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
2764 const struct auto_pin_cfg *cfg)
2766 struct ad198x_spec *spec = codec->spec;
2767 int i, idx;
2769 spec->multiout.dac_nids = spec->private_dac_nids;
2771 /* check the pins hardwired to audio widget */
2772 for (i = 0; i < cfg->line_outs; i++) {
2773 idx = ad1988_pin_idx(cfg->line_out_pins[i]);
2774 spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx);
2776 spec->multiout.num_dacs = cfg->line_outs;
2777 return 0;
2780 /* add playback controls from the parsed DAC table */
2781 static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
2782 const struct auto_pin_cfg *cfg)
2784 char name[32];
2785 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
2786 hda_nid_t nid;
2787 int i, err;
2789 for (i = 0; i < cfg->line_outs; i++) {
2790 hda_nid_t dac = spec->multiout.dac_nids[i];
2791 if (! dac)
2792 continue;
2793 nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];
2794 if (i == 2) {
2795 /* Center/LFE */
2796 err = add_control(spec, AD_CTL_WIDGET_VOL,
2797 "Center Playback Volume",
2798 HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));
2799 if (err < 0)
2800 return err;
2801 err = add_control(spec, AD_CTL_WIDGET_VOL,
2802 "LFE Playback Volume",
2803 HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));
2804 if (err < 0)
2805 return err;
2806 err = add_control(spec, AD_CTL_BIND_MUTE,
2807 "Center Playback Switch",
2808 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
2809 if (err < 0)
2810 return err;
2811 err = add_control(spec, AD_CTL_BIND_MUTE,
2812 "LFE Playback Switch",
2813 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
2814 if (err < 0)
2815 return err;
2816 } else {
2817 sprintf(name, "%s Playback Volume", chname[i]);
2818 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2819 HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));
2820 if (err < 0)
2821 return err;
2822 sprintf(name, "%s Playback Switch", chname[i]);
2823 err = add_control(spec, AD_CTL_BIND_MUTE, name,
2824 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
2825 if (err < 0)
2826 return err;
2829 return 0;
2832 /* add playback controls for speaker and HP outputs */
2833 static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
2834 const char *pfx)
2836 struct ad198x_spec *spec = codec->spec;
2837 hda_nid_t nid;
2838 int i, idx, err;
2839 char name[32];
2841 if (! pin)
2842 return 0;
2844 idx = ad1988_pin_idx(pin);
2845 nid = ad1988_idx_to_dac(codec, idx);
2846 /* check whether the corresponding DAC was already taken */
2847 for (i = 0; i < spec->autocfg.line_outs; i++) {
2848 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2849 hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
2850 if (dac == nid)
2851 break;
2853 if (i >= spec->autocfg.line_outs) {
2854 /* specify the DAC as the extra output */
2855 if (!spec->multiout.hp_nid)
2856 spec->multiout.hp_nid = nid;
2857 else
2858 spec->multiout.extra_out_nid[0] = nid;
2859 /* control HP volume/switch on the output mixer amp */
2860 sprintf(name, "%s Playback Volume", pfx);
2861 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2862 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2863 if (err < 0)
2864 return err;
2866 nid = ad1988_mixer_nids[idx];
2867 sprintf(name, "%s Playback Switch", pfx);
2868 if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
2869 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2870 return err;
2871 return 0;
2874 /* create input playback/capture controls for the given pin */
2875 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
2876 const char *ctlname, int boost)
2878 char name[32];
2879 int err, idx;
2881 sprintf(name, "%s Playback Volume", ctlname);
2882 idx = ad1988_pin_to_loopback_idx(pin);
2883 if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2884 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2885 return err;
2886 sprintf(name, "%s Playback Switch", ctlname);
2887 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,
2888 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2889 return err;
2890 if (boost) {
2891 hda_nid_t bnid;
2892 idx = ad1988_pin_idx(pin);
2893 bnid = ad1988_boost_nids[idx];
2894 if (bnid) {
2895 sprintf(name, "%s Boost", ctlname);
2896 return add_control(spec, AD_CTL_WIDGET_VOL, name,
2897 HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
2901 return 0;
2904 /* create playback/capture controls for input pins */
2905 static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
2906 const struct auto_pin_cfg *cfg)
2908 struct hda_input_mux *imux = &spec->private_imux;
2909 int i, err;
2911 for (i = 0; i < AUTO_PIN_LAST; i++) {
2912 err = new_analog_input(spec, cfg->input_pins[i],
2913 auto_pin_cfg_labels[i],
2914 i <= AUTO_PIN_FRONT_MIC);
2915 if (err < 0)
2916 return err;
2917 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2918 imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
2919 imux->num_items++;
2921 imux->items[imux->num_items].label = "Mix";
2922 imux->items[imux->num_items].index = 9;
2923 imux->num_items++;
2925 if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
2926 "Analog Mix Playback Volume",
2927 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2928 return err;
2929 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,
2930 "Analog Mix Playback Switch",
2931 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2932 return err;
2934 return 0;
2937 static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
2938 hda_nid_t nid, int pin_type,
2939 int dac_idx)
2941 /* set as output */
2942 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2943 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2944 switch (nid) {
2945 case 0x11: /* port-A - DAC 04 */
2946 snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2947 break;
2948 case 0x14: /* port-B - DAC 06 */
2949 snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
2950 break;
2951 case 0x15: /* port-C - DAC 05 */
2952 snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
2953 break;
2954 case 0x17: /* port-E - DAC 0a */
2955 snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2956 break;
2957 case 0x13: /* mono - DAC 04 */
2958 snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2959 break;
2963 static void ad1988_auto_init_multi_out(struct hda_codec *codec)
2965 struct ad198x_spec *spec = codec->spec;
2966 int i;
2968 for (i = 0; i < spec->autocfg.line_outs; i++) {
2969 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2970 ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
2974 static void ad1988_auto_init_extra_out(struct hda_codec *codec)
2976 struct ad198x_spec *spec = codec->spec;
2977 hda_nid_t pin;
2979 pin = spec->autocfg.speaker_pins[0];
2980 if (pin) /* connect to front */
2981 ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
2982 pin = spec->autocfg.hp_pins[0];
2983 if (pin) /* connect to front */
2984 ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
2987 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
2989 struct ad198x_spec *spec = codec->spec;
2990 int i, idx;
2992 for (i = 0; i < AUTO_PIN_LAST; i++) {
2993 hda_nid_t nid = spec->autocfg.input_pins[i];
2994 if (! nid)
2995 continue;
2996 switch (nid) {
2997 case 0x15: /* port-C */
2998 snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
2999 break;
3000 case 0x17: /* port-E */
3001 snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3002 break;
3004 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3005 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
3006 if (nid != AD1988_PIN_CD_NID)
3007 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3008 AMP_OUT_MUTE);
3009 idx = ad1988_pin_idx(nid);
3010 if (ad1988_boost_nids[idx])
3011 snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,
3012 AC_VERB_SET_AMP_GAIN_MUTE,
3013 AMP_OUT_ZERO);
3017 /* parse the BIOS configuration and set up the alc_spec */
3018 /* return 1 if successful, 0 if the proper config is not found, or a negative error code */
3019 static int ad1988_parse_auto_config(struct hda_codec *codec)
3021 struct ad198x_spec *spec = codec->spec;
3022 int err;
3024 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
3025 return err;
3026 if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3027 return err;
3028 if (! spec->autocfg.line_outs)
3029 return 0; /* can't find valid BIOS pin config */
3030 if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
3031 (err = ad1988_auto_create_extra_out(codec,
3032 spec->autocfg.speaker_pins[0],
3033 "Speaker")) < 0 ||
3034 (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
3035 "Headphone")) < 0 ||
3036 (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
3037 return err;
3039 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3041 if (spec->autocfg.dig_outs)
3042 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3043 if (spec->autocfg.dig_in_pin)
3044 spec->dig_in_nid = AD1988_SPDIF_IN;
3046 if (spec->kctls.list)
3047 spec->mixers[spec->num_mixers++] = spec->kctls.list;
3049 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
3051 spec->input_mux = &spec->private_imux;
3053 return 1;
3056 /* init callback for auto-configuration model -- overriding the default init */
3057 static int ad1988_auto_init(struct hda_codec *codec)
3059 ad198x_init(codec);
3060 ad1988_auto_init_multi_out(codec);
3061 ad1988_auto_init_extra_out(codec);
3062 ad1988_auto_init_analog_input(codec);
3063 return 0;
3070 static const char *ad1988_models[AD1988_MODEL_LAST] = {
3071 [AD1988_6STACK] = "6stack",
3072 [AD1988_6STACK_DIG] = "6stack-dig",
3073 [AD1988_3STACK] = "3stack",
3074 [AD1988_3STACK_DIG] = "3stack-dig",
3075 [AD1988_LAPTOP] = "laptop",
3076 [AD1988_LAPTOP_DIG] = "laptop-dig",
3077 [AD1988_AUTO] = "auto",
3080 static struct snd_pci_quirk ad1988_cfg_tbl[] = {
3081 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
3082 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
3083 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
3084 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
3088 static int patch_ad1988(struct hda_codec *codec)
3090 struct ad198x_spec *spec;
3091 int err, board_config;
3093 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3094 if (spec == NULL)
3095 return -ENOMEM;
3097 codec->spec = spec;
3099 if (is_rev2(codec))
3100 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
3102 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
3103 ad1988_models, ad1988_cfg_tbl);
3104 if (board_config < 0) {
3105 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3106 codec->chip_name);
3107 board_config = AD1988_AUTO;
3110 if (board_config == AD1988_AUTO) {
3111 /* automatic parse from the BIOS config */
3112 err = ad1988_parse_auto_config(codec);
3113 if (err < 0) {
3114 ad198x_free(codec);
3115 return err;
3116 } else if (! err) {
3117 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n");
3118 board_config = AD1988_6STACK;
3122 err = snd_hda_attach_beep_device(codec, 0x10);
3123 if (err < 0) {
3124 ad198x_free(codec);
3125 return err;
3127 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3129 switch (board_config) {
3130 case AD1988_6STACK:
3131 case AD1988_6STACK_DIG:
3132 spec->multiout.max_channels = 8;
3133 spec->multiout.num_dacs = 4;
3134 if (is_rev2(codec))
3135 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3136 else
3137 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
3138 spec->input_mux = &ad1988_6stack_capture_source;
3139 spec->num_mixers = 2;
3140 if (is_rev2(codec))
3141 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3142 else
3143 spec->mixers[0] = ad1988_6stack_mixers1;
3144 spec->mixers[1] = ad1988_6stack_mixers2;
3145 spec->num_init_verbs = 1;
3146 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3147 if (board_config == AD1988_6STACK_DIG) {
3148 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3149 spec->dig_in_nid = AD1988_SPDIF_IN;
3151 break;
3152 case AD1988_3STACK:
3153 case AD1988_3STACK_DIG:
3154 spec->multiout.max_channels = 6;
3155 spec->multiout.num_dacs = 3;
3156 if (is_rev2(codec))
3157 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3158 else
3159 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3160 spec->input_mux = &ad1988_6stack_capture_source;
3161 spec->channel_mode = ad1988_3stack_modes;
3162 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
3163 spec->num_mixers = 2;
3164 if (is_rev2(codec))
3165 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3166 else
3167 spec->mixers[0] = ad1988_3stack_mixers1;
3168 spec->mixers[1] = ad1988_3stack_mixers2;
3169 spec->num_init_verbs = 1;
3170 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3171 if (board_config == AD1988_3STACK_DIG)
3172 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3173 break;
3174 case AD1988_LAPTOP:
3175 case AD1988_LAPTOP_DIG:
3176 spec->multiout.max_channels = 2;
3177 spec->multiout.num_dacs = 1;
3178 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3179 spec->input_mux = &ad1988_laptop_capture_source;
3180 spec->num_mixers = 1;
3181 spec->mixers[0] = ad1988_laptop_mixers;
3182 spec->inv_eapd = 1; /* inverted EAPD */
3183 spec->num_init_verbs = 1;
3184 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3185 if (board_config == AD1988_LAPTOP_DIG)
3186 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3187 break;
3190 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3191 spec->adc_nids = ad1988_adc_nids;
3192 spec->capsrc_nids = ad1988_capsrc_nids;
3193 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3194 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3195 if (spec->multiout.dig_out_nid) {
3196 if (codec->vendor_id >= 0x11d4989a) {
3197 spec->mixers[spec->num_mixers++] =
3198 ad1989_spdif_out_mixers;
3199 spec->init_verbs[spec->num_init_verbs++] =
3200 ad1989_spdif_init_verbs;
3201 codec->slave_dig_outs = ad1989b_slave_dig_outs;
3202 } else {
3203 spec->mixers[spec->num_mixers++] =
3204 ad1988_spdif_out_mixers;
3205 spec->init_verbs[spec->num_init_verbs++] =
3206 ad1988_spdif_init_verbs;
3209 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
3210 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
3211 spec->init_verbs[spec->num_init_verbs++] =
3212 ad1988_spdif_in_init_verbs;
3215 codec->patch_ops = ad198x_patch_ops;
3216 switch (board_config) {
3217 case AD1988_AUTO:
3218 codec->patch_ops.init = ad1988_auto_init;
3219 break;
3220 case AD1988_LAPTOP:
3221 case AD1988_LAPTOP_DIG:
3222 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3223 break;
3225 #ifdef CONFIG_SND_HDA_POWER_SAVE
3226 spec->loopback.amplist = ad1988_loopbacks;
3227 #endif
3228 spec->vmaster_nid = 0x04;
3230 codec->no_trigger_sense = 1;
3232 return 0;
3237 * AD1884 / AD1984
3239 * port-B - front line/mic-in
3240 * port-E - aux in/out
3241 * port-F - aux in/out
3242 * port-C - rear line/mic-in
3243 * port-D - rear line/hp-out
3244 * port-A - front line/hp-out
3246 * AD1984 = AD1884 + two digital mic-ins
3248 * FIXME:
3249 * For simplicity, we share the single DAC for both HP and line-outs
3250 * right now. The inidividual playbacks could be easily implemented,
3251 * but no build-up framework is given, so far.
3254 static hda_nid_t ad1884_dac_nids[1] = {
3255 0x04,
3258 static hda_nid_t ad1884_adc_nids[2] = {
3259 0x08, 0x09,
3262 static hda_nid_t ad1884_capsrc_nids[2] = {
3263 0x0c, 0x0d,
3266 #define AD1884_SPDIF_OUT 0x02
3268 static struct hda_input_mux ad1884_capture_source = {
3269 .num_items = 4,
3270 .items = {
3271 { "Front Mic", 0x0 },
3272 { "Mic", 0x1 },
3273 { "CD", 0x2 },
3274 { "Mix", 0x3 },
3278 static struct snd_kcontrol_new ad1884_base_mixers[] = {
3279 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3280 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3281 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3282 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3283 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3284 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3285 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3286 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3287 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3288 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3289 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3290 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3291 HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
3292 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3293 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3294 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3295 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3296 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3298 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3299 /* The multiple "Capture Source" controls confuse alsamixer
3300 * So call somewhat different..
3302 /* .name = "Capture Source", */
3303 .name = "Input Source",
3304 .count = 2,
3305 .info = ad198x_mux_enum_info,
3306 .get = ad198x_mux_enum_get,
3307 .put = ad198x_mux_enum_put,
3309 /* SPDIF controls */
3310 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3312 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3313 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3314 /* identical with ad1983 */
3315 .info = ad1983_spdif_route_info,
3316 .get = ad1983_spdif_route_get,
3317 .put = ad1983_spdif_route_put,
3319 { } /* end */
3322 static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3323 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3324 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3325 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
3326 HDA_INPUT),
3327 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
3328 HDA_INPUT),
3329 { } /* end */
3333 * initialization verbs
3335 static struct hda_verb ad1884_init_verbs[] = {
3336 /* DACs; mute as default */
3337 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3338 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3339 /* Port-A (HP) mixer */
3340 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3341 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3342 /* Port-A pin */
3343 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3344 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3345 /* HP selector - select DAC2 */
3346 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3347 /* Port-D (Line-out) mixer */
3348 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3349 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3350 /* Port-D pin */
3351 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3352 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3353 /* Mono-out mixer */
3354 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3355 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3356 /* Mono-out pin */
3357 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3358 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3359 /* Mono selector */
3360 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3361 /* Port-B (front mic) pin */
3362 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3363 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3364 /* Port-C (rear mic) pin */
3365 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3366 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3367 /* Analog mixer; mute as default */
3368 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3369 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3370 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3371 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3372 /* Analog Mix output amp */
3373 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3374 /* SPDIF output selector */
3375 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3376 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3377 { } /* end */
3380 #ifdef CONFIG_SND_HDA_POWER_SAVE
3381 static struct hda_amp_list ad1884_loopbacks[] = {
3382 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3383 { 0x20, HDA_INPUT, 1 }, /* Mic */
3384 { 0x20, HDA_INPUT, 2 }, /* CD */
3385 { 0x20, HDA_INPUT, 4 }, /* Docking */
3386 { } /* end */
3388 #endif
3390 static const char *ad1884_slave_vols[] = {
3391 "PCM Playback Volume",
3392 "Mic Playback Volume",
3393 "Mono Playback Volume",
3394 "Front Mic Playback Volume",
3395 "Mic Playback Volume",
3396 "CD Playback Volume",
3397 "Internal Mic Playback Volume",
3398 "Docking Mic Playback Volume",
3399 /* "Beep Playback Volume", */
3400 "IEC958 Playback Volume",
3401 NULL
3404 static int patch_ad1884(struct hda_codec *codec)
3406 struct ad198x_spec *spec;
3407 int err;
3409 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3410 if (spec == NULL)
3411 return -ENOMEM;
3413 codec->spec = spec;
3415 err = snd_hda_attach_beep_device(codec, 0x10);
3416 if (err < 0) {
3417 ad198x_free(codec);
3418 return err;
3420 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3422 spec->multiout.max_channels = 2;
3423 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3424 spec->multiout.dac_nids = ad1884_dac_nids;
3425 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3426 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3427 spec->adc_nids = ad1884_adc_nids;
3428 spec->capsrc_nids = ad1884_capsrc_nids;
3429 spec->input_mux = &ad1884_capture_source;
3430 spec->num_mixers = 1;
3431 spec->mixers[0] = ad1884_base_mixers;
3432 spec->num_init_verbs = 1;
3433 spec->init_verbs[0] = ad1884_init_verbs;
3434 spec->spdif_route = 0;
3435 #ifdef CONFIG_SND_HDA_POWER_SAVE
3436 spec->loopback.amplist = ad1884_loopbacks;
3437 #endif
3438 spec->vmaster_nid = 0x04;
3439 /* we need to cover all playback volumes */
3440 spec->slave_vols = ad1884_slave_vols;
3442 codec->patch_ops = ad198x_patch_ops;
3444 codec->no_trigger_sense = 1;
3446 return 0;
3450 * Lenovo Thinkpad T61/X61
3452 static struct hda_input_mux ad1984_thinkpad_capture_source = {
3453 .num_items = 4,
3454 .items = {
3455 { "Mic", 0x0 },
3456 { "Internal Mic", 0x1 },
3457 { "Mix", 0x3 },
3458 { "Docking-Station", 0x4 },
3464 * Dell Precision T3400
3466 static struct hda_input_mux ad1984_dell_desktop_capture_source = {
3467 .num_items = 3,
3468 .items = {
3469 { "Front Mic", 0x0 },
3470 { "Line-In", 0x1 },
3471 { "Mix", 0x3 },
3476 static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3477 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3478 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3479 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3480 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3481 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3482 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3483 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3484 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3485 HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3486 HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3487 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3488 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
3489 HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3490 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3491 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3492 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3493 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3495 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3496 /* The multiple "Capture Source" controls confuse alsamixer
3497 * So call somewhat different..
3499 /* .name = "Capture Source", */
3500 .name = "Input Source",
3501 .count = 2,
3502 .info = ad198x_mux_enum_info,
3503 .get = ad198x_mux_enum_get,
3504 .put = ad198x_mux_enum_put,
3506 /* SPDIF controls */
3507 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3509 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3510 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3511 /* identical with ad1983 */
3512 .info = ad1983_spdif_route_info,
3513 .get = ad1983_spdif_route_get,
3514 .put = ad1983_spdif_route_put,
3516 { } /* end */
3519 /* additional verbs */
3520 static struct hda_verb ad1984_thinkpad_init_verbs[] = {
3521 /* Port-E (docking station mic) pin */
3522 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3523 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3524 /* docking mic boost */
3525 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3526 /* Analog mixer - docking mic; mute as default */
3527 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3528 /* enable EAPD bit */
3529 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3530 { } /* end */
3534 * Dell Precision T3400
3536 static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3537 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3538 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3539 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3540 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3541 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3542 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3543 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3544 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3545 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
3546 HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
3547 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3548 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3549 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3550 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3551 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3553 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3554 /* The multiple "Capture Source" controls confuse alsamixer
3555 * So call somewhat different..
3557 /* .name = "Capture Source", */
3558 .name = "Input Source",
3559 .count = 2,
3560 .info = ad198x_mux_enum_info,
3561 .get = ad198x_mux_enum_get,
3562 .put = ad198x_mux_enum_put,
3564 { } /* end */
3567 /* Digial MIC ADC NID 0x05 + 0x06 */
3568 static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3569 struct hda_codec *codec,
3570 unsigned int stream_tag,
3571 unsigned int format,
3572 struct snd_pcm_substream *substream)
3574 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3575 stream_tag, 0, format);
3576 return 0;
3579 static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3580 struct hda_codec *codec,
3581 struct snd_pcm_substream *substream)
3583 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
3584 return 0;
3587 static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3588 .substreams = 2,
3589 .channels_min = 2,
3590 .channels_max = 2,
3591 .nid = 0x05,
3592 .ops = {
3593 .prepare = ad1984_pcm_dmic_prepare,
3594 .cleanup = ad1984_pcm_dmic_cleanup
3598 static int ad1984_build_pcms(struct hda_codec *codec)
3600 struct ad198x_spec *spec = codec->spec;
3601 struct hda_pcm *info;
3602 int err;
3604 err = ad198x_build_pcms(codec);
3605 if (err < 0)
3606 return err;
3608 info = spec->pcm_rec + codec->num_pcms;
3609 codec->num_pcms++;
3610 info->name = "AD1984 Digital Mic";
3611 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3612 return 0;
3615 /* models */
3616 enum {
3617 AD1984_BASIC,
3618 AD1984_THINKPAD,
3619 AD1984_DELL_DESKTOP,
3620 AD1984_MODELS
3623 static const char *ad1984_models[AD1984_MODELS] = {
3624 [AD1984_BASIC] = "basic",
3625 [AD1984_THINKPAD] = "thinkpad",
3626 [AD1984_DELL_DESKTOP] = "dell_desktop",
3629 static struct snd_pci_quirk ad1984_cfg_tbl[] = {
3630 /* Lenovo Thinkpad T61/X61 */
3631 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
3632 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
3636 static int patch_ad1984(struct hda_codec *codec)
3638 struct ad198x_spec *spec;
3639 int board_config, err;
3641 err = patch_ad1884(codec);
3642 if (err < 0)
3643 return err;
3644 spec = codec->spec;
3645 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3646 ad1984_models, ad1984_cfg_tbl);
3647 switch (board_config) {
3648 case AD1984_BASIC:
3649 /* additional digital mics */
3650 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3651 codec->patch_ops.build_pcms = ad1984_build_pcms;
3652 break;
3653 case AD1984_THINKPAD:
3654 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3655 spec->input_mux = &ad1984_thinkpad_capture_source;
3656 spec->mixers[0] = ad1984_thinkpad_mixers;
3657 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
3658 break;
3659 case AD1984_DELL_DESKTOP:
3660 spec->multiout.dig_out_nid = 0;
3661 spec->input_mux = &ad1984_dell_desktop_capture_source;
3662 spec->mixers[0] = ad1984_dell_desktop_mixers;
3663 break;
3665 return 0;
3670 * AD1883 / AD1884A / AD1984A / AD1984B
3672 * port-B (0x14) - front mic-in
3673 * port-E (0x1c) - rear mic-in
3674 * port-F (0x16) - CD / ext out
3675 * port-C (0x15) - rear line-in
3676 * port-D (0x12) - rear line-out
3677 * port-A (0x11) - front hp-out
3679 * AD1984A = AD1884A + digital-mic
3680 * AD1883 = equivalent with AD1984A
3681 * AD1984B = AD1984A + extra SPDIF-out
3683 * FIXME:
3684 * We share the single DAC for both HP and line-outs (see AD1884/1984).
3687 static hda_nid_t ad1884a_dac_nids[1] = {
3688 0x03,
3691 #define ad1884a_adc_nids ad1884_adc_nids
3692 #define ad1884a_capsrc_nids ad1884_capsrc_nids
3694 #define AD1884A_SPDIF_OUT 0x02
3696 static struct hda_input_mux ad1884a_capture_source = {
3697 .num_items = 5,
3698 .items = {
3699 { "Front Mic", 0x0 },
3700 { "Mic", 0x4 },
3701 { "Line", 0x1 },
3702 { "CD", 0x2 },
3703 { "Mix", 0x3 },
3707 static struct snd_kcontrol_new ad1884a_base_mixers[] = {
3708 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3709 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3710 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3711 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3712 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3713 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3714 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3715 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3716 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3717 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3718 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3719 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3720 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3721 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3722 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3723 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3724 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3725 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
3726 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3727 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3728 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3729 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3730 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3732 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3733 /* The multiple "Capture Source" controls confuse alsamixer
3734 * So call somewhat different..
3736 /* .name = "Capture Source", */
3737 .name = "Input Source",
3738 .count = 2,
3739 .info = ad198x_mux_enum_info,
3740 .get = ad198x_mux_enum_get,
3741 .put = ad198x_mux_enum_put,
3743 /* SPDIF controls */
3744 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3746 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3747 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3748 /* identical with ad1983 */
3749 .info = ad1983_spdif_route_info,
3750 .get = ad1983_spdif_route_get,
3751 .put = ad1983_spdif_route_put,
3753 { } /* end */
3757 * initialization verbs
3759 static struct hda_verb ad1884a_init_verbs[] = {
3760 /* DACs; unmute as default */
3761 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3762 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3763 /* Port-A (HP) mixer - route only from analog mixer */
3764 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3765 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3766 /* Port-A pin */
3767 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3768 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3769 /* Port-D (Line-out) mixer - route only from analog mixer */
3770 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3771 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3772 /* Port-D pin */
3773 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3774 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3775 /* Mono-out mixer - route only from analog mixer */
3776 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3777 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3778 /* Mono-out pin */
3779 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3780 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3781 /* Port-B (front mic) pin */
3782 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3783 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3784 /* Port-C (rear line-in) pin */
3785 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3786 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3787 /* Port-E (rear mic) pin */
3788 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3789 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3790 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
3791 /* Port-F (CD) pin */
3792 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3793 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3794 /* Analog mixer; mute as default */
3795 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3796 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3797 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3798 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3799 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
3800 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3801 /* Analog Mix output amp */
3802 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3803 /* capture sources */
3804 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
3805 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3806 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
3807 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3808 /* SPDIF output amp */
3809 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3810 { } /* end */
3813 #ifdef CONFIG_SND_HDA_POWER_SAVE
3814 static struct hda_amp_list ad1884a_loopbacks[] = {
3815 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3816 { 0x20, HDA_INPUT, 1 }, /* Mic */
3817 { 0x20, HDA_INPUT, 2 }, /* CD */
3818 { 0x20, HDA_INPUT, 4 }, /* Docking */
3819 { } /* end */
3821 #endif
3824 * Laptop model
3826 * Port A: Headphone jack
3827 * Port B: MIC jack
3828 * Port C: Internal MIC
3829 * Port D: Dock Line Out (if enabled)
3830 * Port E: Dock Line In (if enabled)
3831 * Port F: Internal speakers
3834 static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
3835 struct snd_ctl_elem_value *ucontrol)
3837 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
3838 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
3839 int mute = (!ucontrol->value.integer.value[0] &&
3840 !ucontrol->value.integer.value[1]);
3841 /* toggle GPIO1 according to the mute state */
3842 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
3843 mute ? 0x02 : 0x0);
3844 return ret;
3847 static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
3848 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3850 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3851 .name = "Master Playback Switch",
3852 .subdevice = HDA_SUBDEV_AMP_FLAG,
3853 .info = snd_hda_mixer_amp_switch_info,
3854 .get = snd_hda_mixer_amp_switch_get,
3855 .put = ad1884a_mobile_master_sw_put,
3856 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3858 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3859 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3860 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3861 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3862 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3863 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3864 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3865 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3866 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3867 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3868 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
3869 HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3870 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3871 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3872 { } /* end */
3875 static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
3876 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3877 /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
3879 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3880 .name = "Master Playback Switch",
3881 .subdevice = HDA_SUBDEV_AMP_FLAG,
3882 .info = snd_hda_mixer_amp_switch_info,
3883 .get = snd_hda_mixer_amp_switch_get,
3884 .put = ad1884a_mobile_master_sw_put,
3885 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
3887 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3888 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3889 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
3890 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
3891 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3892 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3893 { } /* end */
3896 /* mute internal speaker if HP is plugged */
3897 static void ad1884a_hp_automute(struct hda_codec *codec)
3899 unsigned int present;
3901 present = snd_hda_jack_detect(codec, 0x11);
3902 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3903 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3904 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3905 present ? 0x00 : 0x02);
3908 /* switch to external mic if plugged */
3909 static void ad1884a_hp_automic(struct hda_codec *codec)
3911 unsigned int present;
3913 present = snd_hda_jack_detect(codec, 0x14);
3914 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
3915 present ? 0 : 1);
3918 #define AD1884A_HP_EVENT 0x37
3919 #define AD1884A_MIC_EVENT 0x36
3921 /* unsolicited event for HP jack sensing */
3922 static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3924 switch (res >> 26) {
3925 case AD1884A_HP_EVENT:
3926 ad1884a_hp_automute(codec);
3927 break;
3928 case AD1884A_MIC_EVENT:
3929 ad1884a_hp_automic(codec);
3930 break;
3934 /* initialize jack-sensing, too */
3935 static int ad1884a_hp_init(struct hda_codec *codec)
3937 ad198x_init(codec);
3938 ad1884a_hp_automute(codec);
3939 ad1884a_hp_automic(codec);
3940 return 0;
3943 /* mute internal speaker if HP or docking HP is plugged */
3944 static void ad1884a_laptop_automute(struct hda_codec *codec)
3946 unsigned int present;
3948 present = snd_hda_jack_detect(codec, 0x11);
3949 if (!present)
3950 present = snd_hda_jack_detect(codec, 0x12);
3951 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3952 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3953 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3954 present ? 0x00 : 0x02);
3957 /* switch to external mic if plugged */
3958 static void ad1884a_laptop_automic(struct hda_codec *codec)
3960 unsigned int idx;
3962 if (snd_hda_jack_detect(codec, 0x14))
3963 idx = 0;
3964 else if (snd_hda_jack_detect(codec, 0x1c))
3965 idx = 4;
3966 else
3967 idx = 1;
3968 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
3971 /* unsolicited event for HP jack sensing */
3972 static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
3973 unsigned int res)
3975 switch (res >> 26) {
3976 case AD1884A_HP_EVENT:
3977 ad1884a_laptop_automute(codec);
3978 break;
3979 case AD1884A_MIC_EVENT:
3980 ad1884a_laptop_automic(codec);
3981 break;
3985 /* initialize jack-sensing, too */
3986 static int ad1884a_laptop_init(struct hda_codec *codec)
3988 ad198x_init(codec);
3989 ad1884a_laptop_automute(codec);
3990 ad1884a_laptop_automic(codec);
3991 return 0;
3994 /* additional verbs for laptop model */
3995 static struct hda_verb ad1884a_laptop_verbs[] = {
3996 /* Port-A (HP) pin - always unmuted */
3997 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3998 /* Port-F (int speaker) mixer - route only from analog mixer */
3999 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4000 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4001 /* Port-F (int speaker) pin */
4002 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4003 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4004 /* required for compaq 6530s/6531s speaker output */
4005 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4006 /* Port-C pin - internal mic-in */
4007 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4008 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4009 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4010 /* Port-D (docking line-out) pin - default unmuted */
4011 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4012 /* analog mix */
4013 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4014 /* unsolicited event for pin-sense */
4015 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4016 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4017 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4018 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4019 /* allow to touch GPIO1 (for mute control) */
4020 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4021 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4022 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4023 { } /* end */
4026 static struct hda_verb ad1884a_mobile_verbs[] = {
4027 /* DACs; unmute as default */
4028 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4029 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4030 /* Port-A (HP) mixer - route only from analog mixer */
4031 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4032 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4033 /* Port-A pin */
4034 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4035 /* Port-A (HP) pin - always unmuted */
4036 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4037 /* Port-B (mic jack) pin */
4038 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4039 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4040 /* Port-C (int mic) pin */
4041 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4042 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
4043 /* Port-F (int speaker) mixer - route only from analog mixer */
4044 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4045 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4046 /* Port-F pin */
4047 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4048 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4049 /* Analog mixer; mute as default */
4050 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4051 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4052 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4053 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4054 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4055 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4056 /* Analog Mix output amp */
4057 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4058 /* capture sources */
4059 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4060 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4061 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4062 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4063 /* unsolicited event for pin-sense */
4064 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4065 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4066 /* allow to touch GPIO1 (for mute control) */
4067 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4068 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4069 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4070 { } /* end */
4074 * Thinkpad X300
4075 * 0x11 - HP
4076 * 0x12 - speaker
4077 * 0x14 - mic-in
4078 * 0x17 - built-in mic
4081 static struct hda_verb ad1984a_thinkpad_verbs[] = {
4082 /* HP unmute */
4083 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4084 /* analog mix */
4085 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4086 /* turn on EAPD */
4087 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4088 /* unsolicited event for pin-sense */
4089 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4090 /* internal mic - dmic */
4091 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4092 /* set magic COEFs for dmic */
4093 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4094 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4095 { } /* end */
4098 static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
4099 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4100 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4101 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4102 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4103 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4104 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4105 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
4106 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
4107 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4108 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4110 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4111 .name = "Capture Source",
4112 .info = ad198x_mux_enum_info,
4113 .get = ad198x_mux_enum_get,
4114 .put = ad198x_mux_enum_put,
4116 { } /* end */
4119 static struct hda_input_mux ad1984a_thinkpad_capture_source = {
4120 .num_items = 3,
4121 .items = {
4122 { "Mic", 0x0 },
4123 { "Internal Mic", 0x5 },
4124 { "Mix", 0x3 },
4128 /* mute internal speaker if HP is plugged */
4129 static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4131 unsigned int present;
4133 present = snd_hda_jack_detect(codec, 0x11);
4134 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4135 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4138 /* unsolicited event for HP jack sensing */
4139 static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4140 unsigned int res)
4142 if ((res >> 26) != AD1884A_HP_EVENT)
4143 return;
4144 ad1984a_thinkpad_automute(codec);
4147 /* initialize jack-sensing, too */
4148 static int ad1984a_thinkpad_init(struct hda_codec *codec)
4150 ad198x_init(codec);
4151 ad1984a_thinkpad_automute(codec);
4152 return 0;
4156 * HP Touchsmart
4157 * port-A (0x11) - front hp-out
4158 * port-B (0x14) - unused
4159 * port-C (0x15) - unused
4160 * port-D (0x12) - rear line out
4161 * port-E (0x1c) - front mic-in
4162 * port-F (0x16) - Internal speakers
4163 * digital-mic (0x17) - Internal mic
4166 static struct hda_verb ad1984a_touchsmart_verbs[] = {
4167 /* DACs; unmute as default */
4168 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4169 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
4170 /* Port-A (HP) mixer - route only from analog mixer */
4171 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4172 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4173 /* Port-A pin */
4174 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4175 /* Port-A (HP) pin - always unmuted */
4176 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4177 /* Port-E (int speaker) mixer - route only from analog mixer */
4178 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4179 /* Port-E pin */
4180 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4181 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4182 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4183 /* Port-F (int speaker) mixer - route only from analog mixer */
4184 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4185 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4186 /* Port-F pin */
4187 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4188 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4189 /* Analog mixer; mute as default */
4190 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4191 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4192 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4193 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4194 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4195 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4196 /* Analog Mix output amp */
4197 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4198 /* capture sources */
4199 /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */
4200 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4201 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4202 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4203 /* unsolicited event for pin-sense */
4204 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4205 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4206 /* allow to touch GPIO1 (for mute control) */
4207 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4208 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4209 {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */
4210 /* internal mic - dmic */
4211 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4212 /* set magic COEFs for dmic */
4213 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4214 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4215 { } /* end */
4218 static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
4219 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4220 /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/
4222 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4223 .subdevice = HDA_SUBDEV_AMP_FLAG,
4224 .name = "Master Playback Switch",
4225 .info = snd_hda_mixer_amp_switch_info,
4226 .get = snd_hda_mixer_amp_switch_get,
4227 .put = ad1884a_mobile_master_sw_put,
4228 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4230 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4231 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4232 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4233 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4234 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
4235 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
4236 { } /* end */
4239 /* switch to external mic if plugged */
4240 static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4242 if (snd_hda_jack_detect(codec, 0x1c))
4243 snd_hda_codec_write(codec, 0x0c, 0,
4244 AC_VERB_SET_CONNECT_SEL, 0x4);
4245 else
4246 snd_hda_codec_write(codec, 0x0c, 0,
4247 AC_VERB_SET_CONNECT_SEL, 0x5);
4251 /* unsolicited event for HP jack sensing */
4252 static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4253 unsigned int res)
4255 switch (res >> 26) {
4256 case AD1884A_HP_EVENT:
4257 ad1884a_hp_automute(codec);
4258 break;
4259 case AD1884A_MIC_EVENT:
4260 ad1984a_touchsmart_automic(codec);
4261 break;
4265 /* initialize jack-sensing, too */
4266 static int ad1984a_touchsmart_init(struct hda_codec *codec)
4268 ad198x_init(codec);
4269 ad1884a_hp_automute(codec);
4270 ad1984a_touchsmart_automic(codec);
4271 return 0;
4278 enum {
4279 AD1884A_DESKTOP,
4280 AD1884A_LAPTOP,
4281 AD1884A_MOBILE,
4282 AD1884A_THINKPAD,
4283 AD1984A_TOUCHSMART,
4284 AD1884A_MODELS
4287 static const char *ad1884a_models[AD1884A_MODELS] = {
4288 [AD1884A_DESKTOP] = "desktop",
4289 [AD1884A_LAPTOP] = "laptop",
4290 [AD1884A_MOBILE] = "mobile",
4291 [AD1884A_THINKPAD] = "thinkpad",
4292 [AD1984A_TOUCHSMART] = "touchsmart",
4295 static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
4296 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
4297 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
4298 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
4299 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
4300 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
4301 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4302 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
4303 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
4304 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
4305 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
4309 static int patch_ad1884a(struct hda_codec *codec)
4311 struct ad198x_spec *spec;
4312 int err, board_config;
4314 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4315 if (spec == NULL)
4316 return -ENOMEM;
4318 codec->spec = spec;
4320 err = snd_hda_attach_beep_device(codec, 0x10);
4321 if (err < 0) {
4322 ad198x_free(codec);
4323 return err;
4325 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4327 spec->multiout.max_channels = 2;
4328 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4329 spec->multiout.dac_nids = ad1884a_dac_nids;
4330 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4331 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4332 spec->adc_nids = ad1884a_adc_nids;
4333 spec->capsrc_nids = ad1884a_capsrc_nids;
4334 spec->input_mux = &ad1884a_capture_source;
4335 spec->num_mixers = 1;
4336 spec->mixers[0] = ad1884a_base_mixers;
4337 spec->num_init_verbs = 1;
4338 spec->init_verbs[0] = ad1884a_init_verbs;
4339 spec->spdif_route = 0;
4340 #ifdef CONFIG_SND_HDA_POWER_SAVE
4341 spec->loopback.amplist = ad1884a_loopbacks;
4342 #endif
4343 codec->patch_ops = ad198x_patch_ops;
4345 /* override some parameters */
4346 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
4347 ad1884a_models,
4348 ad1884a_cfg_tbl);
4349 switch (board_config) {
4350 case AD1884A_LAPTOP:
4351 spec->mixers[0] = ad1884a_laptop_mixers;
4352 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4353 spec->multiout.dig_out_nid = 0;
4354 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4355 codec->patch_ops.init = ad1884a_laptop_init;
4356 /* set the upper-limit for mixer amp to 0dB for avoiding the
4357 * possible damage by overloading
4359 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4360 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4361 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4362 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4363 (1 << AC_AMPCAP_MUTE_SHIFT));
4364 break;
4365 case AD1884A_MOBILE:
4366 spec->mixers[0] = ad1884a_mobile_mixers;
4367 spec->init_verbs[0] = ad1884a_mobile_verbs;
4368 spec->multiout.dig_out_nid = 0;
4369 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4370 codec->patch_ops.init = ad1884a_hp_init;
4371 /* set the upper-limit for mixer amp to 0dB for avoiding the
4372 * possible damage by overloading
4374 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4375 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4376 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4377 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4378 (1 << AC_AMPCAP_MUTE_SHIFT));
4379 break;
4380 case AD1884A_THINKPAD:
4381 spec->mixers[0] = ad1984a_thinkpad_mixers;
4382 spec->init_verbs[spec->num_init_verbs++] =
4383 ad1984a_thinkpad_verbs;
4384 spec->multiout.dig_out_nid = 0;
4385 spec->input_mux = &ad1984a_thinkpad_capture_source;
4386 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4387 codec->patch_ops.init = ad1984a_thinkpad_init;
4388 break;
4389 case AD1984A_TOUCHSMART:
4390 spec->mixers[0] = ad1984a_touchsmart_mixers;
4391 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4392 spec->multiout.dig_out_nid = 0;
4393 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4394 codec->patch_ops.init = ad1984a_touchsmart_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;
4406 codec->no_trigger_sense = 1;
4408 return 0;
4413 * AD1882 / AD1882A
4415 * port-A - front hp-out
4416 * port-B - front mic-in
4417 * port-C - rear line-in, shared surr-out (3stack)
4418 * port-D - rear line-out
4419 * port-E - rear mic-in, shared clfe-out (3stack)
4420 * port-F - rear surr-out (6stack)
4421 * port-G - rear clfe-out (6stack)
4424 static hda_nid_t ad1882_dac_nids[3] = {
4425 0x04, 0x03, 0x05
4428 static hda_nid_t ad1882_adc_nids[2] = {
4429 0x08, 0x09,
4432 static hda_nid_t ad1882_capsrc_nids[2] = {
4433 0x0c, 0x0d,
4436 #define AD1882_SPDIF_OUT 0x02
4438 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
4439 static struct hda_input_mux ad1882_capture_source = {
4440 .num_items = 5,
4441 .items = {
4442 { "Front Mic", 0x1 },
4443 { "Mic", 0x4 },
4444 { "Line", 0x2 },
4445 { "CD", 0x3 },
4446 { "Mix", 0x7 },
4450 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
4451 static struct hda_input_mux ad1882a_capture_source = {
4452 .num_items = 5,
4453 .items = {
4454 { "Front Mic", 0x1 },
4455 { "Mic", 0x4},
4456 { "Line", 0x2 },
4457 { "Digital Mic", 0x06 },
4458 { "Mix", 0x7 },
4462 static struct snd_kcontrol_new ad1882_base_mixers[] = {
4463 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4464 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4465 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4466 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4467 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4468 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4469 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4470 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
4472 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
4473 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
4474 HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
4475 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4476 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4477 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4478 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4480 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4481 /* The multiple "Capture Source" controls confuse alsamixer
4482 * So call somewhat different..
4484 /* .name = "Capture Source", */
4485 .name = "Input Source",
4486 .count = 2,
4487 .info = ad198x_mux_enum_info,
4488 .get = ad198x_mux_enum_get,
4489 .put = ad198x_mux_enum_put,
4491 /* SPDIF controls */
4492 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4494 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4495 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4496 /* identical with ad1983 */
4497 .info = ad1983_spdif_route_info,
4498 .get = ad1983_spdif_route_get,
4499 .put = ad1983_spdif_route_put,
4501 { } /* end */
4504 static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4505 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4506 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4507 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4508 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4509 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4510 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4511 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4512 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4513 { } /* end */
4516 static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4517 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4518 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4519 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4520 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4521 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4522 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4523 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4524 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4525 HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
4526 { } /* end */
4529 static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4530 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4531 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4532 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4534 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4535 .name = "Channel Mode",
4536 .info = ad198x_ch_mode_info,
4537 .get = ad198x_ch_mode_get,
4538 .put = ad198x_ch_mode_put,
4540 { } /* end */
4543 static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4544 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4545 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4546 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4547 { } /* end */
4550 static struct hda_verb ad1882_ch2_init[] = {
4551 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4552 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4553 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4554 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4555 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4556 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4557 { } /* end */
4560 static struct hda_verb ad1882_ch4_init[] = {
4561 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4562 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4563 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4564 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4565 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4566 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4567 { } /* end */
4570 static struct hda_verb ad1882_ch6_init[] = {
4571 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4572 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4573 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4574 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4575 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4576 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4577 { } /* end */
4580 static struct hda_channel_mode ad1882_modes[3] = {
4581 { 2, ad1882_ch2_init },
4582 { 4, ad1882_ch4_init },
4583 { 6, ad1882_ch6_init },
4587 * initialization verbs
4589 static struct hda_verb ad1882_init_verbs[] = {
4590 /* DACs; mute as default */
4591 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4592 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4593 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4594 /* Port-A (HP) mixer */
4595 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4596 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4597 /* Port-A pin */
4598 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4599 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4600 /* HP selector - select DAC2 */
4601 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4602 /* Port-D (Line-out) mixer */
4603 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4604 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4605 /* Port-D pin */
4606 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4607 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4608 /* Mono-out mixer */
4609 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4610 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4611 /* Mono-out pin */
4612 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4613 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4614 /* Port-B (front mic) pin */
4615 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4616 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4617 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4618 /* Port-C (line-in) pin */
4619 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4620 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4621 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4622 /* Port-C mixer - mute as input */
4623 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4624 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4625 /* Port-E (mic-in) pin */
4626 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4627 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4628 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4629 /* Port-E mixer - mute as input */
4630 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4631 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4632 /* Port-F (surround) */
4633 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4634 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4635 /* Port-G (CLFE) */
4636 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4637 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4638 /* Analog mixer; mute as default */
4639 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
4640 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4641 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4642 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4643 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4644 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4645 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4646 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4647 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4648 /* Analog Mix output amp */
4649 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
4650 /* SPDIF output selector */
4651 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4652 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
4653 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4654 { } /* end */
4657 #ifdef CONFIG_SND_HDA_POWER_SAVE
4658 static struct hda_amp_list ad1882_loopbacks[] = {
4659 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4660 { 0x20, HDA_INPUT, 1 }, /* Mic */
4661 { 0x20, HDA_INPUT, 4 }, /* Line */
4662 { 0x20, HDA_INPUT, 6 }, /* CD */
4663 { } /* end */
4665 #endif
4667 /* models */
4668 enum {
4669 AD1882_3STACK,
4670 AD1882_6STACK,
4671 AD1882_MODELS
4674 static const char *ad1882_models[AD1986A_MODELS] = {
4675 [AD1882_3STACK] = "3stack",
4676 [AD1882_6STACK] = "6stack",
4680 static int patch_ad1882(struct hda_codec *codec)
4682 struct ad198x_spec *spec;
4683 int err, board_config;
4685 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4686 if (spec == NULL)
4687 return -ENOMEM;
4689 codec->spec = spec;
4691 err = snd_hda_attach_beep_device(codec, 0x10);
4692 if (err < 0) {
4693 ad198x_free(codec);
4694 return err;
4696 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4698 spec->multiout.max_channels = 6;
4699 spec->multiout.num_dacs = 3;
4700 spec->multiout.dac_nids = ad1882_dac_nids;
4701 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
4702 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
4703 spec->adc_nids = ad1882_adc_nids;
4704 spec->capsrc_nids = ad1882_capsrc_nids;
4705 if (codec->vendor_id == 0x11d41882)
4706 spec->input_mux = &ad1882_capture_source;
4707 else
4708 spec->input_mux = &ad1882a_capture_source;
4709 spec->num_mixers = 2;
4710 spec->mixers[0] = ad1882_base_mixers;
4711 if (codec->vendor_id == 0x11d41882)
4712 spec->mixers[1] = ad1882_loopback_mixers;
4713 else
4714 spec->mixers[1] = ad1882a_loopback_mixers;
4715 spec->num_init_verbs = 1;
4716 spec->init_verbs[0] = ad1882_init_verbs;
4717 spec->spdif_route = 0;
4718 #ifdef CONFIG_SND_HDA_POWER_SAVE
4719 spec->loopback.amplist = ad1882_loopbacks;
4720 #endif
4721 spec->vmaster_nid = 0x04;
4723 codec->patch_ops = ad198x_patch_ops;
4725 /* override some parameters */
4726 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
4727 ad1882_models, NULL);
4728 switch (board_config) {
4729 default:
4730 case AD1882_3STACK:
4731 spec->num_mixers = 3;
4732 spec->mixers[2] = ad1882_3stack_mixers;
4733 spec->channel_mode = ad1882_modes;
4734 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
4735 spec->need_dac_fix = 1;
4736 spec->multiout.max_channels = 2;
4737 spec->multiout.num_dacs = 1;
4738 break;
4739 case AD1882_6STACK:
4740 spec->num_mixers = 3;
4741 spec->mixers[2] = ad1882_6stack_mixers;
4742 break;
4745 codec->no_trigger_sense = 1;
4747 return 0;
4752 * patch entries
4754 static struct hda_codec_preset snd_hda_preset_analog[] = {
4755 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
4756 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
4757 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
4758 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
4759 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
4760 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
4761 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
4762 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
4763 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
4764 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
4765 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
4766 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
4767 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
4768 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
4769 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
4770 {} /* terminator */
4773 MODULE_ALIAS("snd-hda-codec-id:11d4*");
4775 MODULE_LICENSE("GPL");
4776 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
4778 static struct hda_codec_preset_list analog_list = {
4779 .preset = snd_hda_preset_analog,
4780 .owner = THIS_MODULE,
4783 static int __init patch_analog_init(void)
4785 return snd_hda_add_codec_preset(&analog_list);
4788 static void __exit patch_analog_exit(void)
4790 snd_hda_delete_codec_preset(&analog_list);
4793 module_init(patch_analog_init)
4794 module_exit(patch_analog_exit)