1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/slab.h>
25#include <linux/pci.h>
26#include <linux/module.h>
27
28#include <sound/core.h>
29#include "hda_codec.h"
30#include "hda_local.h"
31#include "hda_beep.h"
32
33struct ad198x_spec {
34 const struct snd_kcontrol_new *mixers[6];
35 int num_mixers;
36 unsigned int beep_amp;
37 const struct hda_verb *init_verbs[6];
38
39
40 unsigned int num_init_verbs;
41
42
43 struct hda_multi_out multiout;
44
45
46
47 unsigned int cur_eapd;
48 unsigned int need_dac_fix;
49
50 const hda_nid_t *alt_dac_nid;
51 const struct hda_pcm_stream *stream_analog_alt_playback;
52 int independent_hp;
53 int num_active_streams;
54
55
56 unsigned int num_adc_nids;
57 const hda_nid_t *adc_nids;
58 hda_nid_t dig_in_nid;
59
60
61 const struct hda_input_mux *input_mux;
62 const hda_nid_t *capsrc_nids;
63 unsigned int cur_mux[3];
64
65
66 const struct hda_channel_mode *channel_mode;
67 int num_channel_mode;
68
69
70 struct hda_pcm pcm_rec[3];
71
72 unsigned int spdif_route;
73
74
75 struct auto_pin_cfg autocfg;
76 struct snd_array kctls;
77 struct hda_input_mux private_imux;
78 hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
79
80 unsigned int jack_present: 1;
81 unsigned int inv_jack_detect: 1;
82 unsigned int inv_eapd: 1;
83 unsigned int analog_beep: 1;
84
85#ifdef CONFIG_SND_HDA_POWER_SAVE
86 struct hda_loopback_check loopback;
87#endif
88
89 hda_nid_t vmaster_nid;
90 const char * const *slave_vols;
91 const char * const *slave_sws;
92};
93
94
95
96
97static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
98{
99 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
100 struct ad198x_spec *spec = codec->spec;
101
102 return snd_hda_input_mux_info(spec->input_mux, uinfo);
103}
104
105static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
106{
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);
110
111 ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
112 return 0;
113}
114
115static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
116{
117 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
118 struct ad198x_spec *spec = codec->spec;
119 unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
120
121 return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol,
122 spec->capsrc_nids[adc_idx],
123 &spec->cur_mux[adc_idx]);
124}
125
126
127
128
129static int ad198x_init(struct hda_codec *codec)
130{
131 struct ad198x_spec *spec = codec->spec;
132 int i;
133
134 for (i = 0; i < spec->num_init_verbs; i++)
135 snd_hda_sequence_write(codec, spec->init_verbs[i]);
136 return 0;
137}
138
139static const char * const ad_slave_vols[] = {
140 "Front Playback Volume",
141 "Surround Playback Volume",
142 "Center Playback Volume",
143 "LFE Playback Volume",
144 "Side Playback Volume",
145 "Headphone Playback Volume",
146 "Mono Playback Volume",
147 "Speaker Playback Volume",
148 "IEC958 Playback Volume",
149 NULL
150};
151
152static const char * const ad_slave_sws[] = {
153 "Front Playback Switch",
154 "Surround Playback Switch",
155 "Center Playback Switch",
156 "LFE Playback Switch",
157 "Side Playback Switch",
158 "Headphone Playback Switch",
159 "Mono Playback Switch",
160 "Speaker Playback Switch",
161 "IEC958 Playback Switch",
162 NULL
163};
164
165static const char * const ad1988_6stack_fp_slave_vols[] = {
166 "Front Playback Volume",
167 "Surround Playback Volume",
168 "Center Playback Volume",
169 "LFE Playback Volume",
170 "Side Playback Volume",
171 "IEC958 Playback Volume",
172 NULL
173};
174
175static const char * const ad1988_6stack_fp_slave_sws[] = {
176 "Front Playback Switch",
177 "Surround Playback Switch",
178 "Center Playback Switch",
179 "LFE Playback Switch",
180 "Side Playback Switch",
181 "IEC958 Playback Switch",
182 NULL
183};
184static void ad198x_free_kctls(struct hda_codec *codec);
185
186#ifdef CONFIG_SND_HDA_INPUT_BEEP
187
188static const struct snd_kcontrol_new ad_beep_mixer[] = {
189 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
190 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
191 { }
192};
193
194static const struct snd_kcontrol_new ad_beep2_mixer[] = {
195 HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT),
196 HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT),
197 { }
198};
199
200#define set_beep_amp(spec, nid, idx, dir) \
201 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
202#else
203#define set_beep_amp(spec, nid, idx, dir)
204#endif
205
206static int ad198x_build_controls(struct hda_codec *codec)
207{
208 struct ad198x_spec *spec = codec->spec;
209 struct snd_kcontrol *kctl;
210 unsigned int i;
211 int err;
212
213 for (i = 0; i < spec->num_mixers; i++) {
214 err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
215 if (err < 0)
216 return err;
217 }
218 if (spec->multiout.dig_out_nid) {
219 err = snd_hda_create_spdif_out_ctls(codec,
220 spec->multiout.dig_out_nid,
221 spec->multiout.dig_out_nid);
222 if (err < 0)
223 return err;
224 err = snd_hda_create_spdif_share_sw(codec,
225 &spec->multiout);
226 if (err < 0)
227 return err;
228 spec->multiout.share_spdif = 1;
229 }
230 if (spec->dig_in_nid) {
231 err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
232 if (err < 0)
233 return err;
234 }
235
236
237#ifdef CONFIG_SND_HDA_INPUT_BEEP
238 if (spec->beep_amp) {
239 const struct snd_kcontrol_new *knew;
240 knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer;
241 for ( ; knew->name; knew++) {
242 struct snd_kcontrol *kctl;
243 kctl = snd_ctl_new1(knew, codec);
244 if (!kctl)
245 return -ENOMEM;
246 kctl->private_value = spec->beep_amp;
247 err = snd_hda_ctl_add(codec, 0, kctl);
248 if (err < 0)
249 return err;
250 }
251 }
252#endif
253
254
255 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
256 unsigned int vmaster_tlv[4];
257 snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
258 HDA_OUTPUT, vmaster_tlv);
259 err = snd_hda_add_vmaster(codec, "Master Playback Volume",
260 vmaster_tlv,
261 (spec->slave_vols ?
262 spec->slave_vols : ad_slave_vols));
263 if (err < 0)
264 return err;
265 }
266 if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
267 err = snd_hda_add_vmaster(codec, "Master Playback Switch",
268 NULL,
269 (spec->slave_sws ?
270 spec->slave_sws : ad_slave_sws));
271 if (err < 0)
272 return err;
273 }
274
275 ad198x_free_kctls(codec);
276
277
278 kctl = snd_hda_find_mixer_ctl(codec, "Capture Source");
279 if (!kctl)
280 kctl = snd_hda_find_mixer_ctl(codec, "Input Source");
281 for (i = 0; kctl && i < kctl->count; i++) {
282 err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]);
283 if (err < 0)
284 return err;
285 }
286
287
288 kctl = snd_hda_find_mixer_ctl(codec,
289 SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source");
290 if (kctl) {
291 err = snd_hda_add_nid(codec, kctl, 0,
292 spec->multiout.dig_out_nid);
293 if (err < 0)
294 return err;
295 }
296
297 return 0;
298}
299
300#ifdef CONFIG_SND_HDA_POWER_SAVE
301static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid)
302{
303 struct ad198x_spec *spec = codec->spec;
304 return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
305}
306#endif
307
308static void activate_ctl(struct hda_codec *codec, const char *name, int active)
309{
310 struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name);
311 if (ctl) {
312 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
313 ctl->vd[0].access |= active ? 0 :
314 SNDRV_CTL_ELEM_ACCESS_INACTIVE;
315 ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE;
316 ctl->vd[0].access |= active ?
317 SNDRV_CTL_ELEM_ACCESS_WRITE : 0;
318 snd_ctl_notify(codec->bus->card,
319 SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
320 }
321}
322
323static void set_stream_active(struct hda_codec *codec, bool active)
324{
325 struct ad198x_spec *spec = codec->spec;
326 if (active)
327 spec->num_active_streams++;
328 else
329 spec->num_active_streams--;
330 activate_ctl(codec, "Independent HP", spec->num_active_streams == 0);
331}
332
333static int ad1988_independent_hp_info(struct snd_kcontrol *kcontrol,
334 struct snd_ctl_elem_info *uinfo)
335{
336 static const char * const texts[] = { "OFF", "ON", NULL};
337 int index;
338 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
339 uinfo->count = 1;
340 uinfo->value.enumerated.items = 2;
341 index = uinfo->value.enumerated.item;
342 if (index >= 2)
343 index = 1;
344 strcpy(uinfo->value.enumerated.name, texts[index]);
345 return 0;
346}
347
348static int ad1988_independent_hp_get(struct snd_kcontrol *kcontrol,
349 struct snd_ctl_elem_value *ucontrol)
350{
351 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
352 struct ad198x_spec *spec = codec->spec;
353 ucontrol->value.enumerated.item[0] = spec->independent_hp;
354 return 0;
355}
356
357static int ad1988_independent_hp_put(struct snd_kcontrol *kcontrol,
358 struct snd_ctl_elem_value *ucontrol)
359{
360 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
361 struct ad198x_spec *spec = codec->spec;
362 unsigned int select = ucontrol->value.enumerated.item[0];
363 if (spec->independent_hp != select) {
364 spec->independent_hp = select;
365 if (spec->independent_hp)
366 spec->multiout.hp_nid = 0;
367 else
368 spec->multiout.hp_nid = spec->alt_dac_nid[0];
369 return 1;
370 }
371 return 0;
372}
373
374
375
376
377static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo,
378 struct hda_codec *codec,
379 struct snd_pcm_substream *substream)
380{
381 struct ad198x_spec *spec = codec->spec;
382 int err;
383 set_stream_active(codec, true);
384 err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream,
385 hinfo);
386 if (err < 0) {
387 set_stream_active(codec, false);
388 return err;
389 }
390 return 0;
391}
392
393static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
394 struct hda_codec *codec,
395 unsigned int stream_tag,
396 unsigned int format,
397 struct snd_pcm_substream *substream)
398{
399 struct ad198x_spec *spec = codec->spec;
400 return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag,
401 format, substream);
402}
403
404static int ad198x_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
405 struct hda_codec *codec,
406 struct snd_pcm_substream *substream)
407{
408 struct ad198x_spec *spec = codec->spec;
409 return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
410}
411
412static int ad198x_playback_pcm_close(struct hda_pcm_stream *hinfo,
413 struct hda_codec *codec,
414 struct snd_pcm_substream *substream)
415{
416 set_stream_active(codec, false);
417 return 0;
418}
419
420static int ad1988_alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
421 struct hda_codec *codec,
422 struct snd_pcm_substream *substream)
423{
424 struct ad198x_spec *spec = codec->spec;
425 if (!spec->independent_hp)
426 return -EBUSY;
427 set_stream_active(codec, true);
428 return 0;
429}
430
431static int ad1988_alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
432 struct hda_codec *codec,
433 struct snd_pcm_substream *substream)
434{
435 set_stream_active(codec, false);
436 return 0;
437}
438
439static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = {
440 .substreams = 1,
441 .channels_min = 2,
442 .channels_max = 2,
443 .ops = {
444 .open = ad1988_alt_playback_pcm_open,
445 .close = ad1988_alt_playback_pcm_close
446 },
447};
448
449
450
451
452static int ad198x_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
453 struct hda_codec *codec,
454 struct snd_pcm_substream *substream)
455{
456 struct ad198x_spec *spec = codec->spec;
457 return snd_hda_multi_out_dig_open(codec, &spec->multiout);
458}
459
460static int ad198x_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
461 struct hda_codec *codec,
462 struct snd_pcm_substream *substream)
463{
464 struct ad198x_spec *spec = codec->spec;
465 return snd_hda_multi_out_dig_close(codec, &spec->multiout);
466}
467
468static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
469 struct hda_codec *codec,
470 unsigned int stream_tag,
471 unsigned int format,
472 struct snd_pcm_substream *substream)
473{
474 struct ad198x_spec *spec = codec->spec;
475 return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag,
476 format, substream);
477}
478
479static int ad198x_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
480 struct hda_codec *codec,
481 struct snd_pcm_substream *substream)
482{
483 struct ad198x_spec *spec = codec->spec;
484 return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
485}
486
487
488
489
490static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
491 struct hda_codec *codec,
492 unsigned int stream_tag,
493 unsigned int format,
494 struct snd_pcm_substream *substream)
495{
496 struct ad198x_spec *spec = codec->spec;
497 snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number],
498 stream_tag, 0, format);
499 return 0;
500}
501
502static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
503 struct hda_codec *codec,
504 struct snd_pcm_substream *substream)
505{
506 struct ad198x_spec *spec = codec->spec;
507 snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]);
508 return 0;
509}
510
511
512
513static const struct hda_pcm_stream ad198x_pcm_analog_playback = {
514 .substreams = 1,
515 .channels_min = 2,
516 .channels_max = 6,
517 .nid = 0,
518 .ops = {
519 .open = ad198x_playback_pcm_open,
520 .prepare = ad198x_playback_pcm_prepare,
521 .cleanup = ad198x_playback_pcm_cleanup,
522 .close = ad198x_playback_pcm_close
523 },
524};
525
526static const struct hda_pcm_stream ad198x_pcm_analog_capture = {
527 .substreams = 1,
528 .channels_min = 2,
529 .channels_max = 2,
530 .nid = 0,
531 .ops = {
532 .prepare = ad198x_capture_pcm_prepare,
533 .cleanup = ad198x_capture_pcm_cleanup
534 },
535};
536
537static const struct hda_pcm_stream ad198x_pcm_digital_playback = {
538 .substreams = 1,
539 .channels_min = 2,
540 .channels_max = 2,
541 .nid = 0,
542 .ops = {
543 .open = ad198x_dig_playback_pcm_open,
544 .close = ad198x_dig_playback_pcm_close,
545 .prepare = ad198x_dig_playback_pcm_prepare,
546 .cleanup = ad198x_dig_playback_pcm_cleanup
547 },
548};
549
550static const struct hda_pcm_stream ad198x_pcm_digital_capture = {
551 .substreams = 1,
552 .channels_min = 2,
553 .channels_max = 2,
554
555};
556
557static int ad198x_build_pcms(struct hda_codec *codec)
558{
559 struct ad198x_spec *spec = codec->spec;
560 struct hda_pcm *info = spec->pcm_rec;
561
562 codec->num_pcms = 1;
563 codec->pcm_info = info;
564
565 info->name = "AD198x Analog";
566 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback;
567 info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels;
568 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0];
569 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture;
570 info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids;
571 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0];
572
573 if (spec->multiout.dig_out_nid) {
574 info++;
575 codec->num_pcms++;
576 info->name = "AD198x Digital";
577 info->pcm_type = HDA_PCM_TYPE_SPDIF;
578 info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback;
579 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid;
580 if (spec->dig_in_nid) {
581 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture;
582 info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid;
583 }
584 }
585
586 if (spec->alt_dac_nid && spec->stream_analog_alt_playback) {
587 codec->num_pcms++;
588 info = spec->pcm_rec + 2;
589 info->name = "AD198x Headphone";
590 info->pcm_type = HDA_PCM_TYPE_AUDIO;
591 info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
592 *spec->stream_analog_alt_playback;
593 info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid =
594 spec->alt_dac_nid[0];
595 }
596
597 return 0;
598}
599
600static void ad198x_free_kctls(struct hda_codec *codec)
601{
602 struct ad198x_spec *spec = codec->spec;
603
604 if (spec->kctls.list) {
605 struct snd_kcontrol_new *kctl = spec->kctls.list;
606 int i;
607 for (i = 0; i < spec->kctls.used; i++)
608 kfree(kctl[i].name);
609 }
610 snd_array_free(&spec->kctls);
611}
612
613static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
614 hda_nid_t hp)
615{
616 struct ad198x_spec *spec = codec->spec;
617 if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
618 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
619 !spec->inv_eapd ? 0x00 : 0x02);
620 if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
621 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
622 !spec->inv_eapd ? 0x00 : 0x02);
623}
624
625static void ad198x_power_eapd(struct hda_codec *codec)
626{
627
628 switch (codec->vendor_id) {
629 case 0x11d41882:
630 case 0x11d4882a:
631 case 0x11d41884:
632 case 0x11d41984:
633 case 0x11d41883:
634 case 0x11d4184a:
635 case 0x11d4194a:
636 case 0x11d4194b:
637 case 0x11d41988:
638 case 0x11d4198b:
639 case 0x11d4989a:
640 case 0x11d4989b:
641 ad198x_power_eapd_write(codec, 0x12, 0x11);
642 break;
643 case 0x11d41981:
644 case 0x11d41983:
645 ad198x_power_eapd_write(codec, 0x05, 0x06);
646 break;
647 case 0x11d41986:
648 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
649 break;
650 }
651}
652
653static void ad198x_shutup(struct hda_codec *codec)
654{
655 snd_hda_shutup_pins(codec);
656 ad198x_power_eapd(codec);
657}
658
659static void ad198x_free(struct hda_codec *codec)
660{
661 struct ad198x_spec *spec = codec->spec;
662
663 if (!spec)
664 return;
665
666 ad198x_shutup(codec);
667 ad198x_free_kctls(codec);
668 kfree(spec);
669 snd_hda_detach_beep_device(codec);
670}
671
672#ifdef CONFIG_PM
673static int ad198x_suspend(struct hda_codec *codec, pm_message_t state)
674{
675 ad198x_shutup(codec);
676 return 0;
677}
678#endif
679
680static const struct hda_codec_ops ad198x_patch_ops = {
681 .build_controls = ad198x_build_controls,
682 .build_pcms = ad198x_build_pcms,
683 .init = ad198x_init,
684 .free = ad198x_free,
685#ifdef CONFIG_SND_HDA_POWER_SAVE
686 .check_power_status = ad198x_check_power_status,
687#endif
688#ifdef CONFIG_PM
689 .suspend = ad198x_suspend,
690#endif
691 .reboot_notify = ad198x_shutup,
692};
693
694
695
696
697
698
699#define ad198x_eapd_info snd_ctl_boolean_mono_info
700
701static int ad198x_eapd_get(struct snd_kcontrol *kcontrol,
702 struct snd_ctl_elem_value *ucontrol)
703{
704 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
705 struct ad198x_spec *spec = codec->spec;
706 if (spec->inv_eapd)
707 ucontrol->value.integer.value[0] = ! spec->cur_eapd;
708 else
709 ucontrol->value.integer.value[0] = spec->cur_eapd;
710 return 0;
711}
712
713static int ad198x_eapd_put(struct snd_kcontrol *kcontrol,
714 struct snd_ctl_elem_value *ucontrol)
715{
716 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
717 struct ad198x_spec *spec = codec->spec;
718 hda_nid_t nid = kcontrol->private_value & 0xff;
719 unsigned int eapd;
720 eapd = !!ucontrol->value.integer.value[0];
721 if (spec->inv_eapd)
722 eapd = !eapd;
723 if (eapd == spec->cur_eapd)
724 return 0;
725 spec->cur_eapd = eapd;
726 snd_hda_codec_write_cache(codec, nid,
727 0, AC_VERB_SET_EAPD_BTLENABLE,
728 eapd ? 0x02 : 0x00);
729 return 1;
730}
731
732static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
733 struct snd_ctl_elem_info *uinfo);
734static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
735 struct snd_ctl_elem_value *ucontrol);
736static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
737 struct snd_ctl_elem_value *ucontrol);
738
739
740
741
742
743
744#define AD1986A_SPDIF_OUT 0x02
745#define AD1986A_FRONT_DAC 0x03
746#define AD1986A_SURR_DAC 0x04
747#define AD1986A_CLFE_DAC 0x05
748#define AD1986A_ADC 0x06
749
750static const hda_nid_t ad1986a_dac_nids[3] = {
751 AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC
752};
753static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC };
754static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 };
755
756static const struct hda_input_mux ad1986a_capture_source = {
757 .num_items = 7,
758 .items = {
759 { "Mic", 0x0 },
760 { "CD", 0x1 },
761 { "Aux", 0x3 },
762 { "Line", 0x4 },
763 { "Mix", 0x5 },
764 { "Mono", 0x6 },
765 { "Phone", 0x7 },
766 },
767};
768
769
770static const struct hda_bind_ctls ad1986a_bind_pcm_vol = {
771 .ops = &snd_hda_bind_vol,
772 .values = {
773 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
774 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
775 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
776 0
777 },
778};
779
780static const struct hda_bind_ctls ad1986a_bind_pcm_sw = {
781 .ops = &snd_hda_bind_sw,
782 .values = {
783 HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT),
784 HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT),
785 HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT),
786 0
787 },
788};
789
790
791
792
793static const struct snd_kcontrol_new ad1986a_mixers[] = {
794
795
796
797 HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol),
798 HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw),
799 HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
800 HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
801 HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
802 HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
803 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT),
804 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT),
805 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT),
806 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT),
807 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT),
808 HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT),
809 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
810 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
811 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
812 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
813 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
814 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
815 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
816 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
817 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
818 HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT),
819 HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT),
820 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
821 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
822 {
823 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
824 .name = "Capture Source",
825 .info = ad198x_mux_enum_info,
826 .get = ad198x_mux_enum_get,
827 .put = ad198x_mux_enum_put,
828 },
829 HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT),
830 { }
831};
832
833
834static const struct snd_kcontrol_new ad1986a_3st_mixers[] = {
835 {
836 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
837 .name = "Channel Mode",
838 .info = ad198x_ch_mode_info,
839 .get = ad198x_ch_mode_get,
840 .put = ad198x_ch_mode_put,
841 },
842 { }
843};
844
845
846static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC };
847
848
849static const struct hda_bind_ctls ad1986a_laptop_master_vol = {
850 .ops = &snd_hda_bind_vol,
851 .values = {
852 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
853 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
854 0,
855 },
856};
857
858static const struct hda_bind_ctls ad1986a_laptop_master_sw = {
859 .ops = &snd_hda_bind_sw,
860 .values = {
861 HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
862 HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT),
863 0,
864 },
865};
866
867static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = {
868 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
869 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
870 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
871 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
872 HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT),
873 HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT),
874 HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT),
875 HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT),
876 HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT),
877 HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT),
878 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
879 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
880 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
881
882
883
884 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
885 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
886 {
887 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
888 .name = "Capture Source",
889 .info = ad198x_mux_enum_info,
890 .get = ad198x_mux_enum_get,
891 .put = ad198x_mux_enum_put,
892 },
893 { }
894};
895
896
897
898static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = {
899 .num_items = 3,
900 .items = {
901 { "Mic", 0x0 },
902 { "Internal Mic", 0x4 },
903 { "Mix", 0x5 },
904 },
905};
906
907static const struct hda_input_mux ad1986a_automic_capture_source = {
908 .num_items = 2,
909 .items = {
910 { "Mic", 0x0 },
911 { "Mix", 0x5 },
912 },
913};
914
915static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = {
916 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
917 HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw),
918 { }
919};
920
921static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = {
922 HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT),
923 HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT),
924 HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT),
925 HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT),
926 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT),
927 HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT),
928 HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT),
929 {
930 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
931 .name = "Capture Source",
932 .info = ad198x_mux_enum_info,
933 .get = ad198x_mux_enum_get,
934 .put = ad198x_mux_enum_put,
935 },
936 {
937 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
938 .name = "External Amplifier",
939 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
940 .info = ad198x_eapd_info,
941 .get = ad198x_eapd_get,
942 .put = ad198x_eapd_put,
943 .private_value = 0x1b,
944 },
945 { }
946};
947
948static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = {
949 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT),
950 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT),
951 { }
952};
953
954
955static void ad1986a_automic(struct hda_codec *codec)
956{
957 unsigned int present;
958 present = snd_hda_jack_detect(codec, 0x1f);
959
960 snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL,
961 present ? 0 : 2);
962}
963
964#define AD1986A_MIC_EVENT 0x36
965
966static void ad1986a_automic_unsol_event(struct hda_codec *codec,
967 unsigned int res)
968{
969 if ((res >> 26) != AD1986A_MIC_EVENT)
970 return;
971 ad1986a_automic(codec);
972}
973
974static int ad1986a_automic_init(struct hda_codec *codec)
975{
976 ad198x_init(codec);
977 ad1986a_automic(codec);
978 return 0;
979}
980
981
982
983static void ad1986a_update_hp(struct hda_codec *codec)
984{
985 struct ad198x_spec *spec = codec->spec;
986 unsigned int mute;
987
988 if (spec->jack_present)
989 mute = HDA_AMP_MUTE;
990 else
991
992 mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0);
993 snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0,
994 HDA_AMP_MUTE, mute);
995}
996
997static void ad1986a_hp_automute(struct hda_codec *codec)
998{
999 struct ad198x_spec *spec = codec->spec;
1000
1001 spec->jack_present = snd_hda_jack_detect(codec, 0x1a);
1002 if (spec->inv_jack_detect)
1003 spec->jack_present = !spec->jack_present;
1004 ad1986a_update_hp(codec);
1005}
1006
1007#define AD1986A_HP_EVENT 0x37
1008
1009static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
1010{
1011 if ((res >> 26) != AD1986A_HP_EVENT)
1012 return;
1013 ad1986a_hp_automute(codec);
1014}
1015
1016static int ad1986a_hp_init(struct hda_codec *codec)
1017{
1018 ad198x_init(codec);
1019 ad1986a_hp_automute(codec);
1020 return 0;
1021}
1022
1023
1024static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1025 struct snd_ctl_elem_value *ucontrol)
1026{
1027 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1028 long *valp = ucontrol->value.integer.value;
1029 int change;
1030
1031 change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0,
1032 HDA_AMP_MUTE,
1033 valp[0] ? 0 : HDA_AMP_MUTE);
1034 change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0,
1035 HDA_AMP_MUTE,
1036 valp[1] ? 0 : HDA_AMP_MUTE);
1037 if (change)
1038 ad1986a_update_hp(codec);
1039 return change;
1040}
1041
1042static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = {
1043 HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol),
1044 {
1045 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1046 .name = "Master Playback Switch",
1047 .subdevice = HDA_SUBDEV_AMP_FLAG,
1048 .info = snd_hda_mixer_amp_switch_info,
1049 .get = snd_hda_mixer_amp_switch_get,
1050 .put = ad1986a_hp_master_sw_put,
1051 .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT),
1052 },
1053 { }
1054};
1055
1056
1057
1058
1059
1060static const struct hda_verb ad1986a_init_verbs[] = {
1061
1062 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1063 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1064 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1065
1066 {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1067
1068 {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0},
1069 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
1070 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1071 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1072
1073 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0},
1074
1075 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1076
1077 {0x10, AC_VERB_SET_CONNECT_SEL, 0x0},
1078
1079 {0x11, AC_VERB_SET_CONNECT_SEL, 0x0},
1080
1081 {0x12, AC_VERB_SET_CONNECT_SEL, 0x0},
1082
1083 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1084 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1085 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1086 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1087 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1088
1089 {0x18, AC_VERB_SET_CONNECT_SEL, 0x0},
1090
1091 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1092 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1093 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1094 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1095 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1096
1097 {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1098
1099 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1100 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1101 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1102
1103 {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1104
1105 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1106
1107 {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1108 {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1109 {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1110 {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1111 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1112 { }
1113};
1114
1115static const struct hda_verb ad1986a_ch2_init[] = {
1116
1117 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
1118
1119 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 },
1120
1121 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1122
1123 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1124 { }
1125};
1126
1127static const struct hda_verb ad1986a_ch4_init[] = {
1128
1129 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1130 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1131
1132 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
1133 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 },
1134 { }
1135};
1136
1137static const struct hda_verb ad1986a_ch6_init[] = {
1138
1139 { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1140 { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 },
1141
1142 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
1143 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 },
1144 { }
1145};
1146
1147static const struct hda_channel_mode ad1986a_modes[3] = {
1148 { 2, ad1986a_ch2_init },
1149 { 4, ad1986a_ch4_init },
1150 { 6, ad1986a_ch6_init },
1151};
1152
1153
1154static const struct hda_verb ad1986a_eapd_init_verbs[] = {
1155 {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1156 {}
1157};
1158
1159static const struct hda_verb ad1986a_automic_verbs[] = {
1160 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1161 {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
1162
1163 {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0},
1164 {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT},
1165 {}
1166};
1167
1168
1169static const struct hda_verb ad1986a_ultra_init[] = {
1170
1171 { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1172
1173 { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 },
1174 { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1175 { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 },
1176 { }
1177};
1178
1179
1180static const struct hda_verb ad1986a_hp_init_verbs[] = {
1181 {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT},
1182 {}
1183};
1184
1185static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec,
1186 unsigned int res)
1187{
1188 switch (res >> 26) {
1189 case AD1986A_HP_EVENT:
1190 ad1986a_hp_automute(codec);
1191 break;
1192 case AD1986A_MIC_EVENT:
1193 ad1986a_automic(codec);
1194 break;
1195 }
1196}
1197
1198static int ad1986a_samsung_p50_init(struct hda_codec *codec)
1199{
1200 ad198x_init(codec);
1201 ad1986a_hp_automute(codec);
1202 ad1986a_automic(codec);
1203 return 0;
1204}
1205
1206
1207
1208enum {
1209 AD1986A_6STACK,
1210 AD1986A_3STACK,
1211 AD1986A_LAPTOP,
1212 AD1986A_LAPTOP_EAPD,
1213 AD1986A_LAPTOP_AUTOMUTE,
1214 AD1986A_ULTRA,
1215 AD1986A_SAMSUNG,
1216 AD1986A_SAMSUNG_P50,
1217 AD1986A_MODELS
1218};
1219
1220static const char * const ad1986a_models[AD1986A_MODELS] = {
1221 [AD1986A_6STACK] = "6stack",
1222 [AD1986A_3STACK] = "3stack",
1223 [AD1986A_LAPTOP] = "laptop",
1224 [AD1986A_LAPTOP_EAPD] = "laptop-eapd",
1225 [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute",
1226 [AD1986A_ULTRA] = "ultra",
1227 [AD1986A_SAMSUNG] = "samsung",
1228 [AD1986A_SAMSUNG_P50] = "samsung-p50",
1229};
1230
1231static const struct snd_pci_quirk ad1986a_cfg_tbl[] = {
1232 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD),
1233 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD),
1234 SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD),
1235 SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD),
1236 SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD),
1237 SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD),
1238 SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD),
1239 SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD),
1240 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP),
1241 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK),
1242 SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK),
1243 SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP),
1244 SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK),
1245 SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK),
1246 SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK),
1247 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK),
1248 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK),
1249 SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK),
1250 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP),
1251 SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50),
1252 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA),
1253 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG),
1254 SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK),
1255 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP),
1256 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK),
1257 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE),
1258 SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP),
1259 {}
1260};
1261
1262#ifdef CONFIG_SND_HDA_POWER_SAVE
1263static const struct hda_amp_list ad1986a_loopbacks[] = {
1264 { 0x13, HDA_OUTPUT, 0 },
1265 { 0x14, HDA_OUTPUT, 0 },
1266 { 0x15, HDA_OUTPUT, 0 },
1267 { 0x16, HDA_OUTPUT, 0 },
1268 { 0x17, HDA_OUTPUT, 0 },
1269 { }
1270};
1271#endif
1272
1273static int is_jack_available(struct hda_codec *codec, hda_nid_t nid)
1274{
1275 unsigned int conf = snd_hda_codec_get_pincfg(codec, nid);
1276 return get_defcfg_connect(conf) != AC_JACK_PORT_NONE;
1277}
1278
1279static int patch_ad1986a(struct hda_codec *codec)
1280{
1281 struct ad198x_spec *spec;
1282 int err, board_config;
1283
1284 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1285 if (spec == NULL)
1286 return -ENOMEM;
1287
1288 codec->spec = spec;
1289
1290 err = snd_hda_attach_beep_device(codec, 0x19);
1291 if (err < 0) {
1292 ad198x_free(codec);
1293 return err;
1294 }
1295 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
1296
1297 spec->multiout.max_channels = 6;
1298 spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids);
1299 spec->multiout.dac_nids = ad1986a_dac_nids;
1300 spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT;
1301 spec->num_adc_nids = 1;
1302 spec->adc_nids = ad1986a_adc_nids;
1303 spec->capsrc_nids = ad1986a_capsrc_nids;
1304 spec->input_mux = &ad1986a_capture_source;
1305 spec->num_mixers = 1;
1306 spec->mixers[0] = ad1986a_mixers;
1307 spec->num_init_verbs = 1;
1308 spec->init_verbs[0] = ad1986a_init_verbs;
1309#ifdef CONFIG_SND_HDA_POWER_SAVE
1310 spec->loopback.amplist = ad1986a_loopbacks;
1311#endif
1312 spec->vmaster_nid = 0x1b;
1313 spec->inv_eapd = 1;
1314
1315 codec->patch_ops = ad198x_patch_ops;
1316
1317
1318 board_config = snd_hda_check_board_config(codec, AD1986A_MODELS,
1319 ad1986a_models,
1320 ad1986a_cfg_tbl);
1321 switch (board_config) {
1322 case AD1986A_3STACK:
1323 spec->num_mixers = 2;
1324 spec->mixers[1] = ad1986a_3st_mixers;
1325 spec->num_init_verbs = 2;
1326 spec->init_verbs[1] = ad1986a_ch2_init;
1327 spec->channel_mode = ad1986a_modes;
1328 spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes);
1329 spec->need_dac_fix = 1;
1330 spec->multiout.max_channels = 2;
1331 spec->multiout.num_dacs = 1;
1332 break;
1333 case AD1986A_LAPTOP:
1334 spec->mixers[0] = ad1986a_laptop_mixers;
1335 spec->multiout.max_channels = 2;
1336 spec->multiout.num_dacs = 1;
1337 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1338 break;
1339 case AD1986A_LAPTOP_EAPD:
1340 spec->num_mixers = 3;
1341 spec->mixers[0] = ad1986a_laptop_master_mixers;
1342 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1343 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1344 spec->num_init_verbs = 2;
1345 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1346 spec->multiout.max_channels = 2;
1347 spec->multiout.num_dacs = 1;
1348 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1349 if (!is_jack_available(codec, 0x25))
1350 spec->multiout.dig_out_nid = 0;
1351 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1352 break;
1353 case AD1986A_SAMSUNG:
1354 spec->num_mixers = 2;
1355 spec->mixers[0] = ad1986a_laptop_master_mixers;
1356 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1357 spec->num_init_verbs = 3;
1358 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1359 spec->init_verbs[2] = ad1986a_automic_verbs;
1360 spec->multiout.max_channels = 2;
1361 spec->multiout.num_dacs = 1;
1362 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1363 if (!is_jack_available(codec, 0x25))
1364 spec->multiout.dig_out_nid = 0;
1365 spec->input_mux = &ad1986a_automic_capture_source;
1366 codec->patch_ops.unsol_event = ad1986a_automic_unsol_event;
1367 codec->patch_ops.init = ad1986a_automic_init;
1368 break;
1369 case AD1986A_SAMSUNG_P50:
1370 spec->num_mixers = 2;
1371 spec->mixers[0] = ad1986a_automute_master_mixers;
1372 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1373 spec->num_init_verbs = 4;
1374 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1375 spec->init_verbs[2] = ad1986a_automic_verbs;
1376 spec->init_verbs[3] = ad1986a_hp_init_verbs;
1377 spec->multiout.max_channels = 2;
1378 spec->multiout.num_dacs = 1;
1379 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1380 if (!is_jack_available(codec, 0x25))
1381 spec->multiout.dig_out_nid = 0;
1382 spec->input_mux = &ad1986a_automic_capture_source;
1383 codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event;
1384 codec->patch_ops.init = ad1986a_samsung_p50_init;
1385 break;
1386 case AD1986A_LAPTOP_AUTOMUTE:
1387 spec->num_mixers = 3;
1388 spec->mixers[0] = ad1986a_automute_master_mixers;
1389 spec->mixers[1] = ad1986a_laptop_eapd_mixers;
1390 spec->mixers[2] = ad1986a_laptop_intmic_mixers;
1391 spec->num_init_verbs = 3;
1392 spec->init_verbs[1] = ad1986a_eapd_init_verbs;
1393 spec->init_verbs[2] = ad1986a_hp_init_verbs;
1394 spec->multiout.max_channels = 2;
1395 spec->multiout.num_dacs = 1;
1396 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1397 if (!is_jack_available(codec, 0x25))
1398 spec->multiout.dig_out_nid = 0;
1399 spec->input_mux = &ad1986a_laptop_eapd_capture_source;
1400 codec->patch_ops.unsol_event = ad1986a_hp_unsol_event;
1401 codec->patch_ops.init = ad1986a_hp_init;
1402
1403
1404
1405 spec->inv_jack_detect = 1;
1406 break;
1407 case AD1986A_ULTRA:
1408 spec->mixers[0] = ad1986a_laptop_eapd_mixers;
1409 spec->num_init_verbs = 2;
1410 spec->init_verbs[1] = ad1986a_ultra_init;
1411 spec->multiout.max_channels = 2;
1412 spec->multiout.num_dacs = 1;
1413 spec->multiout.dac_nids = ad1986a_laptop_dac_nids;
1414 spec->multiout.dig_out_nid = 0;
1415 break;
1416 }
1417
1418
1419
1420
1421
1422
1423
1424 spec->multiout.no_share_stream = 1;
1425
1426 codec->no_trigger_sense = 1;
1427 codec->no_sticky_stream = 1;
1428
1429 return 0;
1430}
1431
1432
1433
1434
1435
1436#define AD1983_SPDIF_OUT 0x02
1437#define AD1983_DAC 0x03
1438#define AD1983_ADC 0x04
1439
1440static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC };
1441static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC };
1442static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 };
1443
1444static const struct hda_input_mux ad1983_capture_source = {
1445 .num_items = 4,
1446 .items = {
1447 { "Mic", 0x0 },
1448 { "Line", 0x1 },
1449 { "Mix", 0x2 },
1450 { "Mix Mono", 0x3 },
1451 },
1452};
1453
1454
1455
1456
1457static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1458{
1459 static const char * const texts[] = { "PCM", "ADC" };
1460
1461 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1462 uinfo->count = 1;
1463 uinfo->value.enumerated.items = 2;
1464 if (uinfo->value.enumerated.item > 1)
1465 uinfo->value.enumerated.item = 1;
1466 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1467 return 0;
1468}
1469
1470static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1471{
1472 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1473 struct ad198x_spec *spec = codec->spec;
1474
1475 ucontrol->value.enumerated.item[0] = spec->spdif_route;
1476 return 0;
1477}
1478
1479static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1480{
1481 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1482 struct ad198x_spec *spec = codec->spec;
1483
1484 if (ucontrol->value.enumerated.item[0] > 1)
1485 return -EINVAL;
1486 if (spec->spdif_route != ucontrol->value.enumerated.item[0]) {
1487 spec->spdif_route = ucontrol->value.enumerated.item[0];
1488 snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0,
1489 AC_VERB_SET_CONNECT_SEL,
1490 spec->spdif_route);
1491 return 1;
1492 }
1493 return 0;
1494}
1495
1496static const struct snd_kcontrol_new ad1983_mixers[] = {
1497 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1498 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1499 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1500 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1501 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1502 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1503 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1504 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1505 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1506 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1507 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1508 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1509 HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT),
1510 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1511 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1512 {
1513 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1514 .name = "Capture Source",
1515 .info = ad198x_mux_enum_info,
1516 .get = ad198x_mux_enum_get,
1517 .put = ad198x_mux_enum_put,
1518 },
1519 {
1520 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1521 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1522 .info = ad1983_spdif_route_info,
1523 .get = ad1983_spdif_route_get,
1524 .put = ad1983_spdif_route_put,
1525 },
1526 { }
1527};
1528
1529static const struct hda_verb ad1983_init_verbs[] = {
1530
1531 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1532 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1533 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1534
1535 {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1536 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1537 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1538 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1539
1540 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1541 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1542
1543 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1544
1545 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
1546
1547 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
1548
1549 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1550
1551 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1552 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1553
1554 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1555
1556 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1557
1558 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1559
1560 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1561
1562 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1563
1564 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1565 { }
1566};
1567
1568#ifdef CONFIG_SND_HDA_POWER_SAVE
1569static const struct hda_amp_list ad1983_loopbacks[] = {
1570 { 0x12, HDA_OUTPUT, 0 },
1571 { 0x13, HDA_OUTPUT, 0 },
1572 { }
1573};
1574#endif
1575
1576static int patch_ad1983(struct hda_codec *codec)
1577{
1578 struct ad198x_spec *spec;
1579 int err;
1580
1581 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1582 if (spec == NULL)
1583 return -ENOMEM;
1584
1585 codec->spec = spec;
1586
1587 err = snd_hda_attach_beep_device(codec, 0x10);
1588 if (err < 0) {
1589 ad198x_free(codec);
1590 return err;
1591 }
1592 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1593
1594 spec->multiout.max_channels = 2;
1595 spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids);
1596 spec->multiout.dac_nids = ad1983_dac_nids;
1597 spec->multiout.dig_out_nid = AD1983_SPDIF_OUT;
1598 spec->num_adc_nids = 1;
1599 spec->adc_nids = ad1983_adc_nids;
1600 spec->capsrc_nids = ad1983_capsrc_nids;
1601 spec->input_mux = &ad1983_capture_source;
1602 spec->num_mixers = 1;
1603 spec->mixers[0] = ad1983_mixers;
1604 spec->num_init_verbs = 1;
1605 spec->init_verbs[0] = ad1983_init_verbs;
1606 spec->spdif_route = 0;
1607#ifdef CONFIG_SND_HDA_POWER_SAVE
1608 spec->loopback.amplist = ad1983_loopbacks;
1609#endif
1610 spec->vmaster_nid = 0x05;
1611
1612 codec->patch_ops = ad198x_patch_ops;
1613
1614 codec->no_trigger_sense = 1;
1615 codec->no_sticky_stream = 1;
1616
1617 return 0;
1618}
1619
1620
1621
1622
1623
1624
1625#define AD1981_SPDIF_OUT 0x02
1626#define AD1981_DAC 0x03
1627#define AD1981_ADC 0x04
1628
1629static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC };
1630static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC };
1631static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 };
1632
1633
1634static const struct hda_input_mux ad1981_capture_source = {
1635 .num_items = 7,
1636 .items = {
1637 { "Front Mic", 0x0 },
1638 { "Line", 0x1 },
1639 { "Mix", 0x2 },
1640 { "Mix Mono", 0x3 },
1641 { "CD", 0x4 },
1642 { "Mic", 0x6 },
1643 { "Aux", 0x7 },
1644 },
1645};
1646
1647static const struct snd_kcontrol_new ad1981_mixers[] = {
1648 HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1649 HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1650 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT),
1651 HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT),
1652 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT),
1653 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT),
1654 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1655 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1656 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1657 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1658 HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1659 HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1660 HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
1661 HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT),
1662 HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1663 HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1664 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1665 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1666 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1667 HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
1668 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1669 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1670 {
1671 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1672 .name = "Capture Source",
1673 .info = ad198x_mux_enum_info,
1674 .get = ad198x_mux_enum_get,
1675 .put = ad198x_mux_enum_put,
1676 },
1677
1678 {
1679 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1680 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1681 .info = ad1983_spdif_route_info,
1682 .get = ad1983_spdif_route_get,
1683 .put = ad1983_spdif_route_put,
1684 },
1685 { }
1686};
1687
1688static const struct hda_verb ad1981_init_verbs[] = {
1689
1690 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1691 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1692 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1693
1694 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1695 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1696 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1697 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1698 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1699 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1700 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1701
1702 {0x05, AC_VERB_SET_CONNECT_SEL, 0x01},
1703 {0x06, AC_VERB_SET_CONNECT_SEL, 0x01},
1704
1705 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03},
1706
1707 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1708 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1709
1710 {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1711 {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
1712
1713 {0x15, AC_VERB_SET_CONNECT_SEL, 0x0},
1714 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1715
1716 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
1717
1718 {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1719
1720 {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
1721
1722 {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 },
1723
1724 {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1725 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
1726
1727 {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 },
1728
1729 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00},
1730
1731 {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1732 { }
1733};
1734
1735#ifdef CONFIG_SND_HDA_POWER_SAVE
1736static const struct hda_amp_list ad1981_loopbacks[] = {
1737 { 0x12, HDA_OUTPUT, 0 },
1738 { 0x13, HDA_OUTPUT, 0 },
1739 { 0x1b, HDA_OUTPUT, 0 },
1740 { 0x1c, HDA_OUTPUT, 0 },
1741 { 0x1d, HDA_OUTPUT, 0 },
1742 { }
1743};
1744#endif
1745
1746
1747
1748
1749
1750
1751
1752
1753#define AD1981_HP_EVENT 0x37
1754#define AD1981_MIC_EVENT 0x38
1755
1756static const struct hda_verb ad1981_hp_init_verbs[] = {
1757 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 },
1758
1759 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1760 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1761 {}
1762};
1763
1764
1765static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol,
1766 struct snd_ctl_elem_value *ucontrol)
1767{
1768 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
1769 struct ad198x_spec *spec = codec->spec;
1770
1771 if (! ad198x_eapd_put(kcontrol, ucontrol))
1772 return 0;
1773
1774 snd_hda_codec_write(codec, 0x05, 0,
1775 AC_VERB_SET_PIN_WIDGET_CONTROL,
1776 spec->cur_eapd ? PIN_OUT : 0);
1777
1778 snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0,
1779 HDA_AMP_MUTE,
1780 spec->cur_eapd ? 0 : HDA_AMP_MUTE);
1781 return 1;
1782}
1783
1784
1785static const struct hda_bind_ctls ad1981_hp_bind_master_vol = {
1786 .ops = &snd_hda_bind_vol,
1787 .values = {
1788 HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT),
1789 HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT),
1790 0
1791 },
1792};
1793
1794
1795static void ad1981_hp_automute(struct hda_codec *codec)
1796{
1797 unsigned int present;
1798
1799 present = snd_hda_jack_detect(codec, 0x06);
1800 snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0,
1801 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
1802}
1803
1804
1805static void ad1981_hp_automic(struct hda_codec *codec)
1806{
1807 static const struct hda_verb mic_jack_on[] = {
1808 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1809 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1810 {}
1811 };
1812 static const struct hda_verb mic_jack_off[] = {
1813 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080},
1814 {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
1815 {}
1816 };
1817 unsigned int present;
1818
1819 present = snd_hda_jack_detect(codec, 0x08);
1820 if (present)
1821 snd_hda_sequence_write(codec, mic_jack_on);
1822 else
1823 snd_hda_sequence_write(codec, mic_jack_off);
1824}
1825
1826
1827static void ad1981_hp_unsol_event(struct hda_codec *codec,
1828 unsigned int res)
1829{
1830 res >>= 26;
1831 switch (res) {
1832 case AD1981_HP_EVENT:
1833 ad1981_hp_automute(codec);
1834 break;
1835 case AD1981_MIC_EVENT:
1836 ad1981_hp_automic(codec);
1837 break;
1838 }
1839}
1840
1841static const struct hda_input_mux ad1981_hp_capture_source = {
1842 .num_items = 3,
1843 .items = {
1844 { "Mic", 0x0 },
1845 { "Docking-Station", 0x1 },
1846 { "Mix", 0x2 },
1847 },
1848};
1849
1850static const struct snd_kcontrol_new ad1981_hp_mixers[] = {
1851 HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol),
1852 {
1853 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1854 .subdevice = HDA_SUBDEV_NID_FLAG | 0x05,
1855 .name = "Master Playback Switch",
1856 .info = ad198x_eapd_info,
1857 .get = ad198x_eapd_get,
1858 .put = ad1981_hp_master_sw_put,
1859 .private_value = 0x05,
1860 },
1861 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1862 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1863#if 0
1864
1865
1866
1867 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1868 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1869 HDA_CODEC_VOLUME("Docking-Station Playback Volume", 0x13, 0x0, HDA_OUTPUT),
1870 HDA_CODEC_MUTE("Docking-Station Playback Switch", 0x13, 0x0, HDA_OUTPUT),
1871 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT),
1872 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT),
1873
1874 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1875 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1876#endif
1877 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1878 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT),
1879 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1880 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1881 {
1882 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1883 .name = "Capture Source",
1884 .info = ad198x_mux_enum_info,
1885 .get = ad198x_mux_enum_get,
1886 .put = ad198x_mux_enum_put,
1887 },
1888 { }
1889};
1890
1891
1892static int ad1981_hp_init(struct hda_codec *codec)
1893{
1894 ad198x_init(codec);
1895 ad1981_hp_automute(codec);
1896 ad1981_hp_automic(codec);
1897 return 0;
1898}
1899
1900
1901static const struct hda_verb ad1981_toshiba_init_verbs[] = {
1902 {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 },
1903
1904 {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT},
1905 {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT},
1906 {}
1907};
1908
1909static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = {
1910 HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT),
1911 HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT),
1912 { }
1913};
1914
1915
1916static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = {
1917 HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT),
1918 HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT),
1919 HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT),
1920 HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT),
1921 HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT),
1922 HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT),
1923 HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
1924 HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT),
1925 HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT),
1926 HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT),
1927 HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT),
1928 {
1929 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1930 .name = "Capture Source",
1931 .info = ad198x_mux_enum_info,
1932 .get = ad198x_mux_enum_get,
1933 .put = ad198x_mux_enum_put,
1934 },
1935
1936 {
1937 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1938 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
1939 .info = ad1983_spdif_route_info,
1940 .get = ad1983_spdif_route_get,
1941 .put = ad1983_spdif_route_put,
1942 },
1943 { }
1944};
1945
1946static const struct hda_input_mux ad1981_thinkpad_capture_source = {
1947 .num_items = 3,
1948 .items = {
1949 { "Mic", 0x0 },
1950 { "Mix", 0x2 },
1951 { "CD", 0x4 },
1952 },
1953};
1954
1955
1956enum {
1957 AD1981_BASIC,
1958 AD1981_HP,
1959 AD1981_THINKPAD,
1960 AD1981_TOSHIBA,
1961 AD1981_MODELS
1962};
1963
1964static const char * const ad1981_models[AD1981_MODELS] = {
1965 [AD1981_HP] = "hp",
1966 [AD1981_THINKPAD] = "thinkpad",
1967 [AD1981_BASIC] = "basic",
1968 [AD1981_TOSHIBA] = "toshiba"
1969};
1970
1971static const struct snd_pci_quirk ad1981_cfg_tbl[] = {
1972 SND_PCI_QUIRK(0x1014, 0x0597, "Lenovo Z60", AD1981_THINKPAD),
1973 SND_PCI_QUIRK(0x1014, 0x05b7, "Lenovo Z60m", AD1981_THINKPAD),
1974
1975 SND_PCI_QUIRK_VENDOR(0x103c, "HP nx", AD1981_HP),
1976 SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA),
1977
1978 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD),
1979
1980 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP),
1981 {}
1982};
1983
1984static int patch_ad1981(struct hda_codec *codec)
1985{
1986 struct ad198x_spec *spec;
1987 int err, board_config;
1988
1989 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
1990 if (spec == NULL)
1991 return -ENOMEM;
1992
1993 codec->spec = spec;
1994
1995 err = snd_hda_attach_beep_device(codec, 0x10);
1996 if (err < 0) {
1997 ad198x_free(codec);
1998 return err;
1999 }
2000 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
2001
2002 spec->multiout.max_channels = 2;
2003 spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids);
2004 spec->multiout.dac_nids = ad1981_dac_nids;
2005 spec->multiout.dig_out_nid = AD1981_SPDIF_OUT;
2006 spec->num_adc_nids = 1;
2007 spec->adc_nids = ad1981_adc_nids;
2008 spec->capsrc_nids = ad1981_capsrc_nids;
2009 spec->input_mux = &ad1981_capture_source;
2010 spec->num_mixers = 1;
2011 spec->mixers[0] = ad1981_mixers;
2012 spec->num_init_verbs = 1;
2013 spec->init_verbs[0] = ad1981_init_verbs;
2014 spec->spdif_route = 0;
2015#ifdef CONFIG_SND_HDA_POWER_SAVE
2016 spec->loopback.amplist = ad1981_loopbacks;
2017#endif
2018 spec->vmaster_nid = 0x05;
2019
2020 codec->patch_ops = ad198x_patch_ops;
2021
2022
2023 board_config = snd_hda_check_board_config(codec, AD1981_MODELS,
2024 ad1981_models,
2025 ad1981_cfg_tbl);
2026 switch (board_config) {
2027 case AD1981_HP:
2028 spec->mixers[0] = ad1981_hp_mixers;
2029 spec->num_init_verbs = 2;
2030 spec->init_verbs[1] = ad1981_hp_init_verbs;
2031 if (!is_jack_available(codec, 0x0a))
2032 spec->multiout.dig_out_nid = 0;
2033 spec->input_mux = &ad1981_hp_capture_source;
2034
2035 codec->patch_ops.init = ad1981_hp_init;
2036 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
2037
2038
2039
2040 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2041 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2042 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2043 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2044 (1 << AC_AMPCAP_MUTE_SHIFT));
2045 break;
2046 case AD1981_THINKPAD:
2047 spec->mixers[0] = ad1981_thinkpad_mixers;
2048 spec->input_mux = &ad1981_thinkpad_capture_source;
2049
2050
2051
2052 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
2053 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
2054 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
2055 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
2056 (1 << AC_AMPCAP_MUTE_SHIFT));
2057 break;
2058 case AD1981_TOSHIBA:
2059 spec->mixers[0] = ad1981_hp_mixers;
2060 spec->mixers[1] = ad1981_toshiba_mixers;
2061 spec->num_init_verbs = 2;
2062 spec->init_verbs[1] = ad1981_toshiba_init_verbs;
2063 spec->multiout.dig_out_nid = 0;
2064 spec->input_mux = &ad1981_hp_capture_source;
2065 codec->patch_ops.init = ad1981_hp_init;
2066 codec->patch_ops.unsol_event = ad1981_hp_unsol_event;
2067 break;
2068 }
2069
2070 codec->no_trigger_sense = 1;
2071 codec->no_sticky_stream = 1;
2072
2073 return 0;
2074}
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164enum {
2165 AD1988_6STACK,
2166 AD1988_6STACK_DIG,
2167 AD1988_3STACK,
2168 AD1988_3STACK_DIG,
2169 AD1988_LAPTOP,
2170 AD1988_LAPTOP_DIG,
2171 AD1988_AUTO,
2172 AD1988_MODEL_LAST,
2173};
2174
2175
2176#define AD1988A_REV2 0x100200
2177
2178#define is_rev2(codec) \
2179 ((codec)->vendor_id == 0x11d41988 && \
2180 (codec)->revision_id == AD1988A_REV2)
2181
2182
2183
2184
2185
2186static const hda_nid_t ad1988_6stack_dac_nids[4] = {
2187 0x04, 0x06, 0x05, 0x0a
2188};
2189
2190static const hda_nid_t ad1988_3stack_dac_nids[3] = {
2191 0x04, 0x05, 0x0a
2192};
2193
2194
2195static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = {
2196 0x04, 0x05, 0x0a, 0x06
2197};
2198
2199static const hda_nid_t ad1988_alt_dac_nid[1] = {
2200 0x03
2201};
2202
2203static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = {
2204 0x04, 0x0a, 0x06
2205};
2206
2207static const hda_nid_t ad1988_adc_nids[3] = {
2208 0x08, 0x09, 0x0f
2209};
2210
2211static const hda_nid_t ad1988_capsrc_nids[3] = {
2212 0x0c, 0x0d, 0x0e
2213};
2214
2215#define AD1988_SPDIF_OUT 0x02
2216#define AD1988_SPDIF_OUT_HDMI 0x0b
2217#define AD1988_SPDIF_IN 0x07
2218
2219static const hda_nid_t ad1989b_slave_dig_outs[] = {
2220 AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0
2221};
2222
2223static const struct hda_input_mux ad1988_6stack_capture_source = {
2224 .num_items = 5,
2225 .items = {
2226 { "Front Mic", 0x1 },
2227 { "Line", 0x2 },
2228 { "Mic", 0x4 },
2229 { "CD", 0x5 },
2230 { "Mix", 0x9 },
2231 },
2232};
2233
2234static const struct hda_input_mux ad1988_laptop_capture_source = {
2235 .num_items = 3,
2236 .items = {
2237 { "Mic/Line", 0x1 },
2238 { "CD", 0x5 },
2239 { "Mix", 0x9 },
2240 },
2241};
2242
2243
2244
2245static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol,
2246 struct snd_ctl_elem_info *uinfo)
2247{
2248 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2249 struct ad198x_spec *spec = codec->spec;
2250 return snd_hda_ch_mode_info(codec, uinfo, spec->channel_mode,
2251 spec->num_channel_mode);
2252}
2253
2254static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol,
2255 struct snd_ctl_elem_value *ucontrol)
2256{
2257 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2258 struct ad198x_spec *spec = codec->spec;
2259 return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode,
2260 spec->num_channel_mode, spec->multiout.max_channels);
2261}
2262
2263static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol,
2264 struct snd_ctl_elem_value *ucontrol)
2265{
2266 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2267 struct ad198x_spec *spec = codec->spec;
2268 int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode,
2269 spec->num_channel_mode,
2270 &spec->multiout.max_channels);
2271 if (err >= 0 && spec->need_dac_fix)
2272 spec->multiout.num_dacs = spec->multiout.max_channels / 2;
2273 return err;
2274}
2275
2276static const struct snd_kcontrol_new ad1988_hp_mixers[] = {
2277 {
2278 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2279 .name = "Independent HP",
2280 .info = ad1988_independent_hp_info,
2281 .get = ad1988_independent_hp_get,
2282 .put = ad1988_independent_hp_put,
2283 },
2284 { }
2285};
2286
2287
2288static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = {
2289 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2290 HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2291 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2292 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2293 HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2294 { }
2295};
2296
2297static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = {
2298 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2299 HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT),
2300 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT),
2301 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT),
2302 HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT),
2303 { }
2304};
2305
2306static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = {
2307 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2308 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2309 HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT),
2310 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT),
2311 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT),
2312 HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT),
2313 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2314 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2315
2316 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2317 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2318 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2319 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2320 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2321 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2322 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2323 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2324
2325 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2326 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2327
2328 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2329 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2330 { }
2331};
2332
2333
2334static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = {
2335 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2336 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2337 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
2338 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
2339 { }
2340};
2341
2342static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = {
2343 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2344 HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT),
2345 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT),
2346 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT),
2347 { }
2348};
2349
2350static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = {
2351 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2352 HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT),
2353 HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT),
2354 HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT),
2355 HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT),
2356 HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT),
2357 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2358
2359 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2360 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2361 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2362 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2363 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2364 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2365 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT),
2366 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT),
2367
2368 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2369 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2370
2371 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2372 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
2373 {
2374 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2375 .name = "Channel Mode",
2376 .info = ad198x_ch_mode_info,
2377 .get = ad198x_ch_mode_get,
2378 .put = ad198x_ch_mode_put,
2379 },
2380
2381 { }
2382};
2383
2384
2385static const struct snd_kcontrol_new ad1988_laptop_mixers[] = {
2386 HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT),
2387 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
2388 HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT),
2389 HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT),
2390
2391 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT),
2392 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT),
2393 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT),
2394 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT),
2395 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT),
2396 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT),
2397
2398 HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT),
2399 HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT),
2400
2401 HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
2402
2403 {
2404 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2405 .name = "External Amplifier",
2406 .subdevice = HDA_SUBDEV_NID_FLAG | 0x12,
2407 .info = ad198x_eapd_info,
2408 .get = ad198x_eapd_get,
2409 .put = ad198x_eapd_put,
2410 .private_value = 0x12,
2411 },
2412
2413 { }
2414};
2415
2416
2417static const struct snd_kcontrol_new ad1988_capture_mixers[] = {
2418 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
2419 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
2420 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
2421 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
2422 HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT),
2423 HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT),
2424 {
2425 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2426
2427
2428
2429
2430 .name = "Input Source",
2431 .count = 3,
2432 .info = ad198x_mux_enum_info,
2433 .get = ad198x_mux_enum_get,
2434 .put = ad198x_mux_enum_put,
2435 },
2436 { }
2437};
2438
2439static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol,
2440 struct snd_ctl_elem_info *uinfo)
2441{
2442 static const char * const texts[] = {
2443 "PCM", "ADC1", "ADC2", "ADC3"
2444 };
2445 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2446 uinfo->count = 1;
2447 uinfo->value.enumerated.items = 4;
2448 if (uinfo->value.enumerated.item >= 4)
2449 uinfo->value.enumerated.item = 3;
2450 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
2451 return 0;
2452}
2453
2454static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol,
2455 struct snd_ctl_elem_value *ucontrol)
2456{
2457 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2458 unsigned int sel;
2459
2460 sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE,
2461 AC_AMP_GET_INPUT);
2462 if (!(sel & 0x80))
2463 ucontrol->value.enumerated.item[0] = 0;
2464 else {
2465 sel = snd_hda_codec_read(codec, 0x0b, 0,
2466 AC_VERB_GET_CONNECT_SEL, 0);
2467 if (sel < 3)
2468 sel++;
2469 else
2470 sel = 0;
2471 ucontrol->value.enumerated.item[0] = sel;
2472 }
2473 return 0;
2474}
2475
2476static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol,
2477 struct snd_ctl_elem_value *ucontrol)
2478{
2479 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
2480 unsigned int val, sel;
2481 int change;
2482
2483 val = ucontrol->value.enumerated.item[0];
2484 if (val > 3)
2485 return -EINVAL;
2486 if (!val) {
2487 sel = snd_hda_codec_read(codec, 0x1d, 0,
2488 AC_VERB_GET_AMP_GAIN_MUTE,
2489 AC_AMP_GET_INPUT);
2490 change = sel & 0x80;
2491 if (change) {
2492 snd_hda_codec_write_cache(codec, 0x1d, 0,
2493 AC_VERB_SET_AMP_GAIN_MUTE,
2494 AMP_IN_UNMUTE(0));
2495 snd_hda_codec_write_cache(codec, 0x1d, 0,
2496 AC_VERB_SET_AMP_GAIN_MUTE,
2497 AMP_IN_MUTE(1));
2498 }
2499 } else {
2500 sel = snd_hda_codec_read(codec, 0x1d, 0,
2501 AC_VERB_GET_AMP_GAIN_MUTE,
2502 AC_AMP_GET_INPUT | 0x01);
2503 change = sel & 0x80;
2504 if (change) {
2505 snd_hda_codec_write_cache(codec, 0x1d, 0,
2506 AC_VERB_SET_AMP_GAIN_MUTE,
2507 AMP_IN_MUTE(0));
2508 snd_hda_codec_write_cache(codec, 0x1d, 0,
2509 AC_VERB_SET_AMP_GAIN_MUTE,
2510 AMP_IN_UNMUTE(1));
2511 }
2512 sel = snd_hda_codec_read(codec, 0x0b, 0,
2513 AC_VERB_GET_CONNECT_SEL, 0) + 1;
2514 change |= sel != val;
2515 if (change)
2516 snd_hda_codec_write_cache(codec, 0x0b, 0,
2517 AC_VERB_SET_CONNECT_SEL,
2518 val - 1);
2519 }
2520 return change;
2521}
2522
2523static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = {
2524 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2525 {
2526 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2527 .name = "IEC958 Playback Source",
2528 .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b,
2529 .info = ad1988_spdif_playback_source_info,
2530 .get = ad1988_spdif_playback_source_get,
2531 .put = ad1988_spdif_playback_source_put,
2532 },
2533 { }
2534};
2535
2536static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = {
2537 HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT),
2538 { }
2539};
2540
2541static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = {
2542 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
2543 HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT),
2544 { }
2545};
2546
2547
2548
2549
2550
2551
2552
2553
2554static const struct hda_verb ad1988_6stack_init_verbs[] = {
2555
2556 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2557 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2558 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2559 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2560
2561 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00},
2562 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2563 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2564 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2565 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2566
2567 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2568 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2569 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2570 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2571
2572 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2573 {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2574 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2575 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2576
2577 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2578 {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2579 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2580 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2581
2582 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2583 {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2584 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2585 {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2586
2587 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1},
2588 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2589 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2590 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2591 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f},
2592
2593 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2594 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2595 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2596
2597 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2598 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2599 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2600 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2601
2602 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2603 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2604 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2605 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2606
2607 {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
2608
2609 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f},
2610
2611 { }
2612};
2613
2614static const struct hda_verb ad1988_6stack_fp_init_verbs[] = {
2615
2616 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2617
2618 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00},
2619 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2620 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2621 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2622 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2623
2624 { }
2625};
2626
2627static const struct hda_verb ad1988_capture_init_verbs[] = {
2628
2629 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2630 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2631 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2632 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2633 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2634 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2635 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2636 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2637
2638 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2639 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2640 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2641
2642 { }
2643};
2644
2645static const struct hda_verb ad1988_spdif_init_verbs[] = {
2646
2647 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
2648 {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0},
2649 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2650 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2651
2652 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27},
2653
2654 { }
2655};
2656
2657static const struct hda_verb ad1988_spdif_in_init_verbs[] = {
2658
2659 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
2660 { }
2661};
2662
2663
2664static const struct hda_verb ad1989_spdif_init_verbs[] = {
2665
2666 {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2667 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27},
2668
2669 {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2670 {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27},
2671 { }
2672};
2673
2674
2675
2676
2677static const struct hda_verb ad1988_3stack_ch2_init[] = {
2678
2679 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2680 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN },
2681
2682 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2683 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 },
2684 { }
2685};
2686
2687static const struct hda_verb ad1988_3stack_ch6_init[] = {
2688
2689 { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2690 { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2691
2692 { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT },
2693 { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2694 { }
2695};
2696
2697static const struct hda_channel_mode ad1988_3stack_modes[2] = {
2698 { 2, ad1988_3stack_ch2_init },
2699 { 6, ad1988_3stack_ch6_init },
2700};
2701
2702static const struct hda_verb ad1988_3stack_init_verbs[] = {
2703
2704 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2705 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2706 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2707 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2708
2709 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00},
2710 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2711 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2712 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2713 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2714
2715 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2716 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2717 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2718 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2719
2720 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1},
2721 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2722 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2723 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2724 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f},
2725
2726 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2727 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2728 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2729
2730 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2731 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2732 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2733 {0x31, AC_VERB_SET_CONNECT_SEL, 0x0},
2734 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2735
2736 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2737 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2738 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2739 {0x32, AC_VERB_SET_CONNECT_SEL, 0x1},
2740 {0x34, AC_VERB_SET_CONNECT_SEL, 0x0},
2741
2742 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2743 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2744 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2745 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2746 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2747 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2748 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2749 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2750
2751 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2752 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2753 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2754
2755 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f},
2756 { }
2757};
2758
2759
2760
2761
2762static const struct hda_verb ad1988_laptop_hp_on[] = {
2763
2764 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2765 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2766 { }
2767};
2768static const struct hda_verb ad1988_laptop_hp_off[] = {
2769
2770 { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
2771 { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE },
2772 { }
2773};
2774
2775#define AD1988_HP_EVENT 0x01
2776
2777static const struct hda_verb ad1988_laptop_init_verbs[] = {
2778
2779 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2780 {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2781 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2782 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2783
2784 {0x37, AC_VERB_SET_CONNECT_SEL, 0x00},
2785 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2786 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2787 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2788 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
2789
2790 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT },
2791
2792 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2793 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2794 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2795 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2796 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00},
2797
2798 {0x36, AC_VERB_SET_CONNECT_SEL, 0x1},
2799 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2800 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2801 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2802 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f},
2803
2804 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
2805 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
2806 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2807
2808 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
2809 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
2810 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
2811 {0x33, AC_VERB_SET_CONNECT_SEL, 0x0},
2812
2813 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
2814 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
2815 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
2816 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
2817 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
2818 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
2819 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
2820 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
2821
2822 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
2823 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1},
2824 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
2825
2826 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f},
2827 { }
2828};
2829
2830static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res)
2831{
2832 if ((res >> 26) != AD1988_HP_EVENT)
2833 return;
2834 if (snd_hda_jack_detect(codec, 0x11))
2835 snd_hda_sequence_write(codec, ad1988_laptop_hp_on);
2836 else
2837 snd_hda_sequence_write(codec, ad1988_laptop_hp_off);
2838}
2839
2840#ifdef CONFIG_SND_HDA_POWER_SAVE
2841static const struct hda_amp_list ad1988_loopbacks[] = {
2842 { 0x20, HDA_INPUT, 0 },
2843 { 0x20, HDA_INPUT, 1 },
2844 { 0x20, HDA_INPUT, 4 },
2845 { 0x20, HDA_INPUT, 6 },
2846 { }
2847};
2848#endif
2849
2850
2851
2852
2853
2854enum {
2855 AD_CTL_WIDGET_VOL,
2856 AD_CTL_WIDGET_MUTE,
2857 AD_CTL_BIND_MUTE,
2858};
2859static const struct snd_kcontrol_new ad1988_control_templates[] = {
2860 HDA_CODEC_VOLUME(NULL, 0, 0, 0),
2861 HDA_CODEC_MUTE(NULL, 0, 0, 0),
2862 HDA_BIND_MUTE(NULL, 0, 0, 0),
2863};
2864
2865
2866static int add_control(struct ad198x_spec *spec, int type, const char *name,
2867 unsigned long val)
2868{
2869 struct snd_kcontrol_new *knew;
2870
2871 snd_array_init(&spec->kctls, sizeof(*knew), 32);
2872 knew = snd_array_new(&spec->kctls);
2873 if (!knew)
2874 return -ENOMEM;
2875 *knew = ad1988_control_templates[type];
2876 knew->name = kstrdup(name, GFP_KERNEL);
2877 if (! knew->name)
2878 return -ENOMEM;
2879 if (get_amp_nid_(val))
2880 knew->subdevice = HDA_SUBDEV_AMP_FLAG;
2881 knew->private_value = val;
2882 return 0;
2883}
2884
2885#define AD1988_PIN_CD_NID 0x18
2886#define AD1988_PIN_BEEP_NID 0x10
2887
2888static const hda_nid_t ad1988_mixer_nids[8] = {
2889
2890 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28
2891};
2892
2893static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx)
2894{
2895 static const hda_nid_t idx_to_dac[8] = {
2896
2897 0x03, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a
2898 };
2899 static const hda_nid_t idx_to_dac_rev2[8] = {
2900
2901 0x03, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06
2902 };
2903 if (is_rev2(codec))
2904 return idx_to_dac_rev2[idx];
2905 else
2906 return idx_to_dac[idx];
2907}
2908
2909static const hda_nid_t ad1988_boost_nids[8] = {
2910 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0
2911};
2912
2913static int ad1988_pin_idx(hda_nid_t nid)
2914{
2915 static const hda_nid_t ad1988_io_pins[8] = {
2916 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25
2917 };
2918 int i;
2919 for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++)
2920 if (ad1988_io_pins[i] == nid)
2921 return i;
2922 return 0;
2923}
2924
2925static int ad1988_pin_to_loopback_idx(hda_nid_t nid)
2926{
2927 static const int loopback_idx[8] = {
2928 2, 0, 1, 3, 4, 5, 1, 4
2929 };
2930 switch (nid) {
2931 case AD1988_PIN_CD_NID:
2932 return 6;
2933 default:
2934 return loopback_idx[ad1988_pin_idx(nid)];
2935 }
2936}
2937
2938static int ad1988_pin_to_adc_idx(hda_nid_t nid)
2939{
2940 static const int adc_idx[8] = {
2941 0, 1, 2, 8, 4, 3, 6, 7
2942 };
2943 switch (nid) {
2944 case AD1988_PIN_CD_NID:
2945 return 5;
2946 default:
2947 return adc_idx[ad1988_pin_idx(nid)];
2948 }
2949}
2950
2951
2952static int ad1988_auto_fill_dac_nids(struct hda_codec *codec,
2953 const struct auto_pin_cfg *cfg)
2954{
2955 struct ad198x_spec *spec = codec->spec;
2956 int i, idx;
2957
2958 spec->multiout.dac_nids = spec->private_dac_nids;
2959
2960
2961 for (i = 0; i < cfg->line_outs; i++) {
2962 idx = ad1988_pin_idx(cfg->line_out_pins[i]);
2963 spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx);
2964 }
2965 spec->multiout.num_dacs = cfg->line_outs;
2966 return 0;
2967}
2968
2969
2970static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec,
2971 const struct auto_pin_cfg *cfg)
2972{
2973 char name[32];
2974 static const char * const chname[4] = {
2975 "Front", "Surround", NULL , "Side"
2976 };
2977 hda_nid_t nid;
2978 int i, err;
2979
2980 for (i = 0; i < cfg->line_outs; i++) {
2981 hda_nid_t dac = spec->multiout.dac_nids[i];
2982 if (! dac)
2983 continue;
2984 nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])];
2985 if (i == 2) {
2986
2987 err = add_control(spec, AD_CTL_WIDGET_VOL,
2988 "Center Playback Volume",
2989 HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT));
2990 if (err < 0)
2991 return err;
2992 err = add_control(spec, AD_CTL_WIDGET_VOL,
2993 "LFE Playback Volume",
2994 HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT));
2995 if (err < 0)
2996 return err;
2997 err = add_control(spec, AD_CTL_BIND_MUTE,
2998 "Center Playback Switch",
2999 HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT));
3000 if (err < 0)
3001 return err;
3002 err = add_control(spec, AD_CTL_BIND_MUTE,
3003 "LFE Playback Switch",
3004 HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT));
3005 if (err < 0)
3006 return err;
3007 } else {
3008 sprintf(name, "%s Playback Volume", chname[i]);
3009 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
3010 HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT));
3011 if (err < 0)
3012 return err;
3013 sprintf(name, "%s Playback Switch", chname[i]);
3014 err = add_control(spec, AD_CTL_BIND_MUTE, name,
3015 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT));
3016 if (err < 0)
3017 return err;
3018 }
3019 }
3020 return 0;
3021}
3022
3023
3024static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin,
3025 const char *pfx)
3026{
3027 struct ad198x_spec *spec = codec->spec;
3028 hda_nid_t nid;
3029 int i, idx, err;
3030 char name[32];
3031
3032 if (! pin)
3033 return 0;
3034
3035 idx = ad1988_pin_idx(pin);
3036 nid = ad1988_idx_to_dac(codec, idx);
3037
3038 for (i = 0; i < spec->autocfg.line_outs; i++) {
3039 hda_nid_t pin = spec->autocfg.line_out_pins[i];
3040 hda_nid_t dac = ad1988_idx_to_dac(codec, ad1988_pin_idx(pin));
3041 if (dac == nid)
3042 break;
3043 }
3044 if (i >= spec->autocfg.line_outs) {
3045
3046 if (!spec->multiout.hp_nid)
3047 spec->multiout.hp_nid = nid;
3048 else
3049 spec->multiout.extra_out_nid[0] = nid;
3050
3051 sprintf(name, "%s Playback Volume", pfx);
3052 err = add_control(spec, AD_CTL_WIDGET_VOL, name,
3053 HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT));
3054 if (err < 0)
3055 return err;
3056 }
3057 nid = ad1988_mixer_nids[idx];
3058 sprintf(name, "%s Playback Switch", pfx);
3059 if ((err = add_control(spec, AD_CTL_BIND_MUTE, name,
3060 HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0)
3061 return err;
3062 return 0;
3063}
3064
3065
3066static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin,
3067 const char *ctlname, int ctlidx, int boost)
3068{
3069 char name[32];
3070 int err, idx;
3071
3072 sprintf(name, "%s Playback Volume", ctlname);
3073 idx = ad1988_pin_to_loopback_idx(pin);
3074 if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name,
3075 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
3076 return err;
3077 sprintf(name, "%s Playback Switch", ctlname);
3078 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name,
3079 HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0)
3080 return err;
3081 if (boost) {
3082 hda_nid_t bnid;
3083 idx = ad1988_pin_idx(pin);
3084 bnid = ad1988_boost_nids[idx];
3085 if (bnid) {
3086 sprintf(name, "%s Boost Volume", ctlname);
3087 return add_control(spec, AD_CTL_WIDGET_VOL, name,
3088 HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT));
3089
3090 }
3091 }
3092 return 0;
3093}
3094
3095
3096static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec,
3097 const struct auto_pin_cfg *cfg)
3098{
3099 struct ad198x_spec *spec = codec->spec;
3100 struct hda_input_mux *imux = &spec->private_imux;
3101 int i, err, type, type_idx;
3102
3103 for (i = 0; i < cfg->num_inputs; i++) {
3104 const char *label;
3105 type = cfg->inputs[i].type;
3106 label = hda_get_autocfg_input_label(codec, cfg, i);
3107 snd_hda_add_imux_item(imux, label,
3108 ad1988_pin_to_adc_idx(cfg->inputs[i].pin),
3109 &type_idx);
3110 err = new_analog_input(spec, cfg->inputs[i].pin,
3111 label, type_idx,
3112 type == AUTO_PIN_MIC);
3113 if (err < 0)
3114 return err;
3115 }
3116 snd_hda_add_imux_item(imux, "Mix", 9, NULL);
3117
3118 if ((err = add_control(spec, AD_CTL_WIDGET_VOL,
3119 "Analog Mix Playback Volume",
3120 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
3121 return err;
3122 if ((err = add_control(spec, AD_CTL_WIDGET_MUTE,
3123 "Analog Mix Playback Switch",
3124 HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0)
3125 return err;
3126
3127 return 0;
3128}
3129
3130static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec,
3131 hda_nid_t nid, int pin_type,
3132 int dac_idx)
3133{
3134
3135 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type);
3136 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
3137 switch (nid) {
3138 case 0x11:
3139 snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
3140 break;
3141 case 0x14:
3142 snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02);
3143 break;
3144 case 0x15:
3145 snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00);
3146 break;
3147 case 0x17:
3148 snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
3149 break;
3150 case 0x13:
3151 snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01);
3152 break;
3153 }
3154}
3155
3156static void ad1988_auto_init_multi_out(struct hda_codec *codec)
3157{
3158 struct ad198x_spec *spec = codec->spec;
3159 int i;
3160
3161 for (i = 0; i < spec->autocfg.line_outs; i++) {
3162 hda_nid_t nid = spec->autocfg.line_out_pins[i];
3163 ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i);
3164 }
3165}
3166
3167static void ad1988_auto_init_extra_out(struct hda_codec *codec)
3168{
3169 struct ad198x_spec *spec = codec->spec;
3170 hda_nid_t pin;
3171
3172 pin = spec->autocfg.speaker_pins[0];
3173 if (pin)
3174 ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0);
3175 pin = spec->autocfg.hp_pins[0];
3176 if (pin)
3177 ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0);
3178}
3179
3180static void ad1988_auto_init_analog_input(struct hda_codec *codec)
3181{
3182 struct ad198x_spec *spec = codec->spec;
3183 const struct auto_pin_cfg *cfg = &spec->autocfg;
3184 int i, idx;
3185
3186 for (i = 0; i < cfg->num_inputs; i++) {
3187 hda_nid_t nid = cfg->inputs[i].pin;
3188 int type = cfg->inputs[i].type;
3189 switch (nid) {
3190 case 0x15:
3191 snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3192 break;
3193 case 0x17:
3194 snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0);
3195 break;
3196 }
3197 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
3198 type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN);
3199 if (nid != AD1988_PIN_CD_NID)
3200 snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
3201 AMP_OUT_MUTE);
3202 idx = ad1988_pin_idx(nid);
3203 if (ad1988_boost_nids[idx])
3204 snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0,
3205 AC_VERB_SET_AMP_GAIN_MUTE,
3206 AMP_OUT_ZERO);
3207 }
3208}
3209
3210
3211
3212static int ad1988_parse_auto_config(struct hda_codec *codec)
3213{
3214 struct ad198x_spec *spec = codec->spec;
3215 int err;
3216
3217 if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0)
3218 return err;
3219 if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0)
3220 return err;
3221 if (! spec->autocfg.line_outs)
3222 return 0;
3223 if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 ||
3224 (err = ad1988_auto_create_extra_out(codec,
3225 spec->autocfg.speaker_pins[0],
3226 "Speaker")) < 0 ||
3227 (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0],
3228 "Headphone")) < 0 ||
3229 (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0)
3230 return err;
3231
3232 spec->multiout.max_channels = spec->multiout.num_dacs * 2;
3233
3234 if (spec->autocfg.dig_outs)
3235 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3236 if (spec->autocfg.dig_in_pin)
3237 spec->dig_in_nid = AD1988_SPDIF_IN;
3238
3239 if (spec->kctls.list)
3240 spec->mixers[spec->num_mixers++] = spec->kctls.list;
3241
3242 spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs;
3243
3244 spec->input_mux = &spec->private_imux;
3245
3246 return 1;
3247}
3248
3249
3250static int ad1988_auto_init(struct hda_codec *codec)
3251{
3252 ad198x_init(codec);
3253 ad1988_auto_init_multi_out(codec);
3254 ad1988_auto_init_extra_out(codec);
3255 ad1988_auto_init_analog_input(codec);
3256 return 0;
3257}
3258
3259
3260
3261
3262static const char * const ad1988_models[AD1988_MODEL_LAST] = {
3263 [AD1988_6STACK] = "6stack",
3264 [AD1988_6STACK_DIG] = "6stack-dig",
3265 [AD1988_3STACK] = "3stack",
3266 [AD1988_3STACK_DIG] = "3stack-dig",
3267 [AD1988_LAPTOP] = "laptop",
3268 [AD1988_LAPTOP_DIG] = "laptop-dig",
3269 [AD1988_AUTO] = "auto",
3270};
3271
3272static const struct snd_pci_quirk ad1988_cfg_tbl[] = {
3273 SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG),
3274 SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG),
3275 SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG),
3276 SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG),
3277 SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG),
3278 {}
3279};
3280
3281static int patch_ad1988(struct hda_codec *codec)
3282{
3283 struct ad198x_spec *spec;
3284 int err, board_config;
3285
3286 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3287 if (spec == NULL)
3288 return -ENOMEM;
3289
3290 codec->spec = spec;
3291
3292 if (is_rev2(codec))
3293 snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n");
3294
3295 board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST,
3296 ad1988_models, ad1988_cfg_tbl);
3297 if (board_config < 0) {
3298 printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n",
3299 codec->chip_name);
3300 board_config = AD1988_AUTO;
3301 }
3302
3303 if (board_config == AD1988_AUTO) {
3304
3305 err = ad1988_parse_auto_config(codec);
3306 if (err < 0) {
3307 ad198x_free(codec);
3308 return err;
3309 } else if (! err) {
3310 printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n");
3311 board_config = AD1988_6STACK;
3312 }
3313 }
3314
3315 err = snd_hda_attach_beep_device(codec, 0x10);
3316 if (err < 0) {
3317 ad198x_free(codec);
3318 return err;
3319 }
3320 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3321
3322 if (!spec->multiout.hp_nid)
3323 spec->multiout.hp_nid = ad1988_alt_dac_nid[0];
3324 switch (board_config) {
3325 case AD1988_6STACK:
3326 case AD1988_6STACK_DIG:
3327 spec->multiout.max_channels = 8;
3328 spec->multiout.num_dacs = 4;
3329 if (is_rev2(codec))
3330 spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2;
3331 else
3332 spec->multiout.dac_nids = ad1988_6stack_dac_nids;
3333 spec->input_mux = &ad1988_6stack_capture_source;
3334 spec->num_mixers = 2;
3335 if (is_rev2(codec))
3336 spec->mixers[0] = ad1988_6stack_mixers1_rev2;
3337 else
3338 spec->mixers[0] = ad1988_6stack_mixers1;
3339 spec->mixers[1] = ad1988_6stack_mixers2;
3340 spec->num_init_verbs = 1;
3341 spec->init_verbs[0] = ad1988_6stack_init_verbs;
3342 if (board_config == AD1988_6STACK_DIG) {
3343 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3344 spec->dig_in_nid = AD1988_SPDIF_IN;
3345 }
3346 break;
3347 case AD1988_3STACK:
3348 case AD1988_3STACK_DIG:
3349 spec->multiout.max_channels = 6;
3350 spec->multiout.num_dacs = 3;
3351 if (is_rev2(codec))
3352 spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2;
3353 else
3354 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3355 spec->input_mux = &ad1988_6stack_capture_source;
3356 spec->channel_mode = ad1988_3stack_modes;
3357 spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes);
3358 spec->num_mixers = 2;
3359 if (is_rev2(codec))
3360 spec->mixers[0] = ad1988_3stack_mixers1_rev2;
3361 else
3362 spec->mixers[0] = ad1988_3stack_mixers1;
3363 spec->mixers[1] = ad1988_3stack_mixers2;
3364 spec->num_init_verbs = 1;
3365 spec->init_verbs[0] = ad1988_3stack_init_verbs;
3366 if (board_config == AD1988_3STACK_DIG)
3367 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3368 break;
3369 case AD1988_LAPTOP:
3370 case AD1988_LAPTOP_DIG:
3371 spec->multiout.max_channels = 2;
3372 spec->multiout.num_dacs = 1;
3373 spec->multiout.dac_nids = ad1988_3stack_dac_nids;
3374 spec->input_mux = &ad1988_laptop_capture_source;
3375 spec->num_mixers = 1;
3376 spec->mixers[0] = ad1988_laptop_mixers;
3377 spec->inv_eapd = 1;
3378 spec->num_init_verbs = 1;
3379 spec->init_verbs[0] = ad1988_laptop_init_verbs;
3380 if (board_config == AD1988_LAPTOP_DIG)
3381 spec->multiout.dig_out_nid = AD1988_SPDIF_OUT;
3382 break;
3383 }
3384
3385 if (spec->autocfg.hp_pins[0]) {
3386 spec->mixers[spec->num_mixers++] = ad1988_hp_mixers;
3387 spec->slave_vols = ad1988_6stack_fp_slave_vols;
3388 spec->slave_sws = ad1988_6stack_fp_slave_sws;
3389 spec->alt_dac_nid = ad1988_alt_dac_nid;
3390 spec->stream_analog_alt_playback =
3391 &ad198x_pcm_analog_alt_playback;
3392 }
3393
3394 spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids);
3395 spec->adc_nids = ad1988_adc_nids;
3396 spec->capsrc_nids = ad1988_capsrc_nids;
3397 spec->mixers[spec->num_mixers++] = ad1988_capture_mixers;
3398 spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs;
3399 if (spec->multiout.dig_out_nid) {
3400 if (codec->vendor_id >= 0x11d4989a) {
3401 spec->mixers[spec->num_mixers++] =
3402 ad1989_spdif_out_mixers;
3403 spec->init_verbs[spec->num_init_verbs++] =
3404 ad1989_spdif_init_verbs;
3405 codec->slave_dig_outs = ad1989b_slave_dig_outs;
3406 } else {
3407 spec->mixers[spec->num_mixers++] =
3408 ad1988_spdif_out_mixers;
3409 spec->init_verbs[spec->num_init_verbs++] =
3410 ad1988_spdif_init_verbs;
3411 }
3412 }
3413 if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) {
3414 spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers;
3415 spec->init_verbs[spec->num_init_verbs++] =
3416 ad1988_spdif_in_init_verbs;
3417 }
3418
3419 codec->patch_ops = ad198x_patch_ops;
3420 switch (board_config) {
3421 case AD1988_AUTO:
3422 codec->patch_ops.init = ad1988_auto_init;
3423 break;
3424 case AD1988_LAPTOP:
3425 case AD1988_LAPTOP_DIG:
3426 codec->patch_ops.unsol_event = ad1988_laptop_unsol_event;
3427 break;
3428 }
3429#ifdef CONFIG_SND_HDA_POWER_SAVE
3430 spec->loopback.amplist = ad1988_loopbacks;
3431#endif
3432 spec->vmaster_nid = 0x04;
3433
3434 codec->no_trigger_sense = 1;
3435 codec->no_sticky_stream = 1;
3436
3437 return 0;
3438}
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459static const hda_nid_t ad1884_dac_nids[1] = {
3460 0x04,
3461};
3462
3463static const hda_nid_t ad1884_adc_nids[2] = {
3464 0x08, 0x09,
3465};
3466
3467static const hda_nid_t ad1884_capsrc_nids[2] = {
3468 0x0c, 0x0d,
3469};
3470
3471#define AD1884_SPDIF_OUT 0x02
3472
3473static const struct hda_input_mux ad1884_capture_source = {
3474 .num_items = 4,
3475 .items = {
3476 { "Front Mic", 0x0 },
3477 { "Mic", 0x1 },
3478 { "CD", 0x2 },
3479 { "Mix", 0x3 },
3480 },
3481};
3482
3483static const struct snd_kcontrol_new ad1884_base_mixers[] = {
3484 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3485
3486 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3487 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3488 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3489 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3490 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3491 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3492 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3493 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3494 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3495 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3496 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3497 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3498 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3499 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3500 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3501 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3502 {
3503 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3504
3505
3506
3507
3508 .name = "Input Source",
3509 .count = 2,
3510 .info = ad198x_mux_enum_info,
3511 .get = ad198x_mux_enum_get,
3512 .put = ad198x_mux_enum_put,
3513 },
3514
3515 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3516 {
3517 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3518 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3519
3520 .info = ad1983_spdif_route_info,
3521 .get = ad1983_spdif_route_get,
3522 .put = ad1983_spdif_route_put,
3523 },
3524 { }
3525};
3526
3527static const struct snd_kcontrol_new ad1984_dmic_mixers[] = {
3528 HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT),
3529 HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT),
3530 HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0,
3531 HDA_INPUT),
3532 HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0,
3533 HDA_INPUT),
3534 { }
3535};
3536
3537
3538
3539
3540static const struct hda_verb ad1884_init_verbs[] = {
3541
3542 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3543 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3544
3545 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3546 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3547
3548 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3549 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3550
3551 {0x22, AC_VERB_SET_CONNECT_SEL, 0x1},
3552
3553 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3554 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3555
3556 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3557 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3558
3559 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3560 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3561
3562 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3563 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3564
3565 {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1},
3566
3567 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3568 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3569
3570 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3571 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
3572
3573 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3574 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
3575 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
3576 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
3577
3578 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f},
3579
3580 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
3581 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27},
3582 { }
3583};
3584
3585#ifdef CONFIG_SND_HDA_POWER_SAVE
3586static const struct hda_amp_list ad1884_loopbacks[] = {
3587 { 0x20, HDA_INPUT, 0 },
3588 { 0x20, HDA_INPUT, 1 },
3589 { 0x20, HDA_INPUT, 2 },
3590 { 0x20, HDA_INPUT, 4 },
3591 { }
3592};
3593#endif
3594
3595static const char * const ad1884_slave_vols[] = {
3596 "PCM Playback Volume",
3597 "Mic Playback Volume",
3598 "Mono Playback Volume",
3599 "Front Mic Playback Volume",
3600 "Mic Playback Volume",
3601 "CD Playback Volume",
3602 "Internal Mic Playback Volume",
3603 "Docking Mic Playback Volume",
3604
3605 "IEC958 Playback Volume",
3606 NULL
3607};
3608
3609static int patch_ad1884(struct hda_codec *codec)
3610{
3611 struct ad198x_spec *spec;
3612 int err;
3613
3614 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
3615 if (spec == NULL)
3616 return -ENOMEM;
3617
3618 codec->spec = spec;
3619
3620 err = snd_hda_attach_beep_device(codec, 0x10);
3621 if (err < 0) {
3622 ad198x_free(codec);
3623 return err;
3624 }
3625 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
3626
3627 spec->multiout.max_channels = 2;
3628 spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids);
3629 spec->multiout.dac_nids = ad1884_dac_nids;
3630 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3631 spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids);
3632 spec->adc_nids = ad1884_adc_nids;
3633 spec->capsrc_nids = ad1884_capsrc_nids;
3634 spec->input_mux = &ad1884_capture_source;
3635 spec->num_mixers = 1;
3636 spec->mixers[0] = ad1884_base_mixers;
3637 spec->num_init_verbs = 1;
3638 spec->init_verbs[0] = ad1884_init_verbs;
3639 spec->spdif_route = 0;
3640#ifdef CONFIG_SND_HDA_POWER_SAVE
3641 spec->loopback.amplist = ad1884_loopbacks;
3642#endif
3643 spec->vmaster_nid = 0x04;
3644
3645 spec->slave_vols = ad1884_slave_vols;
3646
3647 codec->patch_ops = ad198x_patch_ops;
3648
3649 codec->no_trigger_sense = 1;
3650 codec->no_sticky_stream = 1;
3651
3652 return 0;
3653}
3654
3655
3656
3657
3658static const struct hda_input_mux ad1984_thinkpad_capture_source = {
3659 .num_items = 4,
3660 .items = {
3661 { "Mic", 0x0 },
3662 { "Internal Mic", 0x1 },
3663 { "Mix", 0x3 },
3664 { "Docking-Station", 0x4 },
3665 },
3666};
3667
3668
3669
3670
3671
3672static const struct hda_input_mux ad1984_dell_desktop_capture_source = {
3673 .num_items = 3,
3674 .items = {
3675 { "Front Mic", 0x0 },
3676 { "Line-In", 0x1 },
3677 { "Mix", 0x3 },
3678 },
3679};
3680
3681
3682static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = {
3683 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3684
3685 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3686 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3687 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3688 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3689 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
3690 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
3691 HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT),
3692 HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT),
3693 HDA_CODEC_VOLUME("Docking Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3694 HDA_CODEC_MUTE("Docking Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3695 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3696 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
3697 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3698 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3699 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3700 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3701 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3702 {
3703 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3704
3705
3706
3707
3708 .name = "Input Source",
3709 .count = 2,
3710 .info = ad198x_mux_enum_info,
3711 .get = ad198x_mux_enum_get,
3712 .put = ad198x_mux_enum_put,
3713 },
3714
3715 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3716 {
3717 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3718 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3719
3720 .info = ad1983_spdif_route_info,
3721 .get = ad1983_spdif_route_get,
3722 .put = ad1983_spdif_route_put,
3723 },
3724 { }
3725};
3726
3727
3728static const struct hda_verb ad1984_thinkpad_init_verbs[] = {
3729
3730 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
3731 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3732
3733 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
3734
3735 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a},
3736
3737 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
3738
3739 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
3740 { }
3741};
3742
3743
3744
3745
3746static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = {
3747 HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT),
3748 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3749 HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3750 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3751 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3752 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3753 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3754 HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT),
3755 HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT),
3756 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT),
3757 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3758 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3759 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3760 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3761 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3762 {
3763 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3764
3765
3766
3767
3768 .name = "Input Source",
3769 .count = 2,
3770 .info = ad198x_mux_enum_info,
3771 .get = ad198x_mux_enum_get,
3772 .put = ad198x_mux_enum_put,
3773 },
3774 { }
3775};
3776
3777
3778static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo,
3779 struct hda_codec *codec,
3780 unsigned int stream_tag,
3781 unsigned int format,
3782 struct snd_pcm_substream *substream)
3783{
3784 snd_hda_codec_setup_stream(codec, 0x05 + substream->number,
3785 stream_tag, 0, format);
3786 return 0;
3787}
3788
3789static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo,
3790 struct hda_codec *codec,
3791 struct snd_pcm_substream *substream)
3792{
3793 snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number);
3794 return 0;
3795}
3796
3797static const struct hda_pcm_stream ad1984_pcm_dmic_capture = {
3798 .substreams = 2,
3799 .channels_min = 2,
3800 .channels_max = 2,
3801 .nid = 0x05,
3802 .ops = {
3803 .prepare = ad1984_pcm_dmic_prepare,
3804 .cleanup = ad1984_pcm_dmic_cleanup
3805 },
3806};
3807
3808static int ad1984_build_pcms(struct hda_codec *codec)
3809{
3810 struct ad198x_spec *spec = codec->spec;
3811 struct hda_pcm *info;
3812 int err;
3813
3814 err = ad198x_build_pcms(codec);
3815 if (err < 0)
3816 return err;
3817
3818 info = spec->pcm_rec + codec->num_pcms;
3819 codec->num_pcms++;
3820 info->name = "AD1984 Digital Mic";
3821 info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture;
3822 return 0;
3823}
3824
3825
3826enum {
3827 AD1984_BASIC,
3828 AD1984_THINKPAD,
3829 AD1984_DELL_DESKTOP,
3830 AD1984_MODELS
3831};
3832
3833static const char * const ad1984_models[AD1984_MODELS] = {
3834 [AD1984_BASIC] = "basic",
3835 [AD1984_THINKPAD] = "thinkpad",
3836 [AD1984_DELL_DESKTOP] = "dell_desktop",
3837};
3838
3839static const struct snd_pci_quirk ad1984_cfg_tbl[] = {
3840
3841 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD),
3842 SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP),
3843 SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP),
3844 {}
3845};
3846
3847static int patch_ad1984(struct hda_codec *codec)
3848{
3849 struct ad198x_spec *spec;
3850 int board_config, err;
3851
3852 err = patch_ad1884(codec);
3853 if (err < 0)
3854 return err;
3855 spec = codec->spec;
3856 board_config = snd_hda_check_board_config(codec, AD1984_MODELS,
3857 ad1984_models, ad1984_cfg_tbl);
3858 switch (board_config) {
3859 case AD1984_BASIC:
3860
3861 spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers;
3862 codec->patch_ops.build_pcms = ad1984_build_pcms;
3863 break;
3864 case AD1984_THINKPAD:
3865 if (codec->subsystem_id == 0x17aa20fb) {
3866
3867
3868 spec->multiout.dig_out_nid = 0;
3869 } else
3870 spec->multiout.dig_out_nid = AD1884_SPDIF_OUT;
3871 spec->input_mux = &ad1984_thinkpad_capture_source;
3872 spec->mixers[0] = ad1984_thinkpad_mixers;
3873 spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs;
3874 spec->analog_beep = 1;
3875 break;
3876 case AD1984_DELL_DESKTOP:
3877 spec->multiout.dig_out_nid = 0;
3878 spec->input_mux = &ad1984_dell_desktop_capture_source;
3879 spec->mixers[0] = ad1984_dell_desktop_mixers;
3880 break;
3881 }
3882 return 0;
3883}
3884
3885
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897
3898
3899
3900
3901
3902
3903
3904static const hda_nid_t ad1884a_dac_nids[1] = {
3905 0x03,
3906};
3907
3908#define ad1884a_adc_nids ad1884_adc_nids
3909#define ad1884a_capsrc_nids ad1884_capsrc_nids
3910
3911#define AD1884A_SPDIF_OUT 0x02
3912
3913static const struct hda_input_mux ad1884a_capture_source = {
3914 .num_items = 5,
3915 .items = {
3916 { "Front Mic", 0x0 },
3917 { "Mic", 0x4 },
3918 { "Line", 0x1 },
3919 { "CD", 0x2 },
3920 { "Mix", 0x3 },
3921 },
3922};
3923
3924static const struct snd_kcontrol_new ad1884a_base_mixers[] = {
3925 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
3926 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
3927 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
3928 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
3929 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
3930 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
3931 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
3932 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
3933 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
3934 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
3935 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
3936 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
3937 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
3938 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
3939 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT),
3940 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT),
3941 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
3942 HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT),
3943 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
3944 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
3945 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
3946 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
3947 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
3948 {
3949 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3950
3951
3952
3953
3954 .name = "Input Source",
3955 .count = 2,
3956 .info = ad198x_mux_enum_info,
3957 .get = ad198x_mux_enum_get,
3958 .put = ad198x_mux_enum_put,
3959 },
3960
3961 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
3962 {
3963 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
3964 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
3965
3966 .info = ad1983_spdif_route_info,
3967 .get = ad1983_spdif_route_get,
3968 .put = ad1983_spdif_route_put,
3969 },
3970 { }
3971};
3972
3973
3974
3975
3976static const struct hda_verb ad1884a_init_verbs[] = {
3977
3978 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27},
3979 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27},
3980
3981 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3982 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3983
3984 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3985 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3986
3987 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3988 {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3989
3990 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3991 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3992
3993 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
3994 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
3995
3996 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
3997 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
3998
3999 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4000 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4001
4002 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4003 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4004
4005 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4006 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4007 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4008
4009 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4010 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4011
4012 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4013 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4014 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4015 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4016 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)},
4017 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4018
4019 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4020
4021 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0},
4022 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4023 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4024 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4025
4026 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27},
4027 { }
4028};
4029
4030#ifdef CONFIG_SND_HDA_POWER_SAVE
4031static const struct hda_amp_list ad1884a_loopbacks[] = {
4032 { 0x20, HDA_INPUT, 0 },
4033 { 0x20, HDA_INPUT, 1 },
4034 { 0x20, HDA_INPUT, 2 },
4035 { 0x20, HDA_INPUT, 4 },
4036 { }
4037};
4038#endif
4039
4040
4041
4042
4043
4044
4045
4046
4047
4048
4049
4050
4051static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol,
4052 struct snd_ctl_elem_value *ucontrol)
4053{
4054 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
4055 int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
4056 int mute = (!ucontrol->value.integer.value[0] &&
4057 !ucontrol->value.integer.value[1]);
4058
4059 snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
4060 mute ? 0x02 : 0x0);
4061 return ret;
4062}
4063
4064static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = {
4065 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4066 {
4067 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4068 .name = "Master Playback Switch",
4069 .subdevice = HDA_SUBDEV_AMP_FLAG,
4070 .info = snd_hda_mixer_amp_switch_info,
4071 .get = snd_hda_mixer_amp_switch_get,
4072 .put = ad1884a_mobile_master_sw_put,
4073 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4074 },
4075 HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4076 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4077 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4078 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4079 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4080 HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4081 HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4082 HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4083 HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4084 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4085 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
4086 HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
4087 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4088 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4089 { }
4090};
4091
4092static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = {
4093 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4094
4095 {
4096 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4097 .name = "Master Playback Switch",
4098 .subdevice = HDA_SUBDEV_AMP_FLAG,
4099 .info = snd_hda_mixer_amp_switch_info,
4100 .get = snd_hda_mixer_amp_switch_get,
4101 .put = ad1884a_mobile_master_sw_put,
4102 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4103 },
4104 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4105 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4106 HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT),
4107 HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT),
4108 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4109 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4110 { }
4111};
4112
4113
4114static void ad1884a_hp_automute(struct hda_codec *codec)
4115{
4116 unsigned int present;
4117
4118 present = snd_hda_jack_detect(codec, 0x11);
4119 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4120 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4121 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4122 present ? 0x00 : 0x02);
4123}
4124
4125
4126static void ad1884a_hp_automic(struct hda_codec *codec)
4127{
4128 unsigned int present;
4129
4130 present = snd_hda_jack_detect(codec, 0x14);
4131 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL,
4132 present ? 0 : 1);
4133}
4134
4135#define AD1884A_HP_EVENT 0x37
4136#define AD1884A_MIC_EVENT 0x36
4137
4138
4139static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res)
4140{
4141 switch (res >> 26) {
4142 case AD1884A_HP_EVENT:
4143 ad1884a_hp_automute(codec);
4144 break;
4145 case AD1884A_MIC_EVENT:
4146 ad1884a_hp_automic(codec);
4147 break;
4148 }
4149}
4150
4151
4152static int ad1884a_hp_init(struct hda_codec *codec)
4153{
4154 ad198x_init(codec);
4155 ad1884a_hp_automute(codec);
4156 ad1884a_hp_automic(codec);
4157 return 0;
4158}
4159
4160
4161static void ad1884a_laptop_automute(struct hda_codec *codec)
4162{
4163 unsigned int present;
4164
4165 present = snd_hda_jack_detect(codec, 0x11);
4166 if (!present)
4167 present = snd_hda_jack_detect(codec, 0x12);
4168 snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0,
4169 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4170 snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE,
4171 present ? 0x00 : 0x02);
4172}
4173
4174
4175static void ad1884a_laptop_automic(struct hda_codec *codec)
4176{
4177 unsigned int idx;
4178
4179 if (snd_hda_jack_detect(codec, 0x14))
4180 idx = 0;
4181 else if (snd_hda_jack_detect(codec, 0x1c))
4182 idx = 4;
4183 else
4184 idx = 1;
4185 snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx);
4186}
4187
4188
4189static void ad1884a_laptop_unsol_event(struct hda_codec *codec,
4190 unsigned int res)
4191{
4192 switch (res >> 26) {
4193 case AD1884A_HP_EVENT:
4194 ad1884a_laptop_automute(codec);
4195 break;
4196 case AD1884A_MIC_EVENT:
4197 ad1884a_laptop_automic(codec);
4198 break;
4199 }
4200}
4201
4202
4203static int ad1884a_laptop_init(struct hda_codec *codec)
4204{
4205 ad198x_init(codec);
4206 ad1884a_laptop_automute(codec);
4207 ad1884a_laptop_automic(codec);
4208 return 0;
4209}
4210
4211
4212static const struct hda_verb ad1884a_laptop_verbs[] = {
4213
4214 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4215
4216 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4217 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4218
4219 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4220 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4221
4222 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4223
4224 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4225 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002},
4226 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002},
4227
4228 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4229
4230 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4231
4232 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4233 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4234 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4235 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4236
4237 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4238 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4239 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
4240 { }
4241};
4242
4243static const struct hda_verb ad1884a_mobile_verbs[] = {
4244
4245 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27},
4246 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27},
4247
4248 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4249 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4250
4251 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4252
4253 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4254
4255 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4256 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002},
4257
4258 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4259 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002},
4260
4261 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4262 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4263
4264 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4265 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4266
4267 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4268 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4269 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4270 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4271 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4272 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4273
4274 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4275
4276
4277 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4278 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4279 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4280
4281 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4282 {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4283
4284 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4285 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4286 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
4287 { }
4288};
4289
4290
4291
4292
4293
4294
4295
4296
4297
4298static const struct hda_verb ad1984a_thinkpad_verbs[] = {
4299
4300 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4301
4302 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4303
4304 {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4305
4306 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4307
4308 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4309
4310 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4311 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4312 { }
4313};
4314
4315static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = {
4316 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4317 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4318 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4319 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4320 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4321 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4322 HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT),
4323 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
4324 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4325 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4326 {
4327 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4328 .name = "Capture Source",
4329 .info = ad198x_mux_enum_info,
4330 .get = ad198x_mux_enum_get,
4331 .put = ad198x_mux_enum_put,
4332 },
4333 { }
4334};
4335
4336static const struct hda_input_mux ad1984a_thinkpad_capture_source = {
4337 .num_items = 3,
4338 .items = {
4339 { "Mic", 0x0 },
4340 { "Internal Mic", 0x5 },
4341 { "Mix", 0x3 },
4342 },
4343};
4344
4345
4346static void ad1984a_thinkpad_automute(struct hda_codec *codec)
4347{
4348 unsigned int present;
4349
4350 present = snd_hda_jack_detect(codec, 0x11);
4351 snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0,
4352 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4353}
4354
4355
4356static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec,
4357 unsigned int res)
4358{
4359 if ((res >> 26) != AD1884A_HP_EVENT)
4360 return;
4361 ad1984a_thinkpad_automute(codec);
4362}
4363
4364
4365static int ad1984a_thinkpad_init(struct hda_codec *codec)
4366{
4367 ad198x_init(codec);
4368 ad1984a_thinkpad_automute(codec);
4369 return 0;
4370}
4371
4372
4373
4374
4375
4376
4377
4378
4379static const struct hda_verb ad1984a_precision_verbs[] = {
4380
4381 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27},
4382 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f},
4383 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17},
4384
4385 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4386 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4387 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4388 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4389 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4390
4391 {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1},
4392 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27},
4393
4394 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4395 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002},
4396
4397 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4398
4399 {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
4400
4401 {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4402 { }
4403};
4404
4405static const struct snd_kcontrol_new ad1984a_precision_mixers[] = {
4406 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4407 HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),
4408 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4409 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4410 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4411 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4412 HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT),
4413 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4414 HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT),
4415 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4416 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4417 { }
4418};
4419
4420
4421
4422static void ad1984a_precision_automute(struct hda_codec *codec)
4423{
4424 unsigned int present;
4425
4426 present = snd_hda_jack_detect(codec, 0x12);
4427 snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0,
4428 HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0);
4429}
4430
4431
4432
4433static void ad1984a_precision_unsol_event(struct hda_codec *codec,
4434 unsigned int res)
4435{
4436 if ((res >> 26) != AD1884A_HP_EVENT)
4437 return;
4438 ad1984a_precision_automute(codec);
4439}
4440
4441
4442static int ad1984a_precision_init(struct hda_codec *codec)
4443{
4444 ad198x_init(codec);
4445 ad1984a_precision_automute(codec);
4446 return 0;
4447}
4448
4449
4450
4451
4452
4453
4454
4455
4456
4457
4458
4459
4460
4461static const struct hda_verb ad1984a_touchsmart_verbs[] = {
4462
4463 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27},
4464 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27},
4465
4466 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4467 {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4468
4469 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4470
4471 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4472
4473 {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03},
4474
4475 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4476 {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE},
4477 {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4478
4479 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4480 {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4481
4482 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4483 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4484
4485 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4486 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4487 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4488 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4489 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4490 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4491
4492 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4493
4494
4495 {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4496 {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0},
4497 {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4498
4499 {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT},
4500 {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT},
4501
4502 {0x01, AC_VERB_SET_GPIO_MASK, 0x02},
4503 {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02},
4504 {0x01, AC_VERB_SET_GPIO_DATA, 0x02},
4505
4506 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4507
4508 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
4509 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
4510 { }
4511};
4512
4513static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = {
4514 HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT),
4515
4516 {
4517 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4518 .subdevice = HDA_SUBDEV_AMP_FLAG,
4519 .name = "Master Playback Switch",
4520 .info = snd_hda_mixer_amp_switch_info,
4521 .get = snd_hda_mixer_amp_switch_get,
4522 .put = ad1884a_mobile_master_sw_put,
4523 .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT),
4524 },
4525 HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT),
4526 HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT),
4527 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4528 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4529 HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT),
4530 HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT),
4531 { }
4532};
4533
4534
4535static void ad1984a_touchsmart_automic(struct hda_codec *codec)
4536{
4537 if (snd_hda_jack_detect(codec, 0x1c))
4538 snd_hda_codec_write(codec, 0x0c, 0,
4539 AC_VERB_SET_CONNECT_SEL, 0x4);
4540 else
4541 snd_hda_codec_write(codec, 0x0c, 0,
4542 AC_VERB_SET_CONNECT_SEL, 0x5);
4543}
4544
4545
4546
4547static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec,
4548 unsigned int res)
4549{
4550 switch (res >> 26) {
4551 case AD1884A_HP_EVENT:
4552 ad1884a_hp_automute(codec);
4553 break;
4554 case AD1884A_MIC_EVENT:
4555 ad1984a_touchsmart_automic(codec);
4556 break;
4557 }
4558}
4559
4560
4561static int ad1984a_touchsmart_init(struct hda_codec *codec)
4562{
4563 ad198x_init(codec);
4564 ad1884a_hp_automute(codec);
4565 ad1984a_touchsmart_automic(codec);
4566 return 0;
4567}
4568
4569
4570
4571
4572
4573enum {
4574 AD1884A_DESKTOP,
4575 AD1884A_LAPTOP,
4576 AD1884A_MOBILE,
4577 AD1884A_THINKPAD,
4578 AD1984A_TOUCHSMART,
4579 AD1984A_PRECISION,
4580 AD1884A_MODELS
4581};
4582
4583static const char * const ad1884a_models[AD1884A_MODELS] = {
4584 [AD1884A_DESKTOP] = "desktop",
4585 [AD1884A_LAPTOP] = "laptop",
4586 [AD1884A_MOBILE] = "mobile",
4587 [AD1884A_THINKPAD] = "thinkpad",
4588 [AD1984A_TOUCHSMART] = "touchsmart",
4589 [AD1984A_PRECISION] = "precision",
4590};
4591
4592static const struct snd_pci_quirk ad1884a_cfg_tbl[] = {
4593 SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION),
4594 SND_PCI_QUIRK(0x103c, 0x3030, "HP", AD1884A_MOBILE),
4595 SND_PCI_QUIRK(0x103c, 0x3037, "HP 2230s", AD1884A_LAPTOP),
4596 SND_PCI_QUIRK(0x103c, 0x3056, "HP", AD1884A_MOBILE),
4597 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE),
4598 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP),
4599 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP),
4600 SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP),
4601 SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE),
4602 SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD),
4603 SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART),
4604 {}
4605};
4606
4607static int patch_ad1884a(struct hda_codec *codec)
4608{
4609 struct ad198x_spec *spec;
4610 int err, board_config;
4611
4612 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4613 if (spec == NULL)
4614 return -ENOMEM;
4615
4616 codec->spec = spec;
4617
4618 err = snd_hda_attach_beep_device(codec, 0x10);
4619 if (err < 0) {
4620 ad198x_free(codec);
4621 return err;
4622 }
4623 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
4624
4625 spec->multiout.max_channels = 2;
4626 spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids);
4627 spec->multiout.dac_nids = ad1884a_dac_nids;
4628 spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT;
4629 spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids);
4630 spec->adc_nids = ad1884a_adc_nids;
4631 spec->capsrc_nids = ad1884a_capsrc_nids;
4632 spec->input_mux = &ad1884a_capture_source;
4633 spec->num_mixers = 1;
4634 spec->mixers[0] = ad1884a_base_mixers;
4635 spec->num_init_verbs = 1;
4636 spec->init_verbs[0] = ad1884a_init_verbs;
4637 spec->spdif_route = 0;
4638#ifdef CONFIG_SND_HDA_POWER_SAVE
4639 spec->loopback.amplist = ad1884a_loopbacks;
4640#endif
4641 codec->patch_ops = ad198x_patch_ops;
4642
4643
4644 board_config = snd_hda_check_board_config(codec, AD1884A_MODELS,
4645 ad1884a_models,
4646 ad1884a_cfg_tbl);
4647 switch (board_config) {
4648 case AD1884A_LAPTOP:
4649 spec->mixers[0] = ad1884a_laptop_mixers;
4650 spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs;
4651 spec->multiout.dig_out_nid = 0;
4652 codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event;
4653 codec->patch_ops.init = ad1884a_laptop_init;
4654
4655
4656
4657 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4658 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4659 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4660 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4661 (1 << AC_AMPCAP_MUTE_SHIFT));
4662 break;
4663 case AD1884A_MOBILE:
4664 spec->mixers[0] = ad1884a_mobile_mixers;
4665 spec->init_verbs[0] = ad1884a_mobile_verbs;
4666 spec->multiout.dig_out_nid = 0;
4667 codec->patch_ops.unsol_event = ad1884a_hp_unsol_event;
4668 codec->patch_ops.init = ad1884a_hp_init;
4669
4670
4671
4672 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4673 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4674 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4675 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4676 (1 << AC_AMPCAP_MUTE_SHIFT));
4677 break;
4678 case AD1884A_THINKPAD:
4679 spec->mixers[0] = ad1984a_thinkpad_mixers;
4680 spec->init_verbs[spec->num_init_verbs++] =
4681 ad1984a_thinkpad_verbs;
4682 spec->multiout.dig_out_nid = 0;
4683 spec->input_mux = &ad1984a_thinkpad_capture_source;
4684 codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event;
4685 codec->patch_ops.init = ad1984a_thinkpad_init;
4686 break;
4687 case AD1984A_PRECISION:
4688 spec->mixers[0] = ad1984a_precision_mixers;
4689 spec->init_verbs[spec->num_init_verbs++] =
4690 ad1984a_precision_verbs;
4691 spec->multiout.dig_out_nid = 0;
4692 codec->patch_ops.unsol_event = ad1984a_precision_unsol_event;
4693 codec->patch_ops.init = ad1984a_precision_init;
4694 break;
4695 case AD1984A_TOUCHSMART:
4696 spec->mixers[0] = ad1984a_touchsmart_mixers;
4697 spec->init_verbs[0] = ad1984a_touchsmart_verbs;
4698 spec->multiout.dig_out_nid = 0;
4699 codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event;
4700 codec->patch_ops.init = ad1984a_touchsmart_init;
4701
4702
4703
4704 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
4705 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
4706 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
4707 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
4708 (1 << AC_AMPCAP_MUTE_SHIFT));
4709 break;
4710 }
4711
4712 codec->no_trigger_sense = 1;
4713 codec->no_sticky_stream = 1;
4714
4715 return 0;
4716}
4717
4718
4719
4720
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731static const hda_nid_t ad1882_dac_nids[3] = {
4732 0x04, 0x03, 0x05
4733};
4734
4735static const hda_nid_t ad1882_adc_nids[2] = {
4736 0x08, 0x09,
4737};
4738
4739static const hda_nid_t ad1882_capsrc_nids[2] = {
4740 0x0c, 0x0d,
4741};
4742
4743#define AD1882_SPDIF_OUT 0x02
4744
4745
4746static const struct hda_input_mux ad1882_capture_source = {
4747 .num_items = 5,
4748 .items = {
4749 { "Front Mic", 0x1 },
4750 { "Mic", 0x4 },
4751 { "Line", 0x2 },
4752 { "CD", 0x3 },
4753 { "Mix", 0x7 },
4754 },
4755};
4756
4757
4758static const struct hda_input_mux ad1882a_capture_source = {
4759 .num_items = 5,
4760 .items = {
4761 { "Front Mic", 0x1 },
4762 { "Mic", 0x4},
4763 { "Line", 0x2 },
4764 { "Digital Mic", 0x06 },
4765 { "Mix", 0x7 },
4766 },
4767};
4768
4769static const struct snd_kcontrol_new ad1882_base_mixers[] = {
4770 HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT),
4771 HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT),
4772 HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT),
4773 HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT),
4774 HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT),
4775 HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT),
4776 HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT),
4777 HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT),
4778
4779 HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT),
4780 HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT),
4781 HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT),
4782 HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT),
4783 HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT),
4784 HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT),
4785 HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT),
4786 {
4787 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4788
4789
4790
4791
4792 .name = "Input Source",
4793 .count = 2,
4794 .info = ad198x_mux_enum_info,
4795 .get = ad198x_mux_enum_get,
4796 .put = ad198x_mux_enum_put,
4797 },
4798
4799 HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT),
4800 {
4801 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4802 .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source",
4803
4804 .info = ad1983_spdif_route_info,
4805 .get = ad1983_spdif_route_get,
4806 .put = ad1983_spdif_route_put,
4807 },
4808 { }
4809};
4810
4811static const struct snd_kcontrol_new ad1882_loopback_mixers[] = {
4812 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4813 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4814 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT),
4815 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT),
4816 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT),
4817 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT),
4818 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4819 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4820 { }
4821};
4822
4823static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = {
4824 HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT),
4825 HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT),
4826 HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT),
4827 HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT),
4828 HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT),
4829 HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT),
4830 HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT),
4831 HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT),
4832 HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT),
4833 { }
4834};
4835
4836static const struct snd_kcontrol_new ad1882_3stack_mixers[] = {
4837 HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT),
4838 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT),
4839 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT),
4840 {
4841 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
4842 .name = "Channel Mode",
4843 .info = ad198x_ch_mode_info,
4844 .get = ad198x_ch_mode_get,
4845 .put = ad198x_ch_mode_put,
4846 },
4847 { }
4848};
4849
4850static const struct snd_kcontrol_new ad1882_6stack_mixers[] = {
4851 HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT),
4852 HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT),
4853 HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT),
4854 { }
4855};
4856
4857static const struct hda_verb ad1882_ch2_init[] = {
4858 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4859 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4860 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4861 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4862 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4863 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4864 { }
4865};
4866
4867static const struct hda_verb ad1882_ch4_init[] = {
4868 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4869 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4870 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4871 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4872 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4873 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4874 { }
4875};
4876
4877static const struct hda_verb ad1882_ch6_init[] = {
4878 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4879 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4880 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4881 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4882 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4883 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4884 { }
4885};
4886
4887static const struct hda_channel_mode ad1882_modes[3] = {
4888 { 2, ad1882_ch2_init },
4889 { 4, ad1882_ch4_init },
4890 { 6, ad1882_ch6_init },
4891};
4892
4893
4894
4895
4896static const struct hda_verb ad1882_init_verbs[] = {
4897
4898 {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4899 {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4900 {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4901
4902 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4903 {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4904
4905 {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4906 {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4907
4908 {0x37, AC_VERB_SET_CONNECT_SEL, 0x1},
4909
4910 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4911 {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4912
4913 {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4914 {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4915
4916 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
4917 {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)},
4918
4919 {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP},
4920 {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4921
4922 {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4923 {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4924 {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4925
4926 {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN},
4927 {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4928 {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4929
4930 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4931 {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4932
4933 {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},
4934 {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4935 {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO},
4936
4937 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4938 {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4939
4940 {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4941 {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4942
4943 {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT},
4944 {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE},
4945
4946
4947 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)},
4948 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
4949 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)},
4950 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)},
4951 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)},
4952 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)},
4953 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)},
4954 {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)},
4955
4956 {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f},
4957
4958 {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27},
4959 {0x02, AC_VERB_SET_CONNECT_SEL, 0x0},
4960 {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27},
4961 { }
4962};
4963
4964#ifdef CONFIG_SND_HDA_POWER_SAVE
4965static const struct hda_amp_list ad1882_loopbacks[] = {
4966 { 0x20, HDA_INPUT, 0 },
4967 { 0x20, HDA_INPUT, 1 },
4968 { 0x20, HDA_INPUT, 4 },
4969 { 0x20, HDA_INPUT, 6 },
4970 { }
4971};
4972#endif
4973
4974
4975enum {
4976 AD1882_3STACK,
4977 AD1882_6STACK,
4978 AD1882_MODELS
4979};
4980
4981static const char * const ad1882_models[AD1986A_MODELS] = {
4982 [AD1882_3STACK] = "3stack",
4983 [AD1882_6STACK] = "6stack",
4984};
4985
4986
4987static int patch_ad1882(struct hda_codec *codec)
4988{
4989 struct ad198x_spec *spec;
4990 int err, board_config;
4991
4992 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
4993 if (spec == NULL)
4994 return -ENOMEM;
4995
4996 codec->spec = spec;
4997
4998 err = snd_hda_attach_beep_device(codec, 0x10);
4999 if (err < 0) {
5000 ad198x_free(codec);
5001 return err;
5002 }
5003 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
5004
5005 spec->multiout.max_channels = 6;
5006 spec->multiout.num_dacs = 3;
5007 spec->multiout.dac_nids = ad1882_dac_nids;
5008 spec->multiout.dig_out_nid = AD1882_SPDIF_OUT;
5009 spec->num_adc_nids = ARRAY_SIZE(ad1882_adc_nids);
5010 spec->adc_nids = ad1882_adc_nids;
5011 spec->capsrc_nids = ad1882_capsrc_nids;
5012 if (codec->vendor_id == 0x11d41882)
5013 spec->input_mux = &ad1882_capture_source;
5014 else
5015 spec->input_mux = &ad1882a_capture_source;
5016 spec->num_mixers = 2;
5017 spec->mixers[0] = ad1882_base_mixers;
5018 if (codec->vendor_id == 0x11d41882)
5019 spec->mixers[1] = ad1882_loopback_mixers;
5020 else
5021 spec->mixers[1] = ad1882a_loopback_mixers;
5022 spec->num_init_verbs = 1;
5023 spec->init_verbs[0] = ad1882_init_verbs;
5024 spec->spdif_route = 0;
5025#ifdef CONFIG_SND_HDA_POWER_SAVE
5026 spec->loopback.amplist = ad1882_loopbacks;
5027#endif
5028 spec->vmaster_nid = 0x04;
5029
5030 codec->patch_ops = ad198x_patch_ops;
5031
5032
5033 board_config = snd_hda_check_board_config(codec, AD1882_MODELS,
5034 ad1882_models, NULL);
5035 switch (board_config) {
5036 default:
5037 case AD1882_3STACK:
5038 spec->num_mixers = 3;
5039 spec->mixers[2] = ad1882_3stack_mixers;
5040 spec->channel_mode = ad1882_modes;
5041 spec->num_channel_mode = ARRAY_SIZE(ad1882_modes);
5042 spec->need_dac_fix = 1;
5043 spec->multiout.max_channels = 2;
5044 spec->multiout.num_dacs = 1;
5045 break;
5046 case AD1882_6STACK:
5047 spec->num_mixers = 3;
5048 spec->mixers[2] = ad1882_6stack_mixers;
5049 break;
5050 }
5051
5052 codec->no_trigger_sense = 1;
5053 codec->no_sticky_stream = 1;
5054
5055 return 0;
5056}
5057
5058
5059
5060
5061
5062static const struct hda_codec_preset snd_hda_preset_analog[] = {
5063 { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a },
5064 { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 },
5065 { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a },
5066 { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 },
5067 { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a },
5068 { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a },
5069 { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 },
5070 { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 },
5071 { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 },
5072 { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a },
5073 { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 },
5074 { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 },
5075 { .id = 0x11d4882a, .name = "AD1882A", .patch = patch_ad1882 },
5076 { .id = 0x11d4989a, .name = "AD1989A", .patch = patch_ad1988 },
5077 { .id = 0x11d4989b, .name = "AD1989B", .patch = patch_ad1988 },
5078 {}
5079};
5080
5081MODULE_ALIAS("snd-hda-codec-id:11d4*");
5082
5083MODULE_LICENSE("GPL");
5084MODULE_DESCRIPTION("Analog Devices HD-audio codec");
5085
5086static struct hda_codec_preset_list analog_list = {
5087 .preset = snd_hda_preset_analog,
5088 .owner = THIS_MODULE,
5089};
5090
5091static int __init patch_analog_init(void)
5092{
5093 return snd_hda_add_codec_preset(&analog_list);
5094}
5095
5096static void __exit patch_analog_exit(void)
5097{
5098 snd_hda_delete_codec_preset(&analog_list);
5099}
5100
5101module_init(patch_analog_init)
5102module_exit(patch_analog_exit)
5103