rt2x00 : more devices to rt73usb.c
[firewire-audio.git] / sound / pci / hda / patch_analog.c
blobe48612323aa0f11facf58c1d9df107bca5fa3692
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"
31 struct ad198x_spec {
32 struct snd_kcontrol_new *mixers[5];
33 int num_mixers;
35 const struct hda_verb *init_verbs[5]; /* initialization verbs
36 * don't forget NULL termination!
38 unsigned int num_init_verbs;
40 /* playback */
41 struct hda_multi_out multiout; /* playback set-up
42 * max_channels, dacs must be set
43 * dig_out_nid and hp_nid are optional
45 unsigned int cur_eapd;
46 unsigned int need_dac_fix;
48 /* capture */
49 unsigned int num_adc_nids;
50 hda_nid_t *adc_nids;
51 hda_nid_t dig_in_nid; /* digital-in NID; optional */
53 /* capture source */
54 const struct hda_input_mux *input_mux;
55 hda_nid_t *capsrc_nids;
56 unsigned int cur_mux[3];
58 /* channel model */
59 const struct hda_channel_mode *channel_mode;
60 int num_channel_mode;
62 /* PCM information */
63 struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */
65 unsigned int spdif_route;
67 /* dynamic controls, init_verbs and input_mux */
68 struct auto_pin_cfg autocfg;
69 struct snd_array kctls;
70 struct hda_input_mux private_imux;
71 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
73 unsigned int jack_present :1;
75 #ifdef CONFIG_SND_HDA_POWER_SAVE
76 struct hda_loopback_check loopback;
77 #endif
78 /* for virtual master */
79 hda_nid_t vmaster_nid;
80 const char **slave_vols;
81 const char **slave_sws;
85 * input MUX handling (common part)
87 static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
89 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
90 struct ad198x_spec *spec = codec->spec;
92 return snd_hda_input_mux_info(spec->input_mux, uinfo);
95 static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
97 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
98 struct ad198x_spec *spec = codec->spec;
99 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
101 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
102 return 0;
105 static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
107 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
108 struct ad198x_spec *spec = codec->spec;
109 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
111 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
112 spec->capsrc_nids[adc_idx],
113 &spec->cur_mux[adc_idx]);
117 * initialization (common callbacks)
119 static int ad198x_init(struct hda_codec *codec)
121 struct ad198x_spec *spec = codec->spec;
122 int i;
124 for (i = 0; i < spec->num_init_verbs; i++)
125 snd_hda_sequence_write(codec, spec->init_verbs[i]);
126 return 0;
129 static const char *ad_slave_vols[] = {
130 "Front Playback Volume",
131 "Surround Playback Volume",
132 "Center Playback Volume",
133 "LFE Playback Volume",
134 "Side Playback Volume",
135 "Headphone Playback Volume",
136 "Mono Playback Volume",
137 "Speaker Playback Volume",
138 "IEC958 Playback Volume",
139 NULL
142 static const char *ad_slave_sws[] = {
143 "Front Playback Switch",
144 "Surround Playback Switch",
145 "Center Playback Switch",
146 "LFE Playback Switch",
147 "Side Playback Switch",
148 "Headphone Playback Switch",
149 "Mono Playback Switch",
150 "Speaker Playback Switch",
151 "IEC958 Playback Switch",
152 NULL
155 static void ad198x_free_kctls(struct hda_codec *codec);
157 static int ad198x_build_controls(struct hda_codec *codec)
159 struct ad198x_spec *spec = codec->spec;
160 unsigned int i;
161 int err;
163 for (i = 0; i < spec->num_mixers; i++) {
164 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
165 if (err < 0)
166 return err;
168 if (spec->multiout.dig_out_nid) {
169 err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid);
170 if (err < 0)
171 return err;
172 err = snd_hda_create_spdif_share_sw(codec,
173 &spec->multiout);
174 if (err < 0)
175 return err;
176 spec->multiout.share_spdif = 1;
178 if (spec->dig_in_nid) {
179 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
180 if (err < 0)
181 return err;
184 /* if we have no master control, let's create it */
185 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
186 unsigned int vmaster_tlv[4];
187 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
188 HDA_OUTPUT, vmaster_tlv);
189 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
190 vmaster_tlv,
191 (spec->slave_vols ?
192 spec->slave_vols : ad_slave_vols));
193 if (err < 0)
194 return err;
196 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
197 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
198 NULL,
199 (spec->slave_sws ?
200 spec->slave_sws : ad_slave_sws));
201 if (err < 0)
202 return err;
205 ad198x_free_kctls(codec); /* no longer needed */
206 return 0;
209 #ifdef CONFIG_SND_HDA_POWER_SAVE
210 static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
212 struct ad198x_spec *spec = codec->spec;
213 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
215 #endif
218 * Analog playback callbacks
220 static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
221 struct hda_codec *codec,
222 struct snd_pcm_substream *substream)
224 struct ad198x_spec *spec = codec->spec;
225 return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
226 hinfo);
229 static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
230 struct hda_codec *codec,
231 unsigned int stream_tag,
232 unsigned int format,
233 struct snd_pcm_substream *substream)
235 struct ad198x_spec *spec = codec->spec;
236 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
237 format, substream);
240 static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
241 struct hda_codec *codec,
242 struct snd_pcm_substream *substream)
244 struct ad198x_spec *spec = codec->spec;
245 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
249 * Digital out
251 static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
252 struct hda_codec *codec,
253 struct snd_pcm_substream *substream)
255 struct ad198x_spec *spec = codec->spec;
256 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
259 static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
260 struct hda_codec *codec,
261 struct snd_pcm_substream *substream)
263 struct ad198x_spec *spec = codec->spec;
264 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
267 static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
268 struct hda_codec *codec,
269 unsigned int stream_tag,
270 unsigned int format,
271 struct snd_pcm_substream *substream)
273 struct ad198x_spec *spec = codec->spec;
274 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
275 format, substream);
278 static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
279 struct hda_codec *codec,
280 struct snd_pcm_substream *substream)
282 struct ad198x_spec *spec = codec->spec;
283 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
287 * Analog capture
289 static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
290 struct hda_codec *codec,
291 unsigned int stream_tag,
292 unsigned int format,
293 struct snd_pcm_substream *substream)
295 struct ad198x_spec *spec = codec->spec;
296 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
297 stream_tag, 0, format);
298 return 0;
301 static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
302 struct hda_codec *codec,
303 struct snd_pcm_substream *substream)
305 struct ad198x_spec *spec = codec->spec;
306 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
307 return 0;
313 static struct hda_pcm_stream ad198x_pcm_analog_playback = {
314 .substreams = 1,
315 .channels_min = 2,
316 .channels_max = 6, /* changed later */
317 .nid = 0, /* fill later */
318 .ops = {
319 .open = ad198x_playback_pcm_open,
320 .prepare = ad198x_playback_pcm_prepare,
321 .cleanup = ad198x_playback_pcm_cleanup
325 static struct hda_pcm_stream ad198x_pcm_analog_capture = {
326 .substreams = 1,
327 .channels_min = 2,
328 .channels_max = 2,
329 .nid = 0, /* fill later */
330 .ops = {
331 .prepare = ad198x_capture_pcm_prepare,
332 .cleanup = ad198x_capture_pcm_cleanup
336 static struct hda_pcm_stream ad198x_pcm_digital_playback = {
337 .substreams = 1,
338 .channels_min = 2,
339 .channels_max = 2,
340 .nid = 0, /* fill later */
341 .ops = {
342 .open = ad198x_dig_playback_pcm_open,
343 .close = ad198x_dig_playback_pcm_close,
344 .prepare = ad198x_dig_playback_pcm_prepare,
345 .cleanup = ad198x_dig_playback_pcm_cleanup
349 static struct hda_pcm_stream ad198x_pcm_digital_capture = {
350 .substreams = 1,
351 .channels_min = 2,
352 .channels_max = 2,
353 /* NID is set in alc_build_pcms */
356 static int ad198x_build_pcms(struct hda_codec *codec)
358 struct ad198x_spec *spec = codec->spec;
359 struct hda_pcm *info = spec->pcm_rec;
361 codec->num_pcms = 1;
362 codec->pcm_info = info;
364 info->name = "AD198x Analog";
365 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
366 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
367 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
368 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
369 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
370 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
372 if (spec->multiout.dig_out_nid) {
373 info++;
374 codec->num_pcms++;
375 info->name = "AD198x Digital";
376 info->pcm_type = HDA_PCM_TYPE_SPDIF;
377 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
378 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
379 if (spec->dig_in_nid) {
380 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
381 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
385 return 0;
388 static void ad198x_free_kctls(struct hda_codec *codec)
390 struct ad198x_spec *spec = codec->spec;
392 if (spec->kctls.list) {
393 struct snd_kcontrol_new *kctl = spec->kctls.list;
394 int i;
395 for (i = 0; i < spec->kctls.used; i++)
396 kfree(kctl[i].name);
398 snd_array_free(&spec->kctls);
401 static void ad198x_free(struct hda_codec *codec)
403 struct ad198x_spec *spec = codec->spec;
405 if (!spec)
406 return;
408 ad198x_free_kctls(codec);
409 kfree(codec->spec);
412 static struct hda_codec_ops ad198x_patch_ops = {
413 .build_controls = ad198x_build_controls,
414 .build_pcms = ad198x_build_pcms,
415 .init = ad198x_init,
416 .free = ad198x_free,
417 #ifdef CONFIG_SND_HDA_POWER_SAVE
418 .check_power_status = ad198x_check_power_status,
419 #endif
424 * EAPD control
425 * the private value = nid | (invert << 8)
427 #define ad198x_eapd_info snd_ctl_boolean_mono_info
429 static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
430 struct snd_ctl_elem_value *ucontrol)
432 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
433 struct ad198x_spec *spec = codec->spec;
434 int invert = (kcontrol->private_value >> 8) & 1;
435 if (invert)
436 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
437 else
438 ucontrol->value.integer.value[0] = spec->cur_eapd;
439 return 0;
442 static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
443 struct snd_ctl_elem_value *ucontrol)
445 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
446 struct ad198x_spec *spec = codec->spec;
447 int invert = (kcontrol->private_value >> 8) & 1;
448 hda_nid_t nid = kcontrol->private_value & 0xff;
449 unsigned int eapd;
450 eapd = !!ucontrol->value.integer.value[0];
451 if (invert)
452 eapd = !eapd;
453 if (eapd == spec->cur_eapd)
454 return 0;
455 spec->cur_eapd = eapd;
456 snd_hda_codec_write_cache(codec, nid,
457 0, AC_VERB_SET_EAPD_BTLENABLE,
458 eapd ? 0x02 : 0x00);
459 return 1;
462 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
463 struct snd_ctl_elem_info *uinfo);
464 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
465 struct snd_ctl_elem_value *ucontrol);
466 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
467 struct snd_ctl_elem_value *ucontrol);
471 * AD1986A specific
474 #define AD1986A_SPDIF_OUT 0x02
475 #define AD1986A_FRONT_DAC 0x03
476 #define AD1986A_SURR_DAC 0x04
477 #define AD1986A_CLFE_DAC 0x05
478 #define AD1986A_ADC 0x06
480 static hda_nid_t ad1986a_dac_nids[3] = {
481 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
483 static hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
484 static hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
486 static struct hda_input_mux ad1986a_capture_source = {
487 .num_items = 7,
488 .items = {
489 { "Mic", 0x0 },
490 { "CD", 0x1 },
491 { "Aux", 0x3 },
492 { "Line", 0x4 },
493 { "Mix", 0x5 },
494 { "Mono", 0x6 },
495 { "Phone", 0x7 },
500 static struct hda_bind_ctls ad1986a_bind_pcm_vol = {
501 .ops = &snd_hda_bind_vol,
502 .values = {
503 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
504 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
505 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
510 static struct hda_bind_ctls ad1986a_bind_pcm_sw = {
511 .ops = &snd_hda_bind_sw,
512 .values = {
513 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
514 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
515 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
521 * mixers
523 static struct snd_kcontrol_new ad1986a_mixers[] = {
525 * bind volumes/mutes of 3 DACs as a single PCM control for simplicity
527 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
528 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
529 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
530 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
531 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
532 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
533 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
534 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
535 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
536 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
537 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
538 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
539 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
540 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
541 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
542 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
543 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
544 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
545 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
546 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
547 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
548 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
549 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
550 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
551 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
552 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
553 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
555 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
556 .name = "Capture Source",
557 .info = ad198x_mux_enum_info,
558 .get = ad198x_mux_enum_get,
559 .put = ad198x_mux_enum_put,
561 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
562 { } /* end */
565 /* additional mixers for 3stack mode */
566 static struct snd_kcontrol_new ad1986a_3st_mixers[] = {
568 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
569 .name = "Channel Mode",
570 .info = ad198x_ch_mode_info,
571 .get = ad198x_ch_mode_get,
572 .put = ad198x_ch_mode_put,
574 { } /* end */
577 /* laptop model - 2ch only */
578 static hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
580 /* master controls both pins 0x1a and 0x1b */
581 static struct hda_bind_ctls ad1986a_laptop_master_vol = {
582 .ops = &snd_hda_bind_vol,
583 .values = {
584 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
585 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
590 static struct hda_bind_ctls ad1986a_laptop_master_sw = {
591 .ops = &snd_hda_bind_sw,
592 .values = {
593 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
594 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
599 static struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
600 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
601 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
602 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
603 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
604 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
605 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
606 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
607 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
608 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
609 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
610 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
611 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
612 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
613 /* HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x18, 0x0, HDA_OUTPUT),
614 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x18, 0x0, HDA_OUTPUT),
615 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
616 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */
617 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
618 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
620 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
621 .name = "Capture Source",
622 .info = ad198x_mux_enum_info,
623 .get = ad198x_mux_enum_get,
624 .put = ad198x_mux_enum_put,
626 { } /* end */
629 /* laptop-eapd model - 2ch only */
631 static struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
632 .num_items = 3,
633 .items = {
634 { "Mic", 0x0 },
635 { "Internal Mic", 0x4 },
636 { "Mix", 0x5 },
640 static struct hda_input_mux ad1986a_automic_capture_source = {
641 .num_items = 2,
642 .items = {
643 { "Mic", 0x0 },
644 { "Mix", 0x5 },
648 static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
649 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
650 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
651 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
652 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
653 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
654 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
655 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
656 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
657 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
658 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
659 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
661 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
662 .name = "Capture Source",
663 .info = ad198x_mux_enum_info,
664 .get = ad198x_mux_enum_get,
665 .put = ad198x_mux_enum_put,
668 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
669 .name = "External Amplifier",
670 .info = ad198x_eapd_info,
671 .get = ad198x_eapd_get,
672 .put = ad198x_eapd_put,
673 .private_value = 0x1b | (1 << 8), /* port-D, inversed */
675 { } /* end */
678 static struct snd_kcontrol_new ad1986a_samsung_mixers[] = {
679 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
680 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
681 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
682 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
683 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
684 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
685 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
686 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
687 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
689 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
690 .name = "Capture Source",
691 .info = ad198x_mux_enum_info,
692 .get = ad198x_mux_enum_get,
693 .put = ad198x_mux_enum_put,
696 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
697 .name = "External Amplifier",
698 .info = ad198x_eapd_info,
699 .get = ad198x_eapd_get,
700 .put = ad198x_eapd_put,
701 .private_value = 0x1b | (1 << 8), /* port-D, inversed */
703 { } /* end */
706 /* re-connect the mic boost input according to the jack sensing */
707 static void ad1986a_automic(struct hda_codec *codec)
709 unsigned int present;
710 present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0);
711 /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */
712 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
713 (present & AC_PINSENSE_PRESENCE) ? 0 : 2);
716 #define AD1986A_MIC_EVENT 0x36
718 static void ad1986a_automic_unsol_event(struct hda_codec *codec,
719 unsigned int res)
721 if ((res >> 26) != AD1986A_MIC_EVENT)
722 return;
723 ad1986a_automic(codec);
726 static int ad1986a_automic_init(struct hda_codec *codec)
728 ad198x_init(codec);
729 ad1986a_automic(codec);
730 return 0;
733 /* laptop-automute - 2ch only */
735 static void ad1986a_update_hp(struct hda_codec *codec)
737 struct ad198x_spec *spec = codec->spec;
738 unsigned int mute;
740 if (spec->jack_present)
741 mute = HDA_AMP_MUTE; /* mute internal speaker */
742 else
743 /* unmute internal speaker if necessary */
744 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
745 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
746 HDA_AMP_MUTE, mute);
749 static void ad1986a_hp_automute(struct hda_codec *codec)
751 struct ad198x_spec *spec = codec->spec;
752 unsigned int present;
754 present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0);
755 /* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
756 spec->jack_present = !(present & 0x80000000);
757 ad1986a_update_hp(codec);
760 #define AD1986A_HP_EVENT 0x37
762 static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
764 if ((res >> 26) != AD1986A_HP_EVENT)
765 return;
766 ad1986a_hp_automute(codec);
769 static int ad1986a_hp_init(struct hda_codec *codec)
771 ad198x_init(codec);
772 ad1986a_hp_automute(codec);
773 return 0;
776 /* bind hp and internal speaker mute (with plug check) */
777 static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
778 struct snd_ctl_elem_value *ucontrol)
780 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
781 long *valp = ucontrol->value.integer.value;
782 int change;
784 change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
785 HDA_AMP_MUTE,
786 valp[0] ? 0 : HDA_AMP_MUTE);
787 change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
788 HDA_AMP_MUTE,
789 valp[1] ? 0 : HDA_AMP_MUTE);
790 if (change)
791 ad1986a_update_hp(codec);
792 return change;
795 static struct snd_kcontrol_new ad1986a_laptop_automute_mixers[] = {
796 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
798 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
799 .name = "Master Playback Switch",
800 .info = snd_hda_mixer_amp_switch_info,
801 .get = snd_hda_mixer_amp_switch_get,
802 .put = ad1986a_hp_master_sw_put,
803 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
805 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
806 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
807 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x0, HDA_OUTPUT),
808 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x0, HDA_OUTPUT),
809 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
810 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
811 HDA_CODEC_VOLUME("Mic Boost", 0x0f, 0x0, HDA_OUTPUT),
812 HDA_CODEC_VOLUME("Beep Playback Volume", 0x18, 0x0, HDA_OUTPUT),
813 HDA_CODEC_MUTE("Beep Playback Switch", 0x18, 0x0, HDA_OUTPUT),
814 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
815 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
817 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
818 .name = "Capture Source",
819 .info = ad198x_mux_enum_info,
820 .get = ad198x_mux_enum_get,
821 .put = ad198x_mux_enum_put,
824 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
825 .name = "External Amplifier",
826 .info = ad198x_eapd_info,
827 .get = ad198x_eapd_get,
828 .put = ad198x_eapd_put,
829 .private_value = 0x1b | (1 << 8), /* port-D, inversed */
831 { } /* end */
835 * initialization verbs
837 static struct hda_verb ad1986a_init_verbs[] = {
838 /* Front, Surround, CLFE DAC; mute as default */
839 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
840 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
841 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
842 /* Downmix - off */
843 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
844 /* HP, Line-Out, Surround, CLFE selectors */
845 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
846 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
847 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
848 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
849 /* Mono selector */
850 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
851 /* Mic selector: Mic 1/2 pin */
852 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
853 /* Line-in selector: Line-in */
854 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
855 /* Mic 1/2 swap */
856 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
857 /* Record selector: mic */
858 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
859 /* Mic, Phone, CD, Aux, Line-In amp; mute as default */
860 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
861 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
862 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
863 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
864 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
865 /* PC beep */
866 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
867 /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */
868 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
869 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
870 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
871 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
872 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
873 /* HP Pin */
874 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
875 /* Front, Surround, CLFE Pins */
876 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
877 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
878 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
879 /* Mono Pin */
880 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
881 /* Mic Pin */
882 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
883 /* Line, Aux, CD, Beep-In Pin */
884 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
885 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
886 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
887 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
888 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
889 { } /* end */
892 static struct hda_verb ad1986a_ch2_init[] = {
893 /* Surround out -> Line In */
894 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
895 /* Line-in selectors */
896 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
897 /* CLFE -> Mic in */
898 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
899 /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */
900 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
901 { } /* end */
904 static struct hda_verb ad1986a_ch4_init[] = {
905 /* Surround out -> Surround */
906 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
907 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
908 /* CLFE -> Mic in */
909 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
910 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
911 { } /* end */
914 static struct hda_verb ad1986a_ch6_init[] = {
915 /* Surround out -> Surround out */
916 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
917 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
918 /* CLFE -> CLFE */
919 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
920 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
921 { } /* end */
924 static struct hda_channel_mode ad1986a_modes[3] = {
925 { 2, ad1986a_ch2_init },
926 { 4, ad1986a_ch4_init },
927 { 6, ad1986a_ch6_init },
930 /* eapd initialization */
931 static struct hda_verb ad1986a_eapd_init_verbs[] = {
932 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
936 static struct hda_verb ad1986a_automic_verbs[] = {
937 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
938 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
939 /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/
940 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
941 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
945 /* Ultra initialization */
946 static struct hda_verb ad1986a_ultra_init[] = {
947 /* eapd initialization */
948 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
949 /* CLFE -> Mic in */
950 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
951 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
952 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
953 { } /* end */
956 /* pin sensing on HP jack */
957 static struct hda_verb ad1986a_hp_init_verbs[] = {
958 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
963 /* models */
964 enum {
965 AD1986A_6STACK,
966 AD1986A_3STACK,
967 AD1986A_LAPTOP,
968 AD1986A_LAPTOP_EAPD,
969 AD1986A_LAPTOP_AUTOMUTE,
970 AD1986A_ULTRA,
971 AD1986A_SAMSUNG,
972 AD1986A_MODELS
975 static const char *ad1986a_models[AD1986A_MODELS] = {
976 [AD1986A_6STACK] = "6stack",
977 [AD1986A_3STACK] = "3stack",
978 [AD1986A_LAPTOP] = "laptop",
979 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
980 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
981 [AD1986A_ULTRA] = "ultra",
982 [AD1986A_SAMSUNG] = "samsung",
985 static struct snd_pci_quirk ad1986a_cfg_tbl[] = {
986 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
987 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
988 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
989 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
990 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
991 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
992 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
993 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
994 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
995 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
996 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
997 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
998 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
999 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1000 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
1001 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
1002 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba", AD1986A_LAPTOP_EAPD),
1003 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
1004 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
1005 SND_PCI_QUIRK(0x144d, 0xc023, "Samsung X60", AD1986A_SAMSUNG),
1006 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung R65", AD1986A_SAMSUNG),
1007 SND_PCI_QUIRK(0x144d, 0xc026, "Samsung X11", AD1986A_SAMSUNG),
1008 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
1009 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
1010 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
1011 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
1012 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
1013 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
1017 #ifdef CONFIG_SND_HDA_POWER_SAVE
1018 static struct hda_amp_list ad1986a_loopbacks[] = {
1019 { 0x13, HDA_OUTPUT, 0 }, /* Mic */
1020 { 0x14, HDA_OUTPUT, 0 }, /* Phone */
1021 { 0x15, HDA_OUTPUT, 0 }, /* CD */
1022 { 0x16, HDA_OUTPUT, 0 }, /* Aux */
1023 { 0x17, HDA_OUTPUT, 0 }, /* Line */
1024 { } /* end */
1026 #endif
1028 static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1030 unsigned int conf = snd_hda_codec_read(codec, nid, 0,
1031 AC_VERB_GET_CONFIG_DEFAULT, 0);
1032 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1035 static int patch_ad1986a(struct hda_codec *codec)
1037 struct ad198x_spec *spec;
1038 int board_config;
1040 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1041 if (spec == NULL)
1042 return -ENOMEM;
1044 codec->spec = spec;
1046 spec->multiout.max_channels = 6;
1047 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1048 spec->multiout.dac_nids = ad1986a_dac_nids;
1049 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
1050 spec->num_adc_nids = 1;
1051 spec->adc_nids = ad1986a_adc_nids;
1052 spec->capsrc_nids = ad1986a_capsrc_nids;
1053 spec->input_mux = &ad1986a_capture_source;
1054 spec->num_mixers = 1;
1055 spec->mixers[0] = ad1986a_mixers;
1056 spec->num_init_verbs = 1;
1057 spec->init_verbs[0] = ad1986a_init_verbs;
1058 #ifdef CONFIG_SND_HDA_POWER_SAVE
1059 spec->loopback.amplist = ad1986a_loopbacks;
1060 #endif
1061 spec->vmaster_nid = 0x1b;
1063 codec->patch_ops = ad198x_patch_ops;
1065 /* override some parameters */
1066 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1067 ad1986a_models,
1068 ad1986a_cfg_tbl);
1069 switch (board_config) {
1070 case AD1986A_3STACK:
1071 spec->num_mixers = 2;
1072 spec->mixers[1] = ad1986a_3st_mixers;
1073 spec->num_init_verbs = 2;
1074 spec->init_verbs[1] = ad1986a_ch2_init;
1075 spec->channel_mode = ad1986a_modes;
1076 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
1077 spec->need_dac_fix = 1;
1078 spec->multiout.max_channels = 2;
1079 spec->multiout.num_dacs = 1;
1080 break;
1081 case AD1986A_LAPTOP:
1082 spec->mixers[0] = ad1986a_laptop_mixers;
1083 spec->multiout.max_channels = 2;
1084 spec->multiout.num_dacs = 1;
1085 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1086 break;
1087 case AD1986A_LAPTOP_EAPD:
1088 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1089 spec->num_init_verbs = 2;
1090 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1091 spec->multiout.max_channels = 2;
1092 spec->multiout.num_dacs = 1;
1093 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1094 if (!is_jack_available(codec, 0x25))
1095 spec->multiout.dig_out_nid = 0;
1096 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1097 break;
1098 case AD1986A_SAMSUNG:
1099 spec->mixers[0] = ad1986a_samsung_mixers;
1100 spec->num_init_verbs = 3;
1101 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1102 spec->init_verbs[2] = ad1986a_automic_verbs;
1103 spec->multiout.max_channels = 2;
1104 spec->multiout.num_dacs = 1;
1105 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1106 if (!is_jack_available(codec, 0x25))
1107 spec->multiout.dig_out_nid = 0;
1108 spec->input_mux = &ad1986a_automic_capture_source;
1109 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1110 codec->patch_ops.init = ad1986a_automic_init;
1111 break;
1112 case AD1986A_LAPTOP_AUTOMUTE:
1113 spec->mixers[0] = ad1986a_laptop_automute_mixers;
1114 spec->num_init_verbs = 3;
1115 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1116 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1117 spec->multiout.max_channels = 2;
1118 spec->multiout.num_dacs = 1;
1119 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1120 if (!is_jack_available(codec, 0x25))
1121 spec->multiout.dig_out_nid = 0;
1122 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1123 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1124 codec->patch_ops.init = ad1986a_hp_init;
1125 break;
1126 case AD1986A_ULTRA:
1127 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1128 spec->num_init_verbs = 2;
1129 spec->init_verbs[1] = ad1986a_ultra_init;
1130 spec->multiout.max_channels = 2;
1131 spec->multiout.num_dacs = 1;
1132 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1133 spec->multiout.dig_out_nid = 0;
1134 break;
1137 /* AD1986A has a hardware problem that it can't share a stream
1138 * with multiple output pins. The copy of front to surrounds
1139 * causes noisy or silent outputs at a certain timing, e.g.
1140 * changing the volume.
1141 * So, let's disable the shared stream.
1143 spec->multiout.no_share_stream = 1;
1145 return 0;
1149 * AD1983 specific
1152 #define AD1983_SPDIF_OUT 0x02
1153 #define AD1983_DAC 0x03
1154 #define AD1983_ADC 0x04
1156 static hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
1157 static hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
1158 static hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
1160 static struct hda_input_mux ad1983_capture_source = {
1161 .num_items = 4,
1162 .items = {
1163 { "Mic", 0x0 },
1164 { "Line", 0x1 },
1165 { "Mix", 0x2 },
1166 { "Mix Mono", 0x3 },
1171 * SPDIF playback route
1173 static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1175 static char *texts[] = { "PCM", "ADC" };
1177 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1178 uinfo->count = 1;
1179 uinfo->value.enumerated.items = 2;
1180 if (uinfo->value.enumerated.item > 1)
1181 uinfo->value.enumerated.item = 1;
1182 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1183 return 0;
1186 static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1188 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1189 struct ad198x_spec *spec = codec->spec;
1191 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1192 return 0;
1195 static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1197 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1198 struct ad198x_spec *spec = codec->spec;
1200 if (ucontrol->value.enumerated.item[0] > 1)
1201 return -EINVAL;
1202 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1203 spec->spdif_route = ucontrol->value.enumerated.item[0];
1204 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1205 AC_VERB_SET_CONNECT_SEL,
1206 spec->spdif_route);
1207 return 1;
1209 return 0;
1212 static struct snd_kcontrol_new ad1983_mixers[] = {
1213 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1214 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1215 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1216 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1217 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1218 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1219 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1220 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1221 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1222 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1223 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1224 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1225 HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x10, 1, 0x0, HDA_OUTPUT),
1226 HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x10, 1, 0x0, HDA_OUTPUT),
1227 HDA_CODEC_VOLUME("Mic Boost", 0x0c, 0x0, HDA_OUTPUT),
1228 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1229 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1231 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1232 .name = "Capture Source",
1233 .info = ad198x_mux_enum_info,
1234 .get = ad198x_mux_enum_get,
1235 .put = ad198x_mux_enum_put,
1238 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1239 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1240 .info = ad1983_spdif_route_info,
1241 .get = ad1983_spdif_route_get,
1242 .put = ad1983_spdif_route_put,
1244 { } /* end */
1247 static struct hda_verb ad1983_init_verbs[] = {
1248 /* Front, HP, Mono; mute as default */
1249 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1250 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1251 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1252 /* Beep, PCM, Mic, Line-In: mute */
1253 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1254 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1255 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1256 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1257 /* Front, HP selectors; from Mix */
1258 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1259 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1260 /* Mono selector; from Mix */
1261 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1262 /* Mic selector; Mic */
1263 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1264 /* Line-in selector: Line-in */
1265 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1266 /* Mic boost: 0dB */
1267 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1268 /* Record selector: mic */
1269 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1270 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1271 /* SPDIF route: PCM */
1272 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1273 /* Front Pin */
1274 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1275 /* HP Pin */
1276 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1277 /* Mono Pin */
1278 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1279 /* Mic Pin */
1280 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1281 /* Line Pin */
1282 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1283 { } /* end */
1286 #ifdef CONFIG_SND_HDA_POWER_SAVE
1287 static struct hda_amp_list ad1983_loopbacks[] = {
1288 { 0x12, HDA_OUTPUT, 0 }, /* Mic */
1289 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1290 { } /* end */
1292 #endif
1294 static int patch_ad1983(struct hda_codec *codec)
1296 struct ad198x_spec *spec;
1298 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1299 if (spec == NULL)
1300 return -ENOMEM;
1302 codec->spec = spec;
1304 spec->multiout.max_channels = 2;
1305 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1306 spec->multiout.dac_nids = ad1983_dac_nids;
1307 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
1308 spec->num_adc_nids = 1;
1309 spec->adc_nids = ad1983_adc_nids;
1310 spec->capsrc_nids = ad1983_capsrc_nids;
1311 spec->input_mux = &ad1983_capture_source;
1312 spec->num_mixers = 1;
1313 spec->mixers[0] = ad1983_mixers;
1314 spec->num_init_verbs = 1;
1315 spec->init_verbs[0] = ad1983_init_verbs;
1316 spec->spdif_route = 0;
1317 #ifdef CONFIG_SND_HDA_POWER_SAVE
1318 spec->loopback.amplist = ad1983_loopbacks;
1319 #endif
1320 spec->vmaster_nid = 0x05;
1322 codec->patch_ops = ad198x_patch_ops;
1324 return 0;
1329 * AD1981 HD specific
1332 #define AD1981_SPDIF_OUT 0x02
1333 #define AD1981_DAC 0x03
1334 #define AD1981_ADC 0x04
1336 static hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
1337 static hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
1338 static hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
1340 /* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */
1341 static struct hda_input_mux ad1981_capture_source = {
1342 .num_items = 7,
1343 .items = {
1344 { "Front Mic", 0x0 },
1345 { "Line", 0x1 },
1346 { "Mix", 0x2 },
1347 { "Mix Mono", 0x3 },
1348 { "CD", 0x4 },
1349 { "Mic", 0x6 },
1350 { "Aux", 0x7 },
1354 static struct snd_kcontrol_new ad1981_mixers[] = {
1355 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1356 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1357 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1358 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1359 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1360 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1361 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1362 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1363 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1364 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1365 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1366 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1367 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1368 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1369 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1370 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1371 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1372 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1373 HDA_CODEC_VOLUME_MONO("PC Speaker Playback Volume", 0x0d, 1, 0x0, HDA_OUTPUT),
1374 HDA_CODEC_MUTE_MONO("PC Speaker Playback Switch", 0x0d, 1, 0x0, HDA_OUTPUT),
1375 HDA_CODEC_VOLUME("Front Mic Boost", 0x08, 0x0, HDA_INPUT),
1376 HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x0, HDA_INPUT),
1377 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1378 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1380 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1381 .name = "Capture Source",
1382 .info = ad198x_mux_enum_info,
1383 .get = ad198x_mux_enum_get,
1384 .put = ad198x_mux_enum_put,
1386 /* identical with AD1983 */
1388 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1389 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1390 .info = ad1983_spdif_route_info,
1391 .get = ad1983_spdif_route_get,
1392 .put = ad1983_spdif_route_put,
1394 { } /* end */
1397 static struct hda_verb ad1981_init_verbs[] = {
1398 /* Front, HP, Mono; mute as default */
1399 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1400 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1401 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1402 /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */
1403 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1404 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1405 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1406 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1407 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1408 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1409 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1410 /* Front, HP selectors; from Mix */
1411 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1412 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1413 /* Mono selector; from Mix */
1414 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1415 /* Mic Mixer; select Front Mic */
1416 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1417 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1418 /* Mic boost: 0dB */
1419 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1420 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1421 /* Record selector: Front mic */
1422 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1423 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1424 /* SPDIF route: PCM */
1425 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1426 /* Front Pin */
1427 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1428 /* HP Pin */
1429 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1430 /* Mono Pin */
1431 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1432 /* Front & Rear Mic Pins */
1433 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1434 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1435 /* Line Pin */
1436 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1437 /* Digital Beep */
1438 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1439 /* Line-Out as Input: disabled */
1440 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1441 { } /* end */
1444 #ifdef CONFIG_SND_HDA_POWER_SAVE
1445 static struct hda_amp_list ad1981_loopbacks[] = {
1446 { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */
1447 { 0x13, HDA_OUTPUT, 0 }, /* Line */
1448 { 0x1b, HDA_OUTPUT, 0 }, /* Aux */
1449 { 0x1c, HDA_OUTPUT, 0 }, /* Mic */
1450 { 0x1d, HDA_OUTPUT, 0 }, /* CD */
1451 { } /* end */
1453 #endif
1456 * Patch for HP nx6320
1458 * nx6320 uses EAPD in the reverse way - EAPD-on means the internal
1459 * speaker output enabled _and_ mute-LED off.
1462 #define AD1981_HP_EVENT 0x37
1463 #define AD1981_MIC_EVENT 0x38
1465 static struct hda_verb ad1981_hp_init_verbs[] = {
1466 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */
1467 /* pin sensing on HP and Mic jacks */
1468 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1469 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1473 /* turn on/off EAPD (+ mute HP) as a master switch */
1474 static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1475 struct snd_ctl_elem_value *ucontrol)
1477 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1478 struct ad198x_spec *spec = codec->spec;
1480 if (! ad198x_eapd_put(kcontrol, ucontrol))
1481 return 0;
1482 /* change speaker pin appropriately */
1483 snd_hda_codec_write(codec, 0x05, 0,
1484 AC_VERB_SET_PIN_WIDGET_CONTROL,
1485 spec->cur_eapd ? PIN_OUT : 0);
1486 /* toggle HP mute appropriately */
1487 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1488 HDA_AMP_MUTE,
1489 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
1490 return 1;
1493 /* bind volumes of both NID 0x05 and 0x06 */
1494 static struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1495 .ops = &snd_hda_bind_vol,
1496 .values = {
1497 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1498 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1503 /* mute internal speaker if HP is plugged */
1504 static void ad1981_hp_automute(struct hda_codec *codec)
1506 unsigned int present;
1508 present = snd_hda_codec_read(codec, 0x06, 0,
1509 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1510 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1511 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1514 /* toggle input of built-in and mic jack appropriately */
1515 static void ad1981_hp_automic(struct hda_codec *codec)
1517 static struct hda_verb mic_jack_on[] = {
1518 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1519 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1522 static struct hda_verb mic_jack_off[] = {
1523 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1524 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1527 unsigned int present;
1529 present = snd_hda_codec_read(codec, 0x08, 0,
1530 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
1531 if (present)
1532 snd_hda_sequence_write(codec, mic_jack_on);
1533 else
1534 snd_hda_sequence_write(codec, mic_jack_off);
1537 /* unsolicited event for HP jack sensing */
1538 static void ad1981_hp_unsol_event(struct hda_codec *codec,
1539 unsigned int res)
1541 res >>= 26;
1542 switch (res) {
1543 case AD1981_HP_EVENT:
1544 ad1981_hp_automute(codec);
1545 break;
1546 case AD1981_MIC_EVENT:
1547 ad1981_hp_automic(codec);
1548 break;
1552 static struct hda_input_mux ad1981_hp_capture_source = {
1553 .num_items = 3,
1554 .items = {
1555 { "Mic", 0x0 },
1556 { "Docking-Station", 0x1 },
1557 { "Mix", 0x2 },
1561 static struct snd_kcontrol_new ad1981_hp_mixers[] = {
1562 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
1564 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1565 .name = "Master Playback Switch",
1566 .info = ad198x_eapd_info,
1567 .get = ad198x_eapd_get,
1568 .put = ad1981_hp_master_sw_put,
1569 .private_value = 0x05,
1571 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1572 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1573 #if 0
1574 /* FIXME: analog mic/line loopback doesn't work with my tests...
1575 * (although recording is OK)
1577 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1578 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1579 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1580 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1581 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1582 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1583 /* FIXME: does this laptop have analog CD connection? */
1584 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1585 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1586 #endif
1587 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1588 HDA_CODEC_VOLUME("Internal Mic Boost", 0x18, 0x0, HDA_INPUT),
1589 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1590 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1592 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1593 .name = "Capture Source",
1594 .info = ad198x_mux_enum_info,
1595 .get = ad198x_mux_enum_get,
1596 .put = ad198x_mux_enum_put,
1598 { } /* end */
1601 /* initialize jack-sensing, too */
1602 static int ad1981_hp_init(struct hda_codec *codec)
1604 ad198x_init(codec);
1605 ad1981_hp_automute(codec);
1606 ad1981_hp_automic(codec);
1607 return 0;
1610 /* configuration for Toshiba Laptops */
1611 static struct hda_verb ad1981_toshiba_init_verbs[] = {
1612 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */
1613 /* pin sensing on HP and Mic jacks */
1614 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1615 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1619 static struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1620 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1621 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1625 /* configuration for Lenovo Thinkpad T60 */
1626 static struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1627 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1628 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1629 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1630 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1631 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1632 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1633 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1634 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1635 HDA_CODEC_VOLUME("Mic Boost", 0x08, 0x0, HDA_INPUT),
1636 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1637 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1639 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1640 .name = "Capture Source",
1641 .info = ad198x_mux_enum_info,
1642 .get = ad198x_mux_enum_get,
1643 .put = ad198x_mux_enum_put,
1645 /* identical with AD1983 */
1647 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1648 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1649 .info = ad1983_spdif_route_info,
1650 .get = ad1983_spdif_route_get,
1651 .put = ad1983_spdif_route_put,
1653 { } /* end */
1656 static struct hda_input_mux ad1981_thinkpad_capture_source = {
1657 .num_items = 3,
1658 .items = {
1659 { "Mic", 0x0 },
1660 { "Mix", 0x2 },
1661 { "CD", 0x4 },
1665 /* models */
1666 enum {
1667 AD1981_BASIC,
1668 AD1981_HP,
1669 AD1981_THINKPAD,
1670 AD1981_TOSHIBA,
1671 AD1981_MODELS
1674 static const char *ad1981_models[AD1981_MODELS] = {
1675 [AD1981_HP] = "hp",
1676 [AD1981_THINKPAD] = "thinkpad",
1677 [AD1981_BASIC] = "basic",
1678 [AD1981_TOSHIBA] = "toshiba"
1681 static struct snd_pci_quirk ad1981_cfg_tbl[] = {
1682 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
1683 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
1684 /* All HP models */
1685 SND_PCI_QUIRK(0x103c, 0, "HP nx", AD1981_HP),
1686 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
1687 /* Lenovo Thinkpad T60/X60/Z6xx */
1688 SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1981_THINKPAD),
1689 /* HP nx6320 (reversed SSID, H/W bug) */
1690 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
1694 static int patch_ad1981(struct hda_codec *codec)
1696 struct ad198x_spec *spec;
1697 int board_config;
1699 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1700 if (spec == NULL)
1701 return -ENOMEM;
1703 codec->spec = spec;
1705 spec->multiout.max_channels = 2;
1706 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
1707 spec->multiout.dac_nids = ad1981_dac_nids;
1708 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
1709 spec->num_adc_nids = 1;
1710 spec->adc_nids = ad1981_adc_nids;
1711 spec->capsrc_nids = ad1981_capsrc_nids;
1712 spec->input_mux = &ad1981_capture_source;
1713 spec->num_mixers = 1;
1714 spec->mixers[0] = ad1981_mixers;
1715 spec->num_init_verbs = 1;
1716 spec->init_verbs[0] = ad1981_init_verbs;
1717 spec->spdif_route = 0;
1718 #ifdef CONFIG_SND_HDA_POWER_SAVE
1719 spec->loopback.amplist = ad1981_loopbacks;
1720 #endif
1721 spec->vmaster_nid = 0x05;
1723 codec->patch_ops = ad198x_patch_ops;
1725 /* override some parameters */
1726 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
1727 ad1981_models,
1728 ad1981_cfg_tbl);
1729 switch (board_config) {
1730 case AD1981_HP:
1731 spec->mixers[0] = ad1981_hp_mixers;
1732 spec->num_init_verbs = 2;
1733 spec->init_verbs[1] = ad1981_hp_init_verbs;
1734 spec->multiout.dig_out_nid = 0;
1735 spec->input_mux = &ad1981_hp_capture_source;
1737 codec->patch_ops.init = ad1981_hp_init;
1738 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1739 break;
1740 case AD1981_THINKPAD:
1741 spec->mixers[0] = ad1981_thinkpad_mixers;
1742 spec->input_mux = &ad1981_thinkpad_capture_source;
1743 break;
1744 case AD1981_TOSHIBA:
1745 spec->mixers[0] = ad1981_hp_mixers;
1746 spec->mixers[1] = ad1981_toshiba_mixers;
1747 spec->num_init_verbs = 2;
1748 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
1749 spec->multiout.dig_out_nid = 0;
1750 spec->input_mux = &ad1981_hp_capture_source;
1751 codec->patch_ops.init = ad1981_hp_init;
1752 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
1753 break;
1755 return 0;
1760 * AD1988
1762 * Output pins and routes
1764 * Pin Mix Sel DAC (*)
1765 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
1766 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
1767 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
1768 * port-D 0x12 (mute/hp) <- 0x29 <- 04
1769 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
1770 * port-F 0x16 (mute) <- 0x2a <- 06
1771 * port-G 0x24 (mute) <- 0x27 <- 05
1772 * port-H 0x25 (mute) <- 0x28 <- 0a
1773 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
1775 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
1776 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
1778 * Input pins and routes
1780 * pin boost mix input # / adc input #
1781 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
1782 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
1783 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
1784 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
1785 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
1786 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
1787 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
1788 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
1791 * DAC assignment
1792 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
1793 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
1795 * Inputs of Analog Mix (0x20)
1796 * 0:Port-B (front mic)
1797 * 1:Port-C/G/H (line-in)
1798 * 2:Port-A
1799 * 3:Port-D (line-in/2)
1800 * 4:Port-E/G/H (mic-in)
1801 * 5:Port-F (mic2-in)
1802 * 6:CD
1803 * 7:Beep
1805 * ADC selection
1806 * 0:Port-A
1807 * 1:Port-B (front mic-in)
1808 * 2:Port-C (line-in)
1809 * 3:Port-F (mic2-in)
1810 * 4:Port-E (mic-in)
1811 * 5:CD
1812 * 6:Port-G
1813 * 7:Port-H
1814 * 8:Port-D (line-in/2)
1815 * 9:Mix
1817 * Proposed pin assignments by the datasheet
1819 * 6-stack
1820 * Port-A front headphone
1821 * B front mic-in
1822 * C rear line-in
1823 * D rear front-out
1824 * E rear mic-in
1825 * F rear surround
1826 * G rear CLFE
1827 * H rear side
1829 * 3-stack
1830 * Port-A front headphone
1831 * B front mic
1832 * C rear line-in/surround
1833 * D rear front-out
1834 * E rear mic-in/CLFE
1836 * laptop
1837 * Port-A headphone
1838 * B mic-in
1839 * C docking station
1840 * D internal speaker (with EAPD)
1841 * E/F quad mic array
1845 /* models */
1846 enum {
1847 AD1988_6STACK,
1848 AD1988_6STACK_DIG,
1849 AD1988_3STACK,
1850 AD1988_3STACK_DIG,
1851 AD1988_LAPTOP,
1852 AD1988_LAPTOP_DIG,
1853 AD1988_AUTO,
1854 AD1988_MODEL_LAST,
1857 /* reivision id to check workarounds */
1858 #define AD1988A_REV2 0x100200
1860 #define is_rev2(codec) \
1861 ((codec)->vendor_id == 0x11d41988 && \
1862 (codec)->revision_id == AD1988A_REV2)
1865 * mixers
1868 static hda_nid_t ad1988_6stack_dac_nids[4] = {
1869 0x04, 0x06, 0x05, 0x0a
1872 static hda_nid_t ad1988_3stack_dac_nids[3] = {
1873 0x04, 0x05, 0x0a
1876 /* for AD1988A revision-2, DAC2-4 are swapped */
1877 static hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
1878 0x04, 0x05, 0x0a, 0x06
1881 static hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
1882 0x04, 0x0a, 0x06
1885 static hda_nid_t ad1988_adc_nids[3] = {
1886 0x08, 0x09, 0x0f
1889 static hda_nid_t ad1988_capsrc_nids[3] = {
1890 0x0c, 0x0d, 0x0e
1893 #define AD1988_SPDIF_OUT 0x02
1894 #define AD1988_SPDIF_OUT_HDMI 0x0b
1895 #define AD1988_SPDIF_IN 0x07
1897 static hda_nid_t ad1989b_slave_dig_outs[] = {
1898 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
1901 static struct hda_input_mux ad1988_6stack_capture_source = {
1902 .num_items = 5,
1903 .items = {
1904 { "Front Mic", 0x1 }, /* port-B */
1905 { "Line", 0x2 }, /* port-C */
1906 { "Mic", 0x4 }, /* port-E */
1907 { "CD", 0x5 },
1908 { "Mix", 0x9 },
1912 static struct hda_input_mux ad1988_laptop_capture_source = {
1913 .num_items = 3,
1914 .items = {
1915 { "Mic/Line", 0x1 }, /* port-B */
1916 { "CD", 0x5 },
1917 { "Mix", 0x9 },
1923 static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
1924 struct snd_ctl_elem_info *uinfo)
1926 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1927 struct ad198x_spec *spec = codec->spec;
1928 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
1929 spec->num_channel_mode);
1932 static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
1933 struct snd_ctl_elem_value *ucontrol)
1935 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1936 struct ad198x_spec *spec = codec->spec;
1937 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
1938 spec->num_channel_mode, spec->multiout.max_channels);
1941 static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
1942 struct snd_ctl_elem_value *ucontrol)
1944 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1945 struct ad198x_spec *spec = codec->spec;
1946 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
1947 spec->num_channel_mode,
1948 &spec->multiout.max_channels);
1949 if (err >= 0 && spec->need_dac_fix)
1950 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
1951 return err;
1954 /* 6-stack mode */
1955 static struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
1956 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
1957 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1958 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
1959 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
1960 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
1961 { } /* end */
1964 static struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
1965 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
1966 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1967 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
1968 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
1969 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1970 { } /* end */
1973 static struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
1974 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
1975 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
1976 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
1977 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
1978 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
1979 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
1980 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
1982 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
1983 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
1984 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
1985 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
1986 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
1987 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
1988 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
1989 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
1991 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
1992 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
1994 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
1995 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
1997 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
1998 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2000 { } /* end */
2003 /* 3-stack mode */
2004 static struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
2005 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2006 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2007 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2008 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2009 { } /* end */
2012 static struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2013 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2014 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2015 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2016 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
2017 { } /* end */
2020 static struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
2021 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2022 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2023 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2024 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
2025 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2026 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2028 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2029 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2030 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2031 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2032 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2033 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2034 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2035 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2037 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
2038 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
2040 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2041 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2043 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2044 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
2046 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2047 .name = "Channel Mode",
2048 .info = ad198x_ch_mode_info,
2049 .get = ad198x_ch_mode_get,
2050 .put = ad198x_ch_mode_put,
2053 { } /* end */
2056 /* laptop mode */
2057 static struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2058 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2059 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2060 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2062 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2063 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2064 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2065 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2066 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2067 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2069 HDA_CODEC_VOLUME("Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
2070 HDA_CODEC_MUTE("Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
2072 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2073 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2075 HDA_CODEC_VOLUME("Mic Boost", 0x39, 0x0, HDA_OUTPUT),
2078 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2079 .name = "External Amplifier",
2080 .info = ad198x_eapd_info,
2081 .get = ad198x_eapd_get,
2082 .put = ad198x_eapd_put,
2083 .private_value = 0x12 | (1 << 8), /* port-D, inversed */
2086 { } /* end */
2089 /* capture */
2090 static struct snd_kcontrol_new ad1988_capture_mixers[] = {
2091 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2092 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2093 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2094 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2095 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2096 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2098 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2099 /* The multiple "Capture Source" controls confuse alsamixer
2100 * So call somewhat different..
2102 /* .name = "Capture Source", */
2103 .name = "Input Source",
2104 .count = 3,
2105 .info = ad198x_mux_enum_info,
2106 .get = ad198x_mux_enum_get,
2107 .put = ad198x_mux_enum_put,
2109 { } /* end */
2112 static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2113 struct snd_ctl_elem_info *uinfo)
2115 static char *texts[] = {
2116 "PCM", "ADC1", "ADC2", "ADC3"
2118 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2119 uinfo->count = 1;
2120 uinfo->value.enumerated.items = 4;
2121 if (uinfo->value.enumerated.item >= 4)
2122 uinfo->value.enumerated.item = 3;
2123 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2124 return 0;
2127 static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2128 struct snd_ctl_elem_value *ucontrol)
2130 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2131 unsigned int sel;
2133 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2134 AC_AMP_GET_INPUT);
2135 if (!(sel & 0x80))
2136 ucontrol->value.enumerated.item[0] = 0;
2137 else {
2138 sel = snd_hda_codec_read(codec, 0x0b, 0,
2139 AC_VERB_GET_CONNECT_SEL, 0);
2140 if (sel < 3)
2141 sel++;
2142 else
2143 sel = 0;
2144 ucontrol->value.enumerated.item[0] = sel;
2146 return 0;
2149 static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2150 struct snd_ctl_elem_value *ucontrol)
2152 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2153 unsigned int val, sel;
2154 int change;
2156 val = ucontrol->value.enumerated.item[0];
2157 if (val > 3)
2158 return -EINVAL;
2159 if (!val) {
2160 sel = snd_hda_codec_read(codec, 0x1d, 0,
2161 AC_VERB_GET_AMP_GAIN_MUTE,
2162 AC_AMP_GET_INPUT);
2163 change = sel & 0x80;
2164 if (change) {
2165 snd_hda_codec_write_cache(codec, 0x1d, 0,
2166 AC_VERB_SET_AMP_GAIN_MUTE,
2167 AMP_IN_UNMUTE(0));
2168 snd_hda_codec_write_cache(codec, 0x1d, 0,
2169 AC_VERB_SET_AMP_GAIN_MUTE,
2170 AMP_IN_MUTE(1));
2172 } else {
2173 sel = snd_hda_codec_read(codec, 0x1d, 0,
2174 AC_VERB_GET_AMP_GAIN_MUTE,
2175 AC_AMP_GET_INPUT | 0x01);
2176 change = sel & 0x80;
2177 if (change) {
2178 snd_hda_codec_write_cache(codec, 0x1d, 0,
2179 AC_VERB_SET_AMP_GAIN_MUTE,
2180 AMP_IN_MUTE(0));
2181 snd_hda_codec_write_cache(codec, 0x1d, 0,
2182 AC_VERB_SET_AMP_GAIN_MUTE,
2183 AMP_IN_UNMUTE(1));
2185 sel = snd_hda_codec_read(codec, 0x0b, 0,
2186 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2187 change |= sel != val;
2188 if (change)
2189 snd_hda_codec_write_cache(codec, 0x0b, 0,
2190 AC_VERB_SET_CONNECT_SEL,
2191 val - 1);
2193 return change;
2196 static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2197 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2199 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2200 .name = "IEC958 Playback Source",
2201 .info = ad1988_spdif_playback_source_info,
2202 .get = ad1988_spdif_playback_source_get,
2203 .put = ad1988_spdif_playback_source_put,
2205 { } /* end */
2208 static struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2209 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2210 { } /* end */
2213 static struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2214 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2215 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2216 { } /* end */
2220 * initialization verbs
2224 * for 6-stack (+dig)
2226 static struct hda_verb ad1988_6stack_init_verbs[] = {
2227 /* Front, Surround, CLFE, side DAC; unmute as default */
2228 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2229 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2230 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2231 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2232 /* Port-A front headphon path */
2233 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2234 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2235 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2236 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2237 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2238 /* Port-D line-out path */
2239 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2240 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2241 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2242 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2243 /* Port-F surround path */
2244 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2245 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2246 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2247 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2248 /* Port-G CLFE path */
2249 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2250 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2251 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2252 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2253 /* Port-H side path */
2254 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2255 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2256 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2257 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2258 /* Mono out path */
2259 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2260 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2261 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2262 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2263 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2264 /* Port-B front mic-in path */
2265 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2266 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2267 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2268 /* Port-C line-in path */
2269 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2270 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2271 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2272 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2273 /* Port-E mic-in path */
2274 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2275 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2276 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2277 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2278 /* Analog CD Input */
2279 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2280 /* Analog Mix output amp */
2281 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2286 static struct hda_verb ad1988_capture_init_verbs[] = {
2287 /* mute analog mix */
2288 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2289 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2290 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2291 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2292 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2293 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2294 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2295 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2296 /* select ADCs - front-mic */
2297 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2298 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2299 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2300 /* ADCs; muted */
2301 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2302 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2303 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2308 static struct hda_verb ad1988_spdif_init_verbs[] = {
2309 /* SPDIF out sel */
2310 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
2311 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */
2312 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2313 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2314 /* SPDIF out pin */
2315 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2320 /* AD1989 has no ADC -> SPDIF route */
2321 static struct hda_verb ad1989_spdif_init_verbs[] = {
2322 /* SPDIF-1 out pin */
2323 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2324 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2325 /* SPDIF-2/HDMI out pin */
2326 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2327 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
2332 * verbs for 3stack (+dig)
2334 static struct hda_verb ad1988_3stack_ch2_init[] = {
2335 /* set port-C to line-in */
2336 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2337 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2338 /* set port-E to mic-in */
2339 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2340 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2341 { } /* end */
2344 static struct hda_verb ad1988_3stack_ch6_init[] = {
2345 /* set port-C to surround out */
2346 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2347 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2348 /* set port-E to CLFE out */
2349 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2350 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2351 { } /* end */
2354 static struct hda_channel_mode ad1988_3stack_modes[2] = {
2355 { 2, ad1988_3stack_ch2_init },
2356 { 6, ad1988_3stack_ch6_init },
2359 static struct hda_verb ad1988_3stack_init_verbs[] = {
2360 /* Front, Surround, CLFE, side DAC; unmute as default */
2361 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2362 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2363 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2364 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2365 /* Port-A front headphon path */
2366 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2367 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2368 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2369 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2370 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2371 /* Port-D line-out path */
2372 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2373 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2374 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2375 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2376 /* Mono out path */
2377 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2378 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2379 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2380 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2381 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2382 /* Port-B front mic-in path */
2383 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2384 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2385 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2386 /* Port-C line-in/surround path - 6ch mode as default */
2387 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2388 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2389 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2390 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */
2391 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2392 /* Port-E mic-in/CLFE path - 6ch mode as default */
2393 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2394 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2395 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2396 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */
2397 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2398 /* mute analog mix */
2399 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2400 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2401 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2402 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2403 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2404 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2405 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2406 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2407 /* select ADCs - front-mic */
2408 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2409 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2410 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2411 /* ADCs; muted */
2412 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2413 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2414 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2415 /* Analog Mix output amp */
2416 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2421 * verbs for laptop mode (+dig)
2423 static struct hda_verb ad1988_laptop_hp_on[] = {
2424 /* unmute port-A and mute port-D */
2425 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2426 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2427 { } /* end */
2429 static struct hda_verb ad1988_laptop_hp_off[] = {
2430 /* mute port-A and unmute port-D */
2431 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2432 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2433 { } /* end */
2436 #define AD1988_HP_EVENT 0x01
2438 static struct hda_verb ad1988_laptop_init_verbs[] = {
2439 /* Front, Surround, CLFE, side DAC; unmute as default */
2440 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2441 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2442 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2443 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2444 /* Port-A front headphon path */
2445 {0x37, AC_VERB_SET_CONNECT_SEL, 0x01}, /* DAC1:04h */
2446 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2447 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2448 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2449 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2450 /* unsolicited event for pin-sense */
2451 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2452 /* Port-D line-out path + EAPD */
2453 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2454 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2455 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2456 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2457 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */
2458 /* Mono out path */
2459 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */
2460 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2461 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2462 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2463 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */
2464 /* Port-B mic-in path */
2465 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2466 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2467 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2468 /* Port-C docking station - try to output */
2469 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2470 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2471 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2472 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2473 /* mute analog mix */
2474 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2475 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2476 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2477 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2478 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2479 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2480 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2481 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2482 /* select ADCs - mic */
2483 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2484 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2485 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2486 /* ADCs; muted */
2487 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2488 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2489 {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2490 /* Analog Mix output amp */
2491 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
2495 static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2497 if ((res >> 26) != AD1988_HP_EVENT)
2498 return;
2499 if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31))
2500 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2501 else
2502 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2505 #ifdef CONFIG_SND_HDA_POWER_SAVE
2506 static struct hda_amp_list ad1988_loopbacks[] = {
2507 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
2508 { 0x20, HDA_INPUT, 1 }, /* Line */
2509 { 0x20, HDA_INPUT, 4 }, /* Mic */
2510 { 0x20, HDA_INPUT, 6 }, /* CD */
2511 { } /* end */
2513 #endif
2516 * Automatic parse of I/O pins from the BIOS configuration
2519 enum {
2520 AD_CTL_WIDGET_VOL,
2521 AD_CTL_WIDGET_MUTE,
2522 AD_CTL_BIND_MUTE,
2524 static struct snd_kcontrol_new ad1988_control_templates[] = {
2525 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2526 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2527 HDA_BIND_MUTE(NULL, 0, 0, 0),
2530 /* add dynamic controls */
2531 static int add_control(struct ad198x_spec *spec, int type, const char *name,
2532 unsigned long val)
2534 struct snd_kcontrol_new *knew;
2536 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2537 knew = snd_array_new(&spec->kctls);
2538 if (!knew)
2539 return -ENOMEM;
2540 *knew = ad1988_control_templates[type];
2541 knew->name = kstrdup(name, GFP_KERNEL);
2542 if (! knew->name)
2543 return -ENOMEM;
2544 knew->private_value = val;
2545 return 0;
2548 #define AD1988_PIN_CD_NID 0x18
2549 #define AD1988_PIN_BEEP_NID 0x10
2551 static hda_nid_t ad1988_mixer_nids[8] = {
2552 /* A B C D E F G H */
2553 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
2556 static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
2558 static hda_nid_t idx_to_dac[8] = {
2559 /* A B C D E F G H */
2560 0x04, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
2562 static hda_nid_t idx_to_dac_rev2[8] = {
2563 /* A B C D E F G H */
2564 0x04, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
2566 if (is_rev2(codec))
2567 return idx_to_dac_rev2[idx];
2568 else
2569 return idx_to_dac[idx];
2572 static hda_nid_t ad1988_boost_nids[8] = {
2573 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
2576 static int ad1988_pin_idx(hda_nid_t nid)
2578 static hda_nid_t ad1988_io_pins[8] = {
2579 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
2581 int i;
2582 for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)
2583 if (ad1988_io_pins[i] == nid)
2584 return i;
2585 return 0; /* should be -1 */
2588 static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
2590 static int loopback_idx[8] = {
2591 2, 0, 1, 3, 4, 5, 1, 4
2593 switch (nid) {
2594 case AD1988_PIN_CD_NID:
2595 return 6;
2596 default:
2597 return loopback_idx[ad1988_pin_idx(nid)];
2601 static int ad1988_pin_to_adc_idx(hda_nid_t nid)
2603 static int adc_idx[8] = {
2604 0, 1, 2, 8, 4, 3, 6, 7
2606 switch (nid) {
2607 case AD1988_PIN_CD_NID:
2608 return 5;
2609 default:
2610 return adc_idx[ad1988_pin_idx(nid)];
2614 /* fill in the dac_nids table from the parsed pin configuration */
2615 static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
2616 const struct auto_pin_cfg *cfg)
2618 struct ad198x_spec *spec = codec->spec;
2619 int i, idx;
2621 spec->multiout.dac_nids = spec->private_dac_nids;
2623 /* check the pins hardwired to audio widget */
2624 for (i = 0; i < cfg->line_outs; i++) {
2625 idx = ad1988_pin_idx(cfg->line_out_pins[i]);
2626 spec->multiout.dac_nids[i] = ad1988_idx_to_dac(codec, idx);
2628 spec->multiout.num_dacs = cfg->line_outs;
2629 return 0;
2632 /* add playback controls from the parsed DAC table */
2633 static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
2634 const struct auto_pin_cfg *cfg)
2636 char name[32];
2637 static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" };
2638 hda_nid_t nid;
2639 int i, err;
2641 for (i = 0; i < cfg->line_outs; i++) {
2642 hda_nid_t dac = spec->multiout.dac_nids[i];
2643 if (! dac)
2644 continue;
2645 nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];
2646 if (i == 2) {
2647 /* Center/LFE */
2648 err = add_control(spec, AD_CTL_WIDGET_VOL,
2649 "Center Playback Volume",
2650 HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));
2651 if (err < 0)
2652 return err;
2653 err = add_control(spec, AD_CTL_WIDGET_VOL,
2654 "LFE Playback Volume",
2655 HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));
2656 if (err < 0)
2657 return err;
2658 err = add_control(spec, AD_CTL_BIND_MUTE,
2659 "Center Playback Switch",
2660 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
2661 if (err < 0)
2662 return err;
2663 err = add_control(spec, AD_CTL_BIND_MUTE,
2664 "LFE Playback Switch",
2665 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
2666 if (err < 0)
2667 return err;
2668 } else {
2669 sprintf(name, "%s Playback Volume", chname[i]);
2670 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2671 HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));
2672 if (err < 0)
2673 return err;
2674 sprintf(name, "%s Playback Switch", chname[i]);
2675 err = add_control(spec, AD_CTL_BIND_MUTE, name,
2676 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
2677 if (err < 0)
2678 return err;
2681 return 0;
2684 /* add playback controls for speaker and HP outputs */
2685 static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
2686 const char *pfx)
2688 struct ad198x_spec *spec = codec->spec;
2689 hda_nid_t nid;
2690 int i, idx, err;
2691 char name[32];
2693 if (! pin)
2694 return 0;
2696 idx = ad1988_pin_idx(pin);
2697 nid = ad1988_idx_to_dac(codec, idx);
2698 /* check whether the corresponding DAC was already taken */
2699 for (i = 0; i < spec->autocfg.line_outs; i++) {
2700 hda_nid_t pin = spec->autocfg.line_out_pins[i];
2701 hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
2702 if (dac == nid)
2703 break;
2705 if (i >= spec->autocfg.line_outs) {
2706 /* specify the DAC as the extra output */
2707 if (!spec->multiout.hp_nid)
2708 spec->multiout.hp_nid = nid;
2709 else
2710 spec->multiout.extra_out_nid[0] = nid;
2711 /* control HP volume/switch on the output mixer amp */
2712 sprintf(name, "%s Playback Volume", pfx);
2713 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2714 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
2715 if (err < 0)
2716 return err;
2718 nid = ad1988_mixer_nids[idx];
2719 sprintf(name, "%s Playback Switch", pfx);
2720 if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
2721 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
2722 return err;
2723 return 0;
2726 /* create input playback/capture controls for the given pin */
2727 static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
2728 const char *ctlname, int boost)
2730 char name[32];
2731 int err, idx;
2733 sprintf(name, "%s Playback Volume", ctlname);
2734 idx = ad1988_pin_to_loopback_idx(pin);
2735 if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
2736 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2737 return err;
2738 sprintf(name, "%s Playback Switch", ctlname);
2739 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,
2740 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
2741 return err;
2742 if (boost) {
2743 hda_nid_t bnid;
2744 idx = ad1988_pin_idx(pin);
2745 bnid = ad1988_boost_nids[idx];
2746 if (bnid) {
2747 sprintf(name, "%s Boost", ctlname);
2748 return add_control(spec, AD_CTL_WIDGET_VOL, name,
2749 HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
2753 return 0;
2756 /* create playback/capture controls for input pins */
2757 static int ad1988_auto_create_analog_input_ctls(struct ad198x_spec *spec,
2758 const struct auto_pin_cfg *cfg)
2760 struct hda_input_mux *imux = &spec->private_imux;
2761 int i, err;
2763 for (i = 0; i < AUTO_PIN_LAST; i++) {
2764 err = new_analog_input(spec, cfg->input_pins[i],
2765 auto_pin_cfg_labels[i],
2766 i <= AUTO_PIN_FRONT_MIC);
2767 if (err < 0)
2768 return err;
2769 imux->items[imux->num_items].label = auto_pin_cfg_labels[i];
2770 imux->items[imux->num_items].index = ad1988_pin_to_adc_idx(cfg->input_pins[i]);
2771 imux->num_items++;
2773 imux->items[imux->num_items].label = "Mix";
2774 imux->items[imux->num_items].index = 9;
2775 imux->num_items++;
2777 if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
2778 "Analog Mix Playback Volume",
2779 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2780 return err;
2781 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,
2782 "Analog Mix Playback Switch",
2783 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
2784 return err;
2786 return 0;
2789 static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
2790 hda_nid_t nid, int pin_type,
2791 int dac_idx)
2793 /* set as output */
2794 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
2795 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
2796 switch (nid) {
2797 case 0x11: /* port-A - DAC 04 */
2798 snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2799 break;
2800 case 0x14: /* port-B - DAC 06 */
2801 snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
2802 break;
2803 case 0x15: /* port-C - DAC 05 */
2804 snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
2805 break;
2806 case 0x17: /* port-E - DAC 0a */
2807 snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2808 break;
2809 case 0x13: /* mono - DAC 04 */
2810 snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
2811 break;
2815 static void ad1988_auto_init_multi_out(struct hda_codec *codec)
2817 struct ad198x_spec *spec = codec->spec;
2818 int i;
2820 for (i = 0; i < spec->autocfg.line_outs; i++) {
2821 hda_nid_t nid = spec->autocfg.line_out_pins[i];
2822 ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
2826 static void ad1988_auto_init_extra_out(struct hda_codec *codec)
2828 struct ad198x_spec *spec = codec->spec;
2829 hda_nid_t pin;
2831 pin = spec->autocfg.speaker_pins[0];
2832 if (pin) /* connect to front */
2833 ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
2834 pin = spec->autocfg.hp_pins[0];
2835 if (pin) /* connect to front */
2836 ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
2839 static void ad1988_auto_init_analog_input(struct hda_codec *codec)
2841 struct ad198x_spec *spec = codec->spec;
2842 int i, idx;
2844 for (i = 0; i < AUTO_PIN_LAST; i++) {
2845 hda_nid_t nid = spec->autocfg.input_pins[i];
2846 if (! nid)
2847 continue;
2848 switch (nid) {
2849 case 0x15: /* port-C */
2850 snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
2851 break;
2852 case 0x17: /* port-E */
2853 snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
2854 break;
2856 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
2857 i <= AUTO_PIN_FRONT_MIC ? PIN_VREF80 : PIN_IN);
2858 if (nid != AD1988_PIN_CD_NID)
2859 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
2860 AMP_OUT_MUTE);
2861 idx = ad1988_pin_idx(nid);
2862 if (ad1988_boost_nids[idx])
2863 snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,
2864 AC_VERB_SET_AMP_GAIN_MUTE,
2865 AMP_OUT_ZERO);
2869 /* parse the BIOS configuration and set up the alc_spec */
2870 /* return 1 if successful, 0 if the proper config is not found, or a negative error code */
2871 static int ad1988_parse_auto_config(struct hda_codec *codec)
2873 struct ad198x_spec *spec = codec->spec;
2874 int err;
2876 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
2877 return err;
2878 if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
2879 return err;
2880 if (! spec->autocfg.line_outs)
2881 return 0; /* can't find valid BIOS pin config */
2882 if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
2883 (err = ad1988_auto_create_extra_out(codec,
2884 spec->autocfg.speaker_pins[0],
2885 "Speaker")) < 0 ||
2886 (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
2887 "Headphone")) < 0 ||
2888 (err = ad1988_auto_create_analog_input_ctls(spec, &spec->autocfg)) < 0)
2889 return err;
2891 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
2893 if (spec->autocfg.dig_out_pin)
2894 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
2895 if (spec->autocfg.dig_in_pin)
2896 spec->dig_in_nid = AD1988_SPDIF_IN;
2898 if (spec->kctls.list)
2899 spec->mixers[spec->num_mixers++] = spec->kctls.list;
2901 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
2903 spec->input_mux = &spec->private_imux;
2905 return 1;
2908 /* init callback for auto-configuration model -- overriding the default init */
2909 static int ad1988_auto_init(struct hda_codec *codec)
2911 ad198x_init(codec);
2912 ad1988_auto_init_multi_out(codec);
2913 ad1988_auto_init_extra_out(codec);
2914 ad1988_auto_init_analog_input(codec);
2915 return 0;
2922 static const char *ad1988_models[AD1988_MODEL_LAST] = {
2923 [AD1988_6STACK] = "6stack",
2924 [AD1988_6STACK_DIG] = "6stack-dig",
2925 [AD1988_3STACK] = "3stack",
2926 [AD1988_3STACK_DIG] = "3stack-dig",
2927 [AD1988_LAPTOP] = "laptop",
2928 [AD1988_LAPTOP_DIG] = "laptop-dig",
2929 [AD1988_AUTO] = "auto",
2932 static struct snd_pci_quirk ad1988_cfg_tbl[] = {
2933 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
2934 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
2935 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
2936 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
2940 static int patch_ad1988(struct hda_codec *codec)
2942 struct ad198x_spec *spec;
2943 int board_config;
2945 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
2946 if (spec == NULL)
2947 return -ENOMEM;
2949 codec->spec = spec;
2951 if (is_rev2(codec))
2952 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
2954 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
2955 ad1988_models, ad1988_cfg_tbl);
2956 if (board_config < 0) {
2957 printk(KERN_INFO "hda_codec: Unknown model for AD1988, trying auto-probe from BIOS...\n");
2958 board_config = AD1988_AUTO;
2961 if (board_config == AD1988_AUTO) {
2962 /* automatic parse from the BIOS config */
2963 int err = ad1988_parse_auto_config(codec);
2964 if (err < 0) {
2965 ad198x_free(codec);
2966 return err;
2967 } else if (! err) {
2968 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n");
2969 board_config = AD1988_6STACK;
2973 switch (board_config) {
2974 case AD1988_6STACK:
2975 case AD1988_6STACK_DIG:
2976 spec->multiout.max_channels = 8;
2977 spec->multiout.num_dacs = 4;
2978 if (is_rev2(codec))
2979 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
2980 else
2981 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
2982 spec->input_mux = &ad1988_6stack_capture_source;
2983 spec->num_mixers = 2;
2984 if (is_rev2(codec))
2985 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
2986 else
2987 spec->mixers[0] = ad1988_6stack_mixers1;
2988 spec->mixers[1] = ad1988_6stack_mixers2;
2989 spec->num_init_verbs = 1;
2990 spec->init_verbs[0] = ad1988_6stack_init_verbs;
2991 if (board_config == AD1988_6STACK_DIG) {
2992 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
2993 spec->dig_in_nid = AD1988_SPDIF_IN;
2995 break;
2996 case AD1988_3STACK:
2997 case AD1988_3STACK_DIG:
2998 spec->multiout.max_channels = 6;
2999 spec->multiout.num_dacs = 3;
3000 if (is_rev2(codec))
3001 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3002 else
3003 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3004 spec->input_mux = &ad1988_6stack_capture_source;
3005 spec->channel_mode = ad1988_3stack_modes;
3006 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
3007 spec->num_mixers = 2;
3008 if (is_rev2(codec))
3009 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3010 else
3011 spec->mixers[0] = ad1988_3stack_mixers1;
3012 spec->mixers[1] = ad1988_3stack_mixers2;
3013 spec->num_init_verbs = 1;
3014 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3015 if (board_config == AD1988_3STACK_DIG)
3016 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3017 break;
3018 case AD1988_LAPTOP:
3019 case AD1988_LAPTOP_DIG:
3020 spec->multiout.max_channels = 2;
3021 spec->multiout.num_dacs = 1;
3022 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3023 spec->input_mux = &ad1988_laptop_capture_source;
3024 spec->num_mixers = 1;
3025 spec->mixers[0] = ad1988_laptop_mixers;
3026 spec->num_init_verbs = 1;
3027 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3028 if (board_config == AD1988_LAPTOP_DIG)
3029 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3030 break;
3033 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3034 spec->adc_nids = ad1988_adc_nids;
3035 spec->capsrc_nids = ad1988_capsrc_nids;
3036 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3037 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3038 if (spec->multiout.dig_out_nid) {
3039 if (codec->vendor_id >= 0x11d4989a) {
3040 spec->mixers[spec->num_mixers++] =
3041 ad1989_spdif_out_mixers;
3042 spec->init_verbs[spec->num_init_verbs++] =
3043 ad1989_spdif_init_verbs;
3044 codec->slave_dig_outs = ad1989b_slave_dig_outs;
3045 } else {
3046 spec->mixers[spec->num_mixers++] =
3047 ad1988_spdif_out_mixers;
3048 spec->init_verbs[spec->num_init_verbs++] =
3049 ad1988_spdif_init_verbs;
3052 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a)
3053 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
3055 codec->patch_ops = ad198x_patch_ops;
3056 switch (board_config) {
3057 case AD1988_AUTO:
3058 codec->patch_ops.init = ad1988_auto_init;
3059 break;
3060 case AD1988_LAPTOP:
3061 case AD1988_LAPTOP_DIG:
3062 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3063 break;
3065 #ifdef CONFIG_SND_HDA_POWER_SAVE
3066 spec->loopback.amplist = ad1988_loopbacks;
3067 #endif
3068 spec->vmaster_nid = 0x04;
3070 return 0;
3075 * AD1884 / AD1984
3077 * port-B - front line/mic-in
3078 * port-E - aux in/out
3079 * port-F - aux in/out
3080 * port-C - rear line/mic-in
3081 * port-D - rear line/hp-out
3082 * port-A - front line/hp-out
3084 * AD1984 = AD1884 + two digital mic-ins
3086 * FIXME:
3087 * For simplicity, we share the single DAC for both HP and line-outs
3088 * right now. The inidividual playbacks could be easily implemented,
3089 * but no build-up framework is given, so far.
3092 static hda_nid_t ad1884_dac_nids[1] = {
3093 0x04,
3096 static hda_nid_t ad1884_adc_nids[2] = {
3097 0x08, 0x09,
3100 static hda_nid_t ad1884_capsrc_nids[2] = {
3101 0x0c, 0x0d,
3104 #define AD1884_SPDIF_OUT 0x02
3106 static struct hda_input_mux ad1884_capture_source = {
3107 .num_items = 4,
3108 .items = {
3109 { "Front Mic", 0x0 },
3110 { "Mic", 0x1 },
3111 { "CD", 0x2 },
3112 { "Mix", 0x3 },
3116 static struct snd_kcontrol_new ad1884_base_mixers[] = {
3117 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3118 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3119 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3120 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3121 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3122 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3123 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3124 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3125 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3126 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3127 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3128 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3130 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
3131 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
3132 HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0x10, 0x0, HDA_OUTPUT),
3133 HDA_CODEC_MUTE("Digital Beep Playback Switch", 0x10, 0x0, HDA_OUTPUT),
3135 HDA_CODEC_VOLUME("Mic Boost", 0x15, 0x0, HDA_INPUT),
3136 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3137 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3138 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3139 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3140 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3142 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3143 /* The multiple "Capture Source" controls confuse alsamixer
3144 * So call somewhat different..
3146 /* .name = "Capture Source", */
3147 .name = "Input Source",
3148 .count = 2,
3149 .info = ad198x_mux_enum_info,
3150 .get = ad198x_mux_enum_get,
3151 .put = ad198x_mux_enum_put,
3153 /* SPDIF controls */
3154 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3156 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3157 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3158 /* identical with ad1983 */
3159 .info = ad1983_spdif_route_info,
3160 .get = ad1983_spdif_route_get,
3161 .put = ad1983_spdif_route_put,
3163 { } /* end */
3166 static struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3167 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3168 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3169 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
3170 HDA_INPUT),
3171 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
3172 HDA_INPUT),
3173 { } /* end */
3177 * initialization verbs
3179 static struct hda_verb ad1884_init_verbs[] = {
3180 /* DACs; mute as default */
3181 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3182 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3183 /* Port-A (HP) mixer */
3184 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3185 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3186 /* Port-A pin */
3187 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3188 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3189 /* HP selector - select DAC2 */
3190 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3191 /* Port-D (Line-out) mixer */
3192 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3193 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3194 /* Port-D pin */
3195 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3196 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3197 /* Mono-out mixer */
3198 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3199 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3200 /* Mono-out pin */
3201 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3202 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3203 /* Mono selector */
3204 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3205 /* Port-B (front mic) pin */
3206 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3207 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3208 /* Port-C (rear mic) pin */
3209 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3210 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3211 /* Analog mixer; mute as default */
3212 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3213 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3214 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3215 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3216 /* Analog Mix output amp */
3217 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
3218 /* SPDIF output selector */
3219 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
3220 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3221 { } /* end */
3224 #ifdef CONFIG_SND_HDA_POWER_SAVE
3225 static struct hda_amp_list ad1884_loopbacks[] = {
3226 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3227 { 0x20, HDA_INPUT, 1 }, /* Mic */
3228 { 0x20, HDA_INPUT, 2 }, /* CD */
3229 { 0x20, HDA_INPUT, 4 }, /* Docking */
3230 { } /* end */
3232 #endif
3234 static const char *ad1884_slave_vols[] = {
3235 "PCM Playback Volume",
3236 "Mic Playback Volume",
3237 "Mono Playback Volume",
3238 "Front Mic Playback Volume",
3239 "Mic Playback Volume",
3240 "CD Playback Volume",
3241 "Internal Mic Playback Volume",
3242 "Docking Mic Playback Volume"
3243 "Beep Playback Volume",
3244 "IEC958 Playback Volume",
3245 NULL
3248 static int patch_ad1884(struct hda_codec *codec)
3250 struct ad198x_spec *spec;
3252 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3253 if (spec == NULL)
3254 return -ENOMEM;
3256 codec->spec = spec;
3258 spec->multiout.max_channels = 2;
3259 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3260 spec->multiout.dac_nids = ad1884_dac_nids;
3261 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3262 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3263 spec->adc_nids = ad1884_adc_nids;
3264 spec->capsrc_nids = ad1884_capsrc_nids;
3265 spec->input_mux = &ad1884_capture_source;
3266 spec->num_mixers = 1;
3267 spec->mixers[0] = ad1884_base_mixers;
3268 spec->num_init_verbs = 1;
3269 spec->init_verbs[0] = ad1884_init_verbs;
3270 spec->spdif_route = 0;
3271 #ifdef CONFIG_SND_HDA_POWER_SAVE
3272 spec->loopback.amplist = ad1884_loopbacks;
3273 #endif
3274 spec->vmaster_nid = 0x04;
3275 /* we need to cover all playback volumes */
3276 spec->slave_vols = ad1884_slave_vols;
3278 codec->patch_ops = ad198x_patch_ops;
3280 return 0;
3284 * Lenovo Thinkpad T61/X61
3286 static struct hda_input_mux ad1984_thinkpad_capture_source = {
3287 .num_items = 4,
3288 .items = {
3289 { "Mic", 0x0 },
3290 { "Internal Mic", 0x1 },
3291 { "Mix", 0x3 },
3292 { "Docking-Station", 0x4 },
3298 * Dell Precision T3400
3300 static struct hda_input_mux ad1984_dell_desktop_capture_source = {
3301 .num_items = 3,
3302 .items = {
3303 { "Front Mic", 0x0 },
3304 { "Line-In", 0x1 },
3305 { "Mix", 0x3 },
3310 static struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3311 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3312 /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */
3313 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3314 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3315 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3316 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3317 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3318 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3319 HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3320 HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3321 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3322 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
3323 HDA_CODEC_VOLUME("Docking Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3324 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3325 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3326 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3327 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3328 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3329 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3331 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3332 /* The multiple "Capture Source" controls confuse alsamixer
3333 * So call somewhat different..
3335 /* .name = "Capture Source", */
3336 .name = "Input Source",
3337 .count = 2,
3338 .info = ad198x_mux_enum_info,
3339 .get = ad198x_mux_enum_get,
3340 .put = ad198x_mux_enum_put,
3342 /* SPDIF controls */
3343 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3345 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3346 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3347 /* identical with ad1983 */
3348 .info = ad1983_spdif_route_info,
3349 .get = ad1983_spdif_route_get,
3350 .put = ad1983_spdif_route_put,
3352 { } /* end */
3355 /* additional verbs */
3356 static struct hda_verb ad1984_thinkpad_init_verbs[] = {
3357 /* Port-E (docking station mic) pin */
3358 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3359 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3360 /* docking mic boost */
3361 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3362 /* Analog mixer - docking mic; mute as default */
3363 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3364 /* enable EAPD bit */
3365 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3366 { } /* end */
3370 * Dell Precision T3400
3372 static struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3373 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3374 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3375 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3376 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3377 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3378 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3379 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3380 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3381 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
3383 HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x20, 0x03, HDA_INPUT),
3384 HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x20, 0x03, HDA_INPUT),
3386 HDA_CODEC_VOLUME("Line-In Boost", 0x15, 0x0, HDA_INPUT),
3387 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3388 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3389 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3390 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3391 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3393 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3394 /* The multiple "Capture Source" controls confuse alsamixer
3395 * So call somewhat different..
3397 /* .name = "Capture Source", */
3398 .name = "Input Source",
3399 .count = 2,
3400 .info = ad198x_mux_enum_info,
3401 .get = ad198x_mux_enum_get,
3402 .put = ad198x_mux_enum_put,
3404 { } /* end */
3407 /* Digial MIC ADC NID 0x05 + 0x06 */
3408 static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3409 struct hda_codec *codec,
3410 unsigned int stream_tag,
3411 unsigned int format,
3412 struct snd_pcm_substream *substream)
3414 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3415 stream_tag, 0, format);
3416 return 0;
3419 static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3420 struct hda_codec *codec,
3421 struct snd_pcm_substream *substream)
3423 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
3424 return 0;
3427 static struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3428 .substreams = 2,
3429 .channels_min = 2,
3430 .channels_max = 2,
3431 .nid = 0x05,
3432 .ops = {
3433 .prepare = ad1984_pcm_dmic_prepare,
3434 .cleanup = ad1984_pcm_dmic_cleanup
3438 static int ad1984_build_pcms(struct hda_codec *codec)
3440 struct ad198x_spec *spec = codec->spec;
3441 struct hda_pcm *info;
3442 int err;
3444 err = ad198x_build_pcms(codec);
3445 if (err < 0)
3446 return err;
3448 info = spec->pcm_rec + codec->num_pcms;
3449 codec->num_pcms++;
3450 info->name = "AD1984 Digital Mic";
3451 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3452 return 0;
3455 /* models */
3456 enum {
3457 AD1984_BASIC,
3458 AD1984_THINKPAD,
3459 AD1984_DELL_DESKTOP,
3460 AD1984_MODELS
3463 static const char *ad1984_models[AD1984_MODELS] = {
3464 [AD1984_BASIC] = "basic",
3465 [AD1984_THINKPAD] = "thinkpad",
3466 [AD1984_DELL_DESKTOP] = "dell_desktop",
3469 static struct snd_pci_quirk ad1984_cfg_tbl[] = {
3470 /* Lenovo Thinkpad T61/X61 */
3471 SND_PCI_QUIRK(0x17aa, 0, "Lenovo Thinkpad", AD1984_THINKPAD),
3472 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
3476 static int patch_ad1984(struct hda_codec *codec)
3478 struct ad198x_spec *spec;
3479 int board_config, err;
3481 err = patch_ad1884(codec);
3482 if (err < 0)
3483 return err;
3484 spec = codec->spec;
3485 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3486 ad1984_models, ad1984_cfg_tbl);
3487 switch (board_config) {
3488 case AD1984_BASIC:
3489 /* additional digital mics */
3490 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3491 codec->patch_ops.build_pcms = ad1984_build_pcms;
3492 break;
3493 case AD1984_THINKPAD:
3494 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3495 spec->input_mux = &ad1984_thinkpad_capture_source;
3496 spec->mixers[0] = ad1984_thinkpad_mixers;
3497 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
3498 break;
3499 case AD1984_DELL_DESKTOP:
3500 spec->multiout.dig_out_nid = 0;
3501 spec->input_mux = &ad1984_dell_desktop_capture_source;
3502 spec->mixers[0] = ad1984_dell_desktop_mixers;
3503 break;
3505 return 0;
3510 * AD1883 / AD1884A / AD1984A / AD1984B
3512 * port-B (0x14) - front mic-in
3513 * port-E (0x1c) - rear mic-in
3514 * port-F (0x16) - CD / ext out
3515 * port-C (0x15) - rear line-in
3516 * port-D (0x12) - rear line-out
3517 * port-A (0x11) - front hp-out
3519 * AD1984A = AD1884A + digital-mic
3520 * AD1883 = equivalent with AD1984A
3521 * AD1984B = AD1984A + extra SPDIF-out
3523 * FIXME:
3524 * We share the single DAC for both HP and line-outs (see AD1884/1984).
3527 static hda_nid_t ad1884a_dac_nids[1] = {
3528 0x03,
3531 #define ad1884a_adc_nids ad1884_adc_nids
3532 #define ad1884a_capsrc_nids ad1884_capsrc_nids
3534 #define AD1884A_SPDIF_OUT 0x02
3536 static struct hda_input_mux ad1884a_capture_source = {
3537 .num_items = 5,
3538 .items = {
3539 { "Front Mic", 0x0 },
3540 { "Mic", 0x4 },
3541 { "Line", 0x1 },
3542 { "CD", 0x2 },
3543 { "Mix", 0x3 },
3547 static struct snd_kcontrol_new ad1884a_base_mixers[] = {
3548 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3549 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3550 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3551 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3552 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3553 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3554 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3555 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3556 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3557 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3558 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3559 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3560 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3561 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3562 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3563 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3564 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3565 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3566 HDA_CODEC_VOLUME("Front Mic Boost", 0x14, 0x0, HDA_INPUT),
3567 HDA_CODEC_VOLUME("Line Boost", 0x15, 0x0, HDA_INPUT),
3568 HDA_CODEC_VOLUME("Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3569 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3570 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3571 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3572 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3574 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3575 /* The multiple "Capture Source" controls confuse alsamixer
3576 * So call somewhat different..
3578 /* .name = "Capture Source", */
3579 .name = "Input Source",
3580 .count = 2,
3581 .info = ad198x_mux_enum_info,
3582 .get = ad198x_mux_enum_get,
3583 .put = ad198x_mux_enum_put,
3585 /* SPDIF controls */
3586 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3588 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3589 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3590 /* identical with ad1983 */
3591 .info = ad1983_spdif_route_info,
3592 .get = ad1983_spdif_route_get,
3593 .put = ad1983_spdif_route_put,
3595 { } /* end */
3599 * initialization verbs
3601 static struct hda_verb ad1884a_init_verbs[] = {
3602 /* DACs; unmute as default */
3603 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3604 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */
3605 /* Port-A (HP) mixer - route only from analog mixer */
3606 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3607 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3608 /* Port-A pin */
3609 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3610 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3611 /* Port-D (Line-out) mixer - route only from analog mixer */
3612 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3613 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3614 /* Port-D pin */
3615 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3616 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3617 /* Mono-out mixer - route only from analog mixer */
3618 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3619 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3620 /* Mono-out pin */
3621 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3622 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3623 /* Port-B (front mic) pin */
3624 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3625 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3626 /* Port-C (rear line-in) pin */
3627 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3628 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3629 /* Port-E (rear mic) pin */
3630 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3631 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3632 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */
3633 /* Port-F (CD) pin */
3634 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3635 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3636 /* Analog mixer; mute as default */
3637 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3638 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3639 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3640 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3641 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */
3642 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
3643 /* Analog Mix output amp */
3644 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3645 /* capture sources */
3646 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
3647 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3648 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
3649 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3650 /* SPDIF output amp */
3651 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
3652 { } /* end */
3655 #ifdef CONFIG_SND_HDA_POWER_SAVE
3656 static struct hda_amp_list ad1884a_loopbacks[] = {
3657 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
3658 { 0x20, HDA_INPUT, 1 }, /* Mic */
3659 { 0x20, HDA_INPUT, 2 }, /* CD */
3660 { 0x20, HDA_INPUT, 4 }, /* Docking */
3661 { } /* end */
3663 #endif
3666 * Laptop model
3668 * Port A: Headphone jack
3669 * Port B: MIC jack
3670 * Port C: Internal MIC
3671 * Port D: Dock Line Out (if enabled)
3672 * Port E: Dock Line In (if enabled)
3673 * Port F: Internal speakers
3676 static struct hda_input_mux ad1884a_laptop_capture_source = {
3677 .num_items = 4,
3678 .items = {
3679 { "Mic", 0x0 }, /* port-B */
3680 { "Internal Mic", 0x1 }, /* port-C */
3681 { "Dock Mic", 0x4 }, /* port-E */
3682 { "Mix", 0x3 },
3686 static struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
3687 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3688 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3689 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3690 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3691 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3692 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3693 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3694 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3695 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3696 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3697 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3698 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3699 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3700 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3701 HDA_CODEC_VOLUME("Internal Mic Boost", 0x15, 0x0, HDA_INPUT),
3702 HDA_CODEC_VOLUME("Dock Mic Boost", 0x25, 0x0, HDA_OUTPUT),
3703 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3704 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3705 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3706 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3708 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3709 /* The multiple "Capture Source" controls confuse alsamixer
3710 * So call somewhat different..
3712 /* .name = "Capture Source", */
3713 .name = "Input Source",
3714 .count = 2,
3715 .info = ad198x_mux_enum_info,
3716 .get = ad198x_mux_enum_get,
3717 .put = ad198x_mux_enum_put,
3719 { } /* end */
3722 static struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
3723 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3724 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3725 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3726 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3727 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3728 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3729 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
3730 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
3731 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3732 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3733 { } /* end */
3736 /* mute internal speaker if HP is plugged */
3737 static void ad1884a_hp_automute(struct hda_codec *codec)
3739 unsigned int present;
3741 present = snd_hda_codec_read(codec, 0x11, 0,
3742 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
3743 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
3744 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3745 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
3746 present ? 0x00 : 0x02);
3749 /* switch to external mic if plugged */
3750 static void ad1884a_hp_automic(struct hda_codec *codec)
3752 unsigned int present;
3754 present = snd_hda_codec_read(codec, 0x14, 0,
3755 AC_VERB_GET_PIN_SENSE, 0) & 0x80000000;
3756 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
3757 present ? 0 : 1);
3760 #define AD1884A_HP_EVENT 0x37
3761 #define AD1884A_MIC_EVENT 0x36
3763 /* unsolicited event for HP jack sensing */
3764 static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
3766 switch (res >> 26) {
3767 case AD1884A_HP_EVENT:
3768 ad1884a_hp_automute(codec);
3769 break;
3770 case AD1884A_MIC_EVENT:
3771 ad1884a_hp_automic(codec);
3772 break;
3776 /* initialize jack-sensing, too */
3777 static int ad1884a_hp_init(struct hda_codec *codec)
3779 ad198x_init(codec);
3780 ad1884a_hp_automute(codec);
3781 ad1884a_hp_automic(codec);
3782 return 0;
3785 /* additional verbs for laptop model */
3786 static struct hda_verb ad1884a_laptop_verbs[] = {
3787 /* Port-A (HP) pin - always unmuted */
3788 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3789 /* Port-F (int speaker) mixer - route only from analog mixer */
3790 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3791 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3792 /* Port-F pin */
3793 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3794 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3795 /* Port-C pin - internal mic-in */
3796 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3797 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
3798 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */
3799 /* analog mix */
3800 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3801 /* unsolicited event for pin-sense */
3802 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
3803 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
3804 { } /* end */
3808 * Thinkpad X300
3809 * 0x11 - HP
3810 * 0x12 - speaker
3811 * 0x14 - mic-in
3812 * 0x17 - built-in mic
3815 static struct hda_verb ad1984a_thinkpad_verbs[] = {
3816 /* HP unmute */
3817 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
3818 /* analog mix */
3819 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3820 /* turn on EAPD */
3821 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3822 /* unsolicited event for pin-sense */
3823 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
3824 /* internal mic - dmic */
3825 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
3826 /* set magic COEFs for dmic */
3827 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
3828 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
3829 { } /* end */
3832 static struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
3833 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3834 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3835 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3836 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3837 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3838 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3839 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3840 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3841 HDA_CODEC_VOLUME("Mic Boost", 0x14, 0x0, HDA_INPUT),
3842 HDA_CODEC_VOLUME("Internal Mic Boost", 0x17, 0x0, HDA_INPUT),
3843 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3844 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3846 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3847 .name = "Capture Source",
3848 .info = ad198x_mux_enum_info,
3849 .get = ad198x_mux_enum_get,
3850 .put = ad198x_mux_enum_put,
3852 { } /* end */
3855 static struct hda_input_mux ad1984a_thinkpad_capture_source = {
3856 .num_items = 3,
3857 .items = {
3858 { "Mic", 0x0 },
3859 { "Internal Mic", 0x5 },
3860 { "Mix", 0x3 },
3864 /* mute internal speaker if HP is plugged */
3865 static void ad1984a_thinkpad_automute(struct hda_codec *codec)
3867 unsigned int present;
3869 present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0)
3870 & AC_PINSENSE_PRESENCE;
3871 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
3872 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
3875 /* unsolicited event for HP jack sensing */
3876 static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
3877 unsigned int res)
3879 if ((res >> 26) != AD1884A_HP_EVENT)
3880 return;
3881 ad1984a_thinkpad_automute(codec);
3884 /* initialize jack-sensing, too */
3885 static int ad1984a_thinkpad_init(struct hda_codec *codec)
3887 ad198x_init(codec);
3888 ad1984a_thinkpad_automute(codec);
3889 return 0;
3895 enum {
3896 AD1884A_DESKTOP,
3897 AD1884A_LAPTOP,
3898 AD1884A_MOBILE,
3899 AD1884A_THINKPAD,
3900 AD1884A_MODELS
3903 static const char *ad1884a_models[AD1884A_MODELS] = {
3904 [AD1884A_DESKTOP] = "desktop",
3905 [AD1884A_LAPTOP] = "laptop",
3906 [AD1884A_MOBILE] = "mobile",
3907 [AD1884A_THINKPAD] = "thinkpad",
3910 static struct snd_pci_quirk ad1884a_cfg_tbl[] = {
3911 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
3912 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
3913 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
3914 SND_PCI_QUIRK(0x103c, 0x30e6, "HP 6730b", AD1884A_LAPTOP),
3915 SND_PCI_QUIRK(0x103c, 0x30e7, "HP EliteBook 8530p", AD1884A_LAPTOP),
3916 SND_PCI_QUIRK(0x103c, 0x3614, "HP 6730s", AD1884A_LAPTOP),
3917 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
3921 static int patch_ad1884a(struct hda_codec *codec)
3923 struct ad198x_spec *spec;
3924 int board_config;
3926 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3927 if (spec == NULL)
3928 return -ENOMEM;
3930 codec->spec = spec;
3932 spec->multiout.max_channels = 2;
3933 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
3934 spec->multiout.dac_nids = ad1884a_dac_nids;
3935 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
3936 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
3937 spec->adc_nids = ad1884a_adc_nids;
3938 spec->capsrc_nids = ad1884a_capsrc_nids;
3939 spec->input_mux = &ad1884a_capture_source;
3940 spec->num_mixers = 1;
3941 spec->mixers[0] = ad1884a_base_mixers;
3942 spec->num_init_verbs = 1;
3943 spec->init_verbs[0] = ad1884a_init_verbs;
3944 spec->spdif_route = 0;
3945 #ifdef CONFIG_SND_HDA_POWER_SAVE
3946 spec->loopback.amplist = ad1884a_loopbacks;
3947 #endif
3948 codec->patch_ops = ad198x_patch_ops;
3950 /* override some parameters */
3951 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
3952 ad1884a_models,
3953 ad1884a_cfg_tbl);
3954 switch (board_config) {
3955 case AD1884A_LAPTOP:
3956 spec->mixers[0] = ad1884a_laptop_mixers;
3957 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
3958 spec->multiout.dig_out_nid = 0;
3959 spec->input_mux = &ad1884a_laptop_capture_source;
3960 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
3961 codec->patch_ops.init = ad1884a_hp_init;
3962 break;
3963 case AD1884A_MOBILE:
3964 spec->mixers[0] = ad1884a_mobile_mixers;
3965 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
3966 spec->multiout.dig_out_nid = 0;
3967 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
3968 codec->patch_ops.init = ad1884a_hp_init;
3969 break;
3970 case AD1884A_THINKPAD:
3971 spec->mixers[0] = ad1984a_thinkpad_mixers;
3972 spec->init_verbs[spec->num_init_verbs++] =
3973 ad1984a_thinkpad_verbs;
3974 spec->multiout.dig_out_nid = 0;
3975 spec->input_mux = &ad1984a_thinkpad_capture_source;
3976 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
3977 codec->patch_ops.init = ad1984a_thinkpad_init;
3978 break;
3981 return 0;
3986 * AD1882 / AD1882A
3988 * port-A - front hp-out
3989 * port-B - front mic-in
3990 * port-C - rear line-in, shared surr-out (3stack)
3991 * port-D - rear line-out
3992 * port-E - rear mic-in, shared clfe-out (3stack)
3993 * port-F - rear surr-out (6stack)
3994 * port-G - rear clfe-out (6stack)
3997 static hda_nid_t ad1882_dac_nids[3] = {
3998 0x04, 0x03, 0x05
4001 static hda_nid_t ad1882_adc_nids[2] = {
4002 0x08, 0x09,
4005 static hda_nid_t ad1882_capsrc_nids[2] = {
4006 0x0c, 0x0d,
4009 #define AD1882_SPDIF_OUT 0x02
4011 /* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */
4012 static struct hda_input_mux ad1882_capture_source = {
4013 .num_items = 5,
4014 .items = {
4015 { "Front Mic", 0x1 },
4016 { "Mic", 0x4 },
4017 { "Line", 0x2 },
4018 { "CD", 0x3 },
4019 { "Mix", 0x7 },
4023 /* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */
4024 static struct hda_input_mux ad1882a_capture_source = {
4025 .num_items = 5,
4026 .items = {
4027 { "Front Mic", 0x1 },
4028 { "Mic", 0x4},
4029 { "Line", 0x2 },
4030 { "Digital Mic", 0x06 },
4031 { "Mix", 0x7 },
4035 static struct snd_kcontrol_new ad1882_base_mixers[] = {
4036 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4037 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4038 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4039 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4040 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4041 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4042 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4043 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
4045 HDA_CODEC_VOLUME("Mic Boost", 0x3c, 0x0, HDA_OUTPUT),
4046 HDA_CODEC_VOLUME("Front Mic Boost", 0x39, 0x0, HDA_OUTPUT),
4047 HDA_CODEC_VOLUME("Line-In Boost", 0x3a, 0x0, HDA_OUTPUT),
4048 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4049 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4050 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4051 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4053 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4054 /* The multiple "Capture Source" controls confuse alsamixer
4055 * So call somewhat different..
4057 /* .name = "Capture Source", */
4058 .name = "Input Source",
4059 .count = 2,
4060 .info = ad198x_mux_enum_info,
4061 .get = ad198x_mux_enum_get,
4062 .put = ad198x_mux_enum_put,
4064 /* SPDIF controls */
4065 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4067 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4068 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4069 /* identical with ad1983 */
4070 .info = ad1983_spdif_route_info,
4071 .get = ad1983_spdif_route_get,
4072 .put = ad1983_spdif_route_put,
4074 { } /* end */
4077 static struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4078 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4079 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4080 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4081 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4082 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4083 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4084 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4085 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4086 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
4087 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
4088 { } /* end */
4091 static struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4092 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4093 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4094 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4095 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4096 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4097 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4098 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4099 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4100 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x07, HDA_INPUT),
4101 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x07, HDA_INPUT),
4102 HDA_CODEC_VOLUME("Digital Mic Boost", 0x1f, 0x0, HDA_INPUT),
4103 { } /* end */
4106 static struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4107 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4108 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4109 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4111 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4112 .name = "Channel Mode",
4113 .info = ad198x_ch_mode_info,
4114 .get = ad198x_ch_mode_get,
4115 .put = ad198x_ch_mode_put,
4117 { } /* end */
4120 static struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4121 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4122 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4123 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4124 { } /* end */
4127 static struct hda_verb ad1882_ch2_init[] = {
4128 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4129 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4130 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4131 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4132 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4133 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4134 { } /* end */
4137 static struct hda_verb ad1882_ch4_init[] = {
4138 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4139 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4140 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4141 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4142 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4143 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4144 { } /* end */
4147 static struct hda_verb ad1882_ch6_init[] = {
4148 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4149 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4150 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4151 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4152 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4153 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4154 { } /* end */
4157 static struct hda_channel_mode ad1882_modes[3] = {
4158 { 2, ad1882_ch2_init },
4159 { 4, ad1882_ch4_init },
4160 { 6, ad1882_ch6_init },
4164 * initialization verbs
4166 static struct hda_verb ad1882_init_verbs[] = {
4167 /* DACs; mute as default */
4168 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4169 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4170 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4171 /* Port-A (HP) mixer */
4172 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4173 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4174 /* Port-A pin */
4175 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4176 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4177 /* HP selector - select DAC2 */
4178 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4179 /* Port-D (Line-out) mixer */
4180 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4181 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4182 /* Port-D pin */
4183 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4184 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4185 /* Mono-out mixer */
4186 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4187 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4188 /* Mono-out pin */
4189 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4190 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4191 /* Port-B (front mic) pin */
4192 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4193 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4194 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4195 /* Port-C (line-in) pin */
4196 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4197 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4198 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4199 /* Port-C mixer - mute as input */
4200 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4201 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4202 /* Port-E (mic-in) pin */
4203 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4204 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4205 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */
4206 /* Port-E mixer - mute as input */
4207 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4208 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4209 /* Port-F (surround) */
4210 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4211 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4212 /* Port-G (CLFE) */
4213 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4214 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4215 /* Analog mixer; mute as default */
4216 /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */
4217 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4218 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4219 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4220 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4221 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4222 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4223 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4224 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4225 /* Analog Mix output amp */
4226 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */
4227 /* SPDIF output selector */
4228 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4229 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */
4230 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */
4231 { } /* end */
4234 #ifdef CONFIG_SND_HDA_POWER_SAVE
4235 static struct hda_amp_list ad1882_loopbacks[] = {
4236 { 0x20, HDA_INPUT, 0 }, /* Front Mic */
4237 { 0x20, HDA_INPUT, 1 }, /* Mic */
4238 { 0x20, HDA_INPUT, 4 }, /* Line */
4239 { 0x20, HDA_INPUT, 6 }, /* CD */
4240 { } /* end */
4242 #endif
4244 /* models */
4245 enum {
4246 AD1882_3STACK,
4247 AD1882_6STACK,
4248 AD1882_MODELS
4251 static const char *ad1882_models[AD1986A_MODELS] = {
4252 [AD1882_3STACK] = "3stack",
4253 [AD1882_6STACK] = "6stack",
4257 static int patch_ad1882(struct hda_codec *codec)
4259 struct ad198x_spec *spec;
4260 int board_config;
4262 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4263 if (spec == NULL)
4264 return -ENOMEM;
4266 codec->spec = spec;
4268 spec->multiout.max_channels = 6;
4269 spec->multiout.num_dacs = 3;
4270 spec->multiout.dac_nids = ad1882_dac_nids;
4271 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
4272 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
4273 spec->adc_nids = ad1882_adc_nids;
4274 spec->capsrc_nids = ad1882_capsrc_nids;
4275 if (codec->vendor_id == 0x11d41882)
4276 spec->input_mux = &ad1882_capture_source;
4277 else
4278 spec->input_mux = &ad1882a_capture_source;
4279 spec->num_mixers = 2;
4280 spec->mixers[0] = ad1882_base_mixers;
4281 if (codec->vendor_id == 0x11d41882)
4282 spec->mixers[1] = ad1882_loopback_mixers;
4283 else
4284 spec->mixers[1] = ad1882a_loopback_mixers;
4285 spec->num_init_verbs = 1;
4286 spec->init_verbs[0] = ad1882_init_verbs;
4287 spec->spdif_route = 0;
4288 #ifdef CONFIG_SND_HDA_POWER_SAVE
4289 spec->loopback.amplist = ad1882_loopbacks;
4290 #endif
4291 spec->vmaster_nid = 0x04;
4293 codec->patch_ops = ad198x_patch_ops;
4295 /* override some parameters */
4296 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
4297 ad1882_models, NULL);
4298 switch (board_config) {
4299 default:
4300 case AD1882_3STACK:
4301 spec->num_mixers = 3;
4302 spec->mixers[2] = ad1882_3stack_mixers;
4303 spec->channel_mode = ad1882_modes;
4304 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
4305 spec->need_dac_fix = 1;
4306 spec->multiout.max_channels = 2;
4307 spec->multiout.num_dacs = 1;
4308 break;
4309 case AD1882_6STACK:
4310 spec->num_mixers = 3;
4311 spec->mixers[2] = ad1882_6stack_mixers;
4312 break;
4314 return 0;
4319 * patch entries
4321 static struct hda_codec_preset snd_hda_preset_analog[] = {
4322 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
4323 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
4324 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
4325 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
4326 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
4327 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
4328 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
4329 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
4330 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
4331 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
4332 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
4333 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
4334 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
4335 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
4336 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
4337 {} /* terminator */
4340 MODULE_ALIAS("snd-hda-codec-id:11d4*");
4342 MODULE_LICENSE("GPL");
4343 MODULE_DESCRIPTION("Analog Devices HD-audio codec");
4345 static struct hda_codec_preset_list analog_list = {
4346 .preset = snd_hda_preset_analog,
4347 .owner = THIS_MODULE,
4350 static int __init patch_analog_init(void)
4352 return snd_hda_add_codec_preset(&analog_list);
4355 static void __exit patch_analog_exit(void)
4357 snd_hda_delete_codec_preset(&analog_list);
4360 module_init(patch_analog_init)
4361 module_exit(patch_analog_exit)