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