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