1
2
3
4
5
6
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
26 int smux_paths[4];
27 unsigned int cur_smux;
28 hda_nid_t eapd_nid;
29
30 unsigned int beep_amp;
31};
32
33
34#ifdef CONFIG_SND_HDA_INPUT_BEEP
35
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 { }
40};
41
42#define set_beep_amp(spec, nid, idx, dir) \
43 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
44#else
45#define set_beep_amp(spec, nid, idx, dir)
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
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
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
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
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
217
218
219
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
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
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 },
279 { 0x1d, 0x90a7013e },
280 {}
281 },
282 },
283 [AD1986A_FIXUP_SAMSUNG] = {
284 .type = HDA_FIXUP_PINS,
285 .v.pins = (const struct hda_pintbl[]) {
286 { 0x1b, 0x90170110 },
287 { 0x1d, 0x90a7013e },
288 { 0x20, 0x411111f0 },
289 { 0x24, 0x411111f0 },
290 {}
291 },
292 },
293 [AD1986A_FIXUP_3STACK] = {
294 .type = HDA_FIXUP_PINS,
295 .v.pins = (const struct hda_pintbl[]) {
296 { 0x1a, 0x02214021 },
297 { 0x1b, 0x01014011 },
298 { 0x1c, 0x01813030 },
299 { 0x1d, 0x01a19020 },
300 { 0x1e, 0x411111f0 },
301 { 0x1f, 0x02a190f0 },
302 { 0x20, 0x411111f0 },
303 {}
304 },
305 },
306 [AD1986A_FIXUP_LAPTOP] = {
307 .type = HDA_FIXUP_PINS,
308 .v.pins = (const struct hda_pintbl[]) {
309 { 0x1a, 0x02214021 },
310 { 0x1b, 0x90170110 },
311 { 0x1c, 0x411111f0 },
312 { 0x1d, 0x411111f0 },
313 { 0x1e, 0x411111f0 },
314 { 0x1f, 0x02a191f0 },
315 { 0x20, 0x411111f0 },
316 {}
317 },
318 },
319 [AD1986A_FIXUP_LAPTOP_IMIC] = {
320 .type = HDA_FIXUP_PINS,
321 .v.pins = (const struct hda_pintbl[]) {
322 { 0x1d, 0x90a7013e },
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 },
340 { 0x1b, 0x90170110 },
341 { 0x1c, 0x411111f0 },
342 { 0x1d, 0x90a70130 },
343 { 0x1e, 0x411111f0 },
344 { 0x1f, 0x04a19040 },
345 { 0x20, 0x411111f0 },
346 { 0x21, 0x411111f0 },
347 { 0x22, 0x411111f0 },
348 { 0x23, 0x411111f0 },
349 { 0x24, 0x411111f0 },
350 { 0x25, 0x411111f0 },
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, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
361 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
362 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
363 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
364 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
365 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),
366 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
367 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
368 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
369 SND_PCI_QUIRK(0x1631, 0xc022, "PackardBell EasyNote MX65", AD1986A_FIXUP_EASYNOTE),
370 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
371 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
372 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
373 {}
374};
375
376static const struct hda_model_fixup ad1986a_fixup_models[] = {
377 { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
378 { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
379 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
380 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" },
381 { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
382 {}
383};
384
385
386
387static int patch_ad1986a(struct hda_codec *codec)
388{
389 int err;
390 struct ad198x_spec *spec;
391 static hda_nid_t preferred_pairs[] = {
392 0x1a, 0x03,
393 0x1b, 0x03,
394 0x1c, 0x04,
395 0x1d, 0x05,
396 0x1e, 0x03,
397 0
398 };
399
400 err = alloc_ad_spec(codec);
401 if (err < 0)
402 return err;
403 spec = codec->spec;
404
405
406 codec->inv_eapd = 1;
407
408 spec->gen.mixer_nid = 0x07;
409 spec->gen.beep_nid = 0x19;
410 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
411
412
413
414
415
416
417
418 spec->gen.multiout.no_share_stream = 1;
419
420 spec->gen.preferred_dacs = preferred_pairs;
421
422
423 spec->gen.auto_mute_via_amp = 1;
424
425 snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
426 ad1986a_fixups);
427 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
428
429 err = ad198x_parse_auto_config(codec, false);
430 if (err < 0) {
431 snd_hda_gen_free(codec);
432 return err;
433 }
434
435 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
436
437 return 0;
438}
439
440
441
442
443
444
445
446
447
448static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
449 struct snd_ctl_elem_info *uinfo)
450{
451 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
452 struct ad198x_spec *spec = codec->spec;
453 static const char * const texts2[] = { "PCM", "ADC" };
454 static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
455 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
456 int num_conns = snd_hda_get_num_conns(codec, dig_out);
457
458 if (num_conns == 2)
459 return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
460 else if (num_conns == 3)
461 return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
462 else
463 return -EINVAL;
464}
465
466static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
467 struct snd_ctl_elem_value *ucontrol)
468{
469 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
470 struct ad198x_spec *spec = codec->spec;
471
472 ucontrol->value.enumerated.item[0] = spec->cur_smux;
473 return 0;
474}
475
476static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
477 struct snd_ctl_elem_value *ucontrol)
478{
479 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
480 struct ad198x_spec *spec = codec->spec;
481 unsigned int val = ucontrol->value.enumerated.item[0];
482 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
483 int num_conns = snd_hda_get_num_conns(codec, dig_out);
484
485 if (val >= num_conns)
486 return -EINVAL;
487 if (spec->cur_smux == val)
488 return 0;
489 spec->cur_smux = val;
490 snd_hda_codec_write_cache(codec, dig_out, 0,
491 AC_VERB_SET_CONNECT_SEL, val);
492 return 1;
493}
494
495static const struct snd_kcontrol_new ad1983_auto_smux_mixer = {
496 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
497 .name = "IEC958 Playback Source",
498 .info = ad1983_auto_smux_enum_info,
499 .get = ad1983_auto_smux_enum_get,
500 .put = ad1983_auto_smux_enum_put,
501};
502
503static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
504{
505 struct ad198x_spec *spec = codec->spec;
506 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
507 int num_conns;
508
509 if (!dig_out)
510 return 0;
511 num_conns = snd_hda_get_num_conns(codec, dig_out);
512 if (num_conns != 2 && num_conns != 3)
513 return 0;
514 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
515 return -ENOMEM;
516 return 0;
517}
518
519static int patch_ad1983(struct hda_codec *codec)
520{
521 struct ad198x_spec *spec;
522 static hda_nid_t conn_0c[] = { 0x08 };
523 static hda_nid_t conn_0d[] = { 0x09 };
524 int err;
525
526 err = alloc_ad_spec(codec);
527 if (err < 0)
528 return err;
529 spec = codec->spec;
530
531 spec->gen.mixer_nid = 0x0e;
532 spec->gen.beep_nid = 0x10;
533 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
534
535
536 snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);
537 snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);
538
539 err = ad198x_parse_auto_config(codec, false);
540 if (err < 0)
541 goto error;
542 err = ad1983_add_spdif_mux_ctl(codec);
543 if (err < 0)
544 goto error;
545 return 0;
546
547 error:
548 snd_hda_gen_free(codec);
549 return err;
550}
551
552
553
554
555
556
557static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
558 const struct hda_fixup *fix, int action)
559{
560 struct ad198x_spec *spec = codec->spec;
561
562 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
563 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
564 spec->eapd_nid = 0x05;
565 }
566}
567
568
569
570
571static void ad1981_fixup_amp_override(struct hda_codec *codec,
572 const struct hda_fixup *fix, int action)
573{
574 if (action == HDA_FIXUP_ACT_PRE_PROBE)
575 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
576 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
577 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
578 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
579 (1 << AC_AMPCAP_MUTE_SHIFT));
580}
581
582enum {
583 AD1981_FIXUP_AMP_OVERRIDE,
584 AD1981_FIXUP_HP_EAPD,
585};
586
587static const struct hda_fixup ad1981_fixups[] = {
588 [AD1981_FIXUP_AMP_OVERRIDE] = {
589 .type = HDA_FIXUP_FUNC,
590 .v.func = ad1981_fixup_amp_override,
591 },
592 [AD1981_FIXUP_HP_EAPD] = {
593 .type = HDA_FIXUP_FUNC,
594 .v.func = ad1981_fixup_hp_eapd,
595 .chained = true,
596 .chain_id = AD1981_FIXUP_AMP_OVERRIDE,
597 },
598};
599
600static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
601 SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
602 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
603 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
604
605 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
606 {}
607};
608
609static int patch_ad1981(struct hda_codec *codec)
610{
611 struct ad198x_spec *spec;
612 int err;
613
614 err = alloc_ad_spec(codec);
615 if (err < 0)
616 return -ENOMEM;
617 spec = codec->spec;
618
619 spec->gen.mixer_nid = 0x0e;
620 spec->gen.beep_nid = 0x10;
621 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
622
623 snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
624 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
625
626 err = ad198x_parse_auto_config(codec, false);
627 if (err < 0)
628 goto error;
629 err = ad1983_add_spdif_mux_ctl(codec);
630 if (err < 0)
631 goto error;
632
633 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
634
635 return 0;
636
637 error:
638 snd_hda_gen_free(codec);
639 return err;
640}
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
729 struct snd_ctl_elem_info *uinfo)
730{
731 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
732 static const char * const texts[] = {
733 "PCM", "ADC1", "ADC2", "ADC3",
734 };
735 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
736 if (num_conns > 4)
737 num_conns = 4;
738 return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
739}
740
741static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
742 struct snd_ctl_elem_value *ucontrol)
743{
744 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
745 struct ad198x_spec *spec = codec->spec;
746
747 ucontrol->value.enumerated.item[0] = spec->cur_smux;
748 return 0;
749}
750
751static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
752 struct snd_ctl_elem_value *ucontrol)
753{
754 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
755 struct ad198x_spec *spec = codec->spec;
756 unsigned int val = ucontrol->value.enumerated.item[0];
757 struct nid_path *path;
758 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
759
760 if (val >= num_conns)
761 return -EINVAL;
762 if (spec->cur_smux == val)
763 return 0;
764
765 mutex_lock(&codec->control_mutex);
766 path = snd_hda_get_path_from_idx(codec,
767 spec->smux_paths[spec->cur_smux]);
768 if (path)
769 snd_hda_activate_path(codec, path, false, true);
770 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
771 if (path)
772 snd_hda_activate_path(codec, path, true, true);
773 spec->cur_smux = val;
774 mutex_unlock(&codec->control_mutex);
775 return 1;
776}
777
778static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
780 .name = "IEC958 Playback Source",
781 .info = ad1988_auto_smux_enum_info,
782 .get = ad1988_auto_smux_enum_get,
783 .put = ad1988_auto_smux_enum_put,
784};
785
786static int ad1988_auto_init(struct hda_codec *codec)
787{
788 struct ad198x_spec *spec = codec->spec;
789 int i, err;
790
791 err = snd_hda_gen_init(codec);
792 if (err < 0)
793 return err;
794 if (!spec->gen.autocfg.dig_outs)
795 return 0;
796
797 for (i = 0; i < 4; i++) {
798 struct nid_path *path;
799 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
800 if (path)
801 snd_hda_activate_path(codec, path, path->active, false);
802 }
803
804 return 0;
805}
806
807static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
808{
809 struct ad198x_spec *spec = codec->spec;
810 int i, num_conns;
811
812
813
814 static struct nid_path fake_paths[4] = {
815 {
816 .depth = 3,
817 .path = { 0x02, 0x1d, 0x1b },
818 .idx = { 0, 0, 0 },
819 .multi = { 0, 0, 0 },
820 },
821 {
822 .depth = 4,
823 .path = { 0x08, 0x0b, 0x1d, 0x1b },
824 .idx = { 0, 0, 1, 0 },
825 .multi = { 0, 1, 0, 0 },
826 },
827 {
828 .depth = 4,
829 .path = { 0x09, 0x0b, 0x1d, 0x1b },
830 .idx = { 0, 1, 1, 0 },
831 .multi = { 0, 1, 0, 0 },
832 },
833 {
834 .depth = 4,
835 .path = { 0x0f, 0x0b, 0x1d, 0x1b },
836 .idx = { 0, 2, 1, 0 },
837 .multi = { 0, 1, 0, 0 },
838 },
839 };
840
841
842 if (!spec->gen.autocfg.dig_outs ||
843 get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
844 return 0;
845
846 num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
847 if (num_conns != 3 && num_conns != 4)
848 return 0;
849
850 for (i = 0; i < num_conns; i++) {
851 struct nid_path *path = snd_array_new(&spec->gen.paths);
852 if (!path)
853 return -ENOMEM;
854 *path = fake_paths[i];
855 if (!i)
856 path->active = 1;
857 spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
858 }
859
860 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
861 return -ENOMEM;
862
863 codec->patch_ops.init = ad1988_auto_init;
864
865 return 0;
866}
867
868
869
870
871enum {
872 AD1988_FIXUP_6STACK_DIG,
873};
874
875static const struct hda_fixup ad1988_fixups[] = {
876 [AD1988_FIXUP_6STACK_DIG] = {
877 .type = HDA_FIXUP_PINS,
878 .v.pins = (const struct hda_pintbl[]) {
879 { 0x11, 0x02214130 },
880 { 0x12, 0x01014010 },
881 { 0x14, 0x02a19122 },
882 { 0x15, 0x01813021 },
883 { 0x16, 0x01011012 },
884 { 0x17, 0x01a19020 },
885 { 0x1b, 0x0145f1f0 },
886 { 0x24, 0x01016011 },
887 { 0x25, 0x01012013 },
888 { }
889 }
890 },
891};
892
893static const struct hda_model_fixup ad1988_fixup_models[] = {
894 { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
895 {}
896};
897
898static int patch_ad1988(struct hda_codec *codec)
899{
900 struct ad198x_spec *spec;
901 int err;
902
903 err = alloc_ad_spec(codec);
904 if (err < 0)
905 return err;
906 spec = codec->spec;
907
908 spec->gen.mixer_nid = 0x20;
909 spec->gen.mixer_merge_nid = 0x21;
910 spec->gen.beep_nid = 0x10;
911 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
912
913 snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
914 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
915
916 err = ad198x_parse_auto_config(codec, true);
917 if (err < 0)
918 goto error;
919 err = ad1988_add_spdif_mux_ctl(codec);
920 if (err < 0)
921 goto error;
922
923 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
924
925 return 0;
926
927 error:
928 snd_hda_gen_free(codec);
929 return err;
930}
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962static void ad1884_fixup_amp_override(struct hda_codec *codec,
963 const struct hda_fixup *fix, int action)
964{
965 if (action == HDA_FIXUP_ACT_PRE_PROBE)
966 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
967 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
968 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
969 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
970 (1 << AC_AMPCAP_MUTE_SHIFT));
971}
972
973
974static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
975{
976 struct hda_codec *codec = private_data;
977 struct ad198x_spec *spec = codec->spec;
978
979 if (spec->eapd_nid)
980 ad_vmaster_eapd_hook(private_data, enabled);
981 snd_hda_codec_write_cache(codec, 0x01, 0,
982 AC_VERB_SET_GPIO_DATA,
983 enabled ? 0x00 : 0x02);
984}
985
986static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
987 const struct hda_fixup *fix, int action)
988{
989 struct ad198x_spec *spec = codec->spec;
990
991 switch (action) {
992 case HDA_FIXUP_ACT_PRE_PROBE:
993 spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
994 spec->gen.own_eapd_ctl = 1;
995 snd_hda_codec_write_cache(codec, 0x01, 0,
996 AC_VERB_SET_GPIO_MASK, 0x02);
997 snd_hda_codec_write_cache(codec, 0x01, 0,
998 AC_VERB_SET_GPIO_DIRECTION, 0x02);
999 snd_hda_codec_write_cache(codec, 0x01, 0,
1000 AC_VERB_SET_GPIO_DATA, 0x02);
1001 break;
1002 case HDA_FIXUP_ACT_PROBE:
1003 if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
1004 spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
1005 else
1006 spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
1007 break;
1008 }
1009}
1010
1011static void ad1884_fixup_thinkpad(struct hda_codec *codec,
1012 const struct hda_fixup *fix, int action)
1013{
1014 struct ad198x_spec *spec = codec->spec;
1015
1016 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
1017 spec->gen.keep_eapd_on = 1;
1018 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
1019 spec->eapd_nid = 0x12;
1020
1021 spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
1022 spec->gen.beep_nid = 0;
1023 }
1024}
1025
1026
1027static const struct hda_verb ad1884_dmic_init_verbs[] = {
1028 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
1029 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
1030 {}
1031};
1032
1033enum {
1034 AD1884_FIXUP_AMP_OVERRIDE,
1035 AD1884_FIXUP_HP_EAPD,
1036 AD1884_FIXUP_DMIC_COEF,
1037 AD1884_FIXUP_THINKPAD,
1038 AD1884_FIXUP_HP_TOUCHSMART,
1039};
1040
1041static const struct hda_fixup ad1884_fixups[] = {
1042 [AD1884_FIXUP_AMP_OVERRIDE] = {
1043 .type = HDA_FIXUP_FUNC,
1044 .v.func = ad1884_fixup_amp_override,
1045 },
1046 [AD1884_FIXUP_HP_EAPD] = {
1047 .type = HDA_FIXUP_FUNC,
1048 .v.func = ad1884_fixup_hp_eapd,
1049 .chained = true,
1050 .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
1051 },
1052 [AD1884_FIXUP_DMIC_COEF] = {
1053 .type = HDA_FIXUP_VERBS,
1054 .v.verbs = ad1884_dmic_init_verbs,
1055 },
1056 [AD1884_FIXUP_THINKPAD] = {
1057 .type = HDA_FIXUP_FUNC,
1058 .v.func = ad1884_fixup_thinkpad,
1059 .chained = true,
1060 .chain_id = AD1884_FIXUP_DMIC_COEF,
1061 },
1062 [AD1884_FIXUP_HP_TOUCHSMART] = {
1063 .type = HDA_FIXUP_VERBS,
1064 .v.verbs = ad1884_dmic_init_verbs,
1065 .chained = true,
1066 .chain_id = AD1884_FIXUP_HP_EAPD,
1067 },
1068};
1069
1070static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
1071 SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
1072 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
1073 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
1074 {}
1075};
1076
1077
1078static int patch_ad1884(struct hda_codec *codec)
1079{
1080 struct ad198x_spec *spec;
1081 int err;
1082
1083 err = alloc_ad_spec(codec);
1084 if (err < 0)
1085 return err;
1086 spec = codec->spec;
1087
1088 spec->gen.mixer_nid = 0x20;
1089 spec->gen.mixer_merge_nid = 0x21;
1090 spec->gen.beep_nid = 0x10;
1091 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1092
1093 snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
1094 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1095
1096 err = ad198x_parse_auto_config(codec, true);
1097 if (err < 0)
1098 goto error;
1099 err = ad1983_add_spdif_mux_ctl(codec);
1100 if (err < 0)
1101 goto error;
1102
1103 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1104
1105 return 0;
1106
1107 error:
1108 snd_hda_gen_free(codec);
1109 return err;
1110}
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124static int patch_ad1882(struct hda_codec *codec)
1125{
1126 struct ad198x_spec *spec;
1127 int err;
1128
1129 err = alloc_ad_spec(codec);
1130 if (err < 0)
1131 return err;
1132 spec = codec->spec;
1133
1134 spec->gen.mixer_nid = 0x20;
1135 spec->gen.mixer_merge_nid = 0x21;
1136 spec->gen.beep_nid = 0x10;
1137 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1138 err = ad198x_parse_auto_config(codec, true);
1139 if (err < 0)
1140 goto error;
1141 err = ad1988_add_spdif_mux_ctl(codec);
1142 if (err < 0)
1143 goto error;
1144 return 0;
1145
1146 error:
1147 snd_hda_gen_free(codec);
1148 return err;
1149}
1150
1151
1152
1153
1154
1155static const struct hda_device_id snd_hda_id_analog[] = {
1156 HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
1157 HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
1158 HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
1159 HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
1160 HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
1161 HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
1162 HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
1163 HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
1164 HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
1165 HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
1166 HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
1167 HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
1168 HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
1169 HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
1170 HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
1171 {}
1172};
1173MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
1174
1175MODULE_LICENSE("GPL");
1176MODULE_DESCRIPTION("Analog Devices HD-audio codec");
1177
1178static struct hda_codec_driver analog_driver = {
1179 .id = snd_hda_id_analog,
1180};
1181
1182module_hda_codec_driver(analog_driver);
1183