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 int num_smux_conns;
32};
33
34
35#ifdef CONFIG_SND_HDA_INPUT_BEEP
36
37static const struct snd_kcontrol_new ad_beep_mixer[] = {
38 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
39 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
40 { }
41};
42
43#define set_beep_amp(spec, nid, idx, dir) \
44 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir))
45#else
46#define set_beep_amp(spec, nid, idx, dir)
47#endif
48
49#ifdef CONFIG_SND_HDA_INPUT_BEEP
50static int create_beep_ctls(struct hda_codec *codec)
51{
52 struct ad198x_spec *spec = codec->spec;
53 const struct snd_kcontrol_new *knew;
54
55 if (!spec->beep_amp)
56 return 0;
57
58 for (knew = ad_beep_mixer ; knew->name; knew++) {
59 int err;
60 struct snd_kcontrol *kctl;
61 kctl = snd_ctl_new1(knew, codec);
62 if (!kctl)
63 return -ENOMEM;
64 kctl->private_value = spec->beep_amp;
65 err = snd_hda_ctl_add(codec, 0, kctl);
66 if (err < 0)
67 return err;
68 }
69 return 0;
70}
71#else
72#define create_beep_ctls(codec) 0
73#endif
74
75
76static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
77 hda_nid_t hp)
78{
79 if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
80 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
81 !codec->inv_eapd ? 0x00 : 0x02);
82 if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
83 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
84 !codec->inv_eapd ? 0x00 : 0x02);
85}
86
87static void ad198x_power_eapd(struct hda_codec *codec)
88{
89
90 switch (codec->core.vendor_id) {
91 case 0x11d41882:
92 case 0x11d4882a:
93 case 0x11d41884:
94 case 0x11d41984:
95 case 0x11d41883:
96 case 0x11d4184a:
97 case 0x11d4194a:
98 case 0x11d4194b:
99 case 0x11d41988:
100 case 0x11d4198b:
101 case 0x11d4989a:
102 case 0x11d4989b:
103 ad198x_power_eapd_write(codec, 0x12, 0x11);
104 break;
105 case 0x11d41981:
106 case 0x11d41983:
107 ad198x_power_eapd_write(codec, 0x05, 0x06);
108 break;
109 case 0x11d41986:
110 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
111 break;
112 }
113}
114
115static void ad198x_shutup(struct hda_codec *codec)
116{
117 snd_hda_shutup_pins(codec);
118 ad198x_power_eapd(codec);
119}
120
121#ifdef CONFIG_PM
122static int ad198x_suspend(struct hda_codec *codec)
123{
124 ad198x_shutup(codec);
125 return 0;
126}
127#endif
128
129
130static void ad_vmaster_eapd_hook(void *private_data, int enabled)
131{
132 struct hda_codec *codec = private_data;
133 struct ad198x_spec *spec = codec->spec;
134
135 if (!spec->eapd_nid)
136 return;
137 if (codec->inv_eapd)
138 enabled = !enabled;
139 snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,
140 AC_VERB_SET_EAPD_BTLENABLE,
141 enabled ? 0x02 : 0x00);
142}
143
144
145
146
147
148static int ad198x_auto_build_controls(struct hda_codec *codec)
149{
150 int err;
151
152 err = snd_hda_gen_build_controls(codec);
153 if (err < 0)
154 return err;
155 err = create_beep_ctls(codec);
156 if (err < 0)
157 return err;
158 return 0;
159}
160
161static const struct hda_codec_ops ad198x_auto_patch_ops = {
162 .build_controls = ad198x_auto_build_controls,
163 .build_pcms = snd_hda_gen_build_pcms,
164 .init = snd_hda_gen_init,
165 .free = snd_hda_gen_free,
166 .unsol_event = snd_hda_jack_unsol_event,
167#ifdef CONFIG_PM
168 .check_power_status = snd_hda_gen_check_power_status,
169 .suspend = ad198x_suspend,
170#endif
171 .reboot_notify = ad198x_shutup,
172};
173
174
175static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
176{
177 struct ad198x_spec *spec = codec->spec;
178 struct auto_pin_cfg *cfg = &spec->gen.autocfg;
179 int err;
180
181 codec->spdif_status_reset = 1;
182 codec->no_trigger_sense = 1;
183 codec->no_sticky_stream = 1;
184
185 spec->gen.indep_hp = indep_hp;
186 if (!spec->gen.add_stereo_mix_input)
187 spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
188
189 err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
190 if (err < 0)
191 return err;
192 err = snd_hda_gen_parse_auto_config(codec, cfg);
193 if (err < 0)
194 return err;
195
196 return 0;
197}
198
199
200
201
202
203static int alloc_ad_spec(struct hda_codec *codec)
204{
205 struct ad198x_spec *spec;
206
207 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
208 if (!spec)
209 return -ENOMEM;
210 codec->spec = spec;
211 snd_hda_gen_spec_init(&spec->gen);
212 codec->patch_ops = ad198x_auto_patch_ops;
213 return 0;
214}
215
216
217
218
219
220
221static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
222 const struct hda_fixup *fix, int action)
223{
224 struct ad198x_spec *spec = codec->spec;
225
226 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
227 codec->inv_jack_detect = 1;
228 spec->gen.keep_eapd_on = 1;
229 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
230 spec->eapd_nid = 0x1b;
231 }
232}
233
234
235static void ad1986a_fixup_eapd(struct hda_codec *codec,
236 const struct hda_fixup *fix, int action)
237{
238 struct ad198x_spec *spec = codec->spec;
239
240 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
241 codec->inv_eapd = 0;
242 spec->gen.keep_eapd_on = 1;
243 spec->eapd_nid = 0x1b;
244 }
245}
246
247
248static void ad1986a_fixup_eapd_mix_in(struct hda_codec *codec,
249 const struct hda_fixup *fix, int action)
250{
251 struct ad198x_spec *spec = codec->spec;
252
253 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
254 ad1986a_fixup_eapd(codec, fix, action);
255 spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_ENABLE;
256 }
257}
258
259enum {
260 AD1986A_FIXUP_INV_JACK_DETECT,
261 AD1986A_FIXUP_ULTRA,
262 AD1986A_FIXUP_SAMSUNG,
263 AD1986A_FIXUP_3STACK,
264 AD1986A_FIXUP_LAPTOP,
265 AD1986A_FIXUP_LAPTOP_IMIC,
266 AD1986A_FIXUP_EAPD,
267 AD1986A_FIXUP_EAPD_MIX_IN,
268 AD1986A_FIXUP_EASYNOTE,
269};
270
271static const struct hda_fixup ad1986a_fixups[] = {
272 [AD1986A_FIXUP_INV_JACK_DETECT] = {
273 .type = HDA_FIXUP_FUNC,
274 .v.func = ad_fixup_inv_jack_detect,
275 },
276 [AD1986A_FIXUP_ULTRA] = {
277 .type = HDA_FIXUP_PINS,
278 .v.pins = (const struct hda_pintbl[]) {
279 { 0x1b, 0x90170110 },
280 { 0x1d, 0x90a7013e },
281 {}
282 },
283 },
284 [AD1986A_FIXUP_SAMSUNG] = {
285 .type = HDA_FIXUP_PINS,
286 .v.pins = (const struct hda_pintbl[]) {
287 { 0x1b, 0x90170110 },
288 { 0x1d, 0x90a7013e },
289 { 0x20, 0x411111f0 },
290 { 0x24, 0x411111f0 },
291 {}
292 },
293 },
294 [AD1986A_FIXUP_3STACK] = {
295 .type = HDA_FIXUP_PINS,
296 .v.pins = (const struct hda_pintbl[]) {
297 { 0x1a, 0x02214021 },
298 { 0x1b, 0x01014011 },
299 { 0x1c, 0x01813030 },
300 { 0x1d, 0x01a19020 },
301 { 0x1e, 0x411111f0 },
302 { 0x1f, 0x02a190f0 },
303 { 0x20, 0x411111f0 },
304 {}
305 },
306 },
307 [AD1986A_FIXUP_LAPTOP] = {
308 .type = HDA_FIXUP_PINS,
309 .v.pins = (const struct hda_pintbl[]) {
310 { 0x1a, 0x02214021 },
311 { 0x1b, 0x90170110 },
312 { 0x1c, 0x411111f0 },
313 { 0x1d, 0x411111f0 },
314 { 0x1e, 0x411111f0 },
315 { 0x1f, 0x02a191f0 },
316 { 0x20, 0x411111f0 },
317 {}
318 },
319 },
320 [AD1986A_FIXUP_LAPTOP_IMIC] = {
321 .type = HDA_FIXUP_PINS,
322 .v.pins = (const struct hda_pintbl[]) {
323 { 0x1d, 0x90a7013e },
324 {}
325 },
326 .chained_before = 1,
327 .chain_id = AD1986A_FIXUP_LAPTOP,
328 },
329 [AD1986A_FIXUP_EAPD] = {
330 .type = HDA_FIXUP_FUNC,
331 .v.func = ad1986a_fixup_eapd,
332 },
333 [AD1986A_FIXUP_EAPD_MIX_IN] = {
334 .type = HDA_FIXUP_FUNC,
335 .v.func = ad1986a_fixup_eapd_mix_in,
336 },
337 [AD1986A_FIXUP_EASYNOTE] = {
338 .type = HDA_FIXUP_PINS,
339 .v.pins = (const struct hda_pintbl[]) {
340 { 0x1a, 0x0421402f },
341 { 0x1b, 0x90170110 },
342 { 0x1c, 0x411111f0 },
343 { 0x1d, 0x90a70130 },
344 { 0x1e, 0x411111f0 },
345 { 0x1f, 0x04a19040 },
346 { 0x20, 0x411111f0 },
347 { 0x21, 0x411111f0 },
348 { 0x22, 0x411111f0 },
349 { 0x23, 0x411111f0 },
350 { 0x24, 0x411111f0 },
351 { 0x25, 0x411111f0 },
352 {}
353 },
354 .chained = true,
355 .chain_id = AD1986A_FIXUP_EAPD_MIX_IN,
356 },
357};
358
359static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
360 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
361 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC),
362 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
363 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
364 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
365 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
366 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
367 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),
368 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
369 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
370 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
371 SND_PCI_QUIRK(0x1631, 0xc022, "PackardBell EasyNote MX65", AD1986A_FIXUP_EASYNOTE),
372 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
373 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
374 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
375 {}
376};
377
378static const struct hda_model_fixup ad1986a_fixup_models[] = {
379 { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
380 { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
381 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
382 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" },
383 { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
384 {}
385};
386
387
388
389static int patch_ad1986a(struct hda_codec *codec)
390{
391 int err;
392 struct ad198x_spec *spec;
393 static const hda_nid_t preferred_pairs[] = {
394 0x1a, 0x03,
395 0x1b, 0x03,
396 0x1c, 0x04,
397 0x1d, 0x05,
398 0x1e, 0x03,
399 0
400 };
401
402 err = alloc_ad_spec(codec);
403 if (err < 0)
404 return err;
405 spec = codec->spec;
406
407
408 codec->inv_eapd = 1;
409
410 spec->gen.mixer_nid = 0x07;
411 spec->gen.beep_nid = 0x19;
412 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
413
414
415
416
417
418
419
420 spec->gen.multiout.no_share_stream = 1;
421
422 spec->gen.preferred_dacs = preferred_pairs;
423
424
425 spec->gen.auto_mute_via_amp = 1;
426
427 snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
428 ad1986a_fixups);
429 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
430
431 err = ad198x_parse_auto_config(codec, false);
432 if (err < 0) {
433 snd_hda_gen_free(codec);
434 return err;
435 }
436
437 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
438
439 return 0;
440}
441
442
443
444
445
446
447
448
449
450static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
451 struct snd_ctl_elem_info *uinfo)
452{
453 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
454 struct ad198x_spec *spec = codec->spec;
455 static const char * const texts2[] = { "PCM", "ADC" };
456 static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
457 int num_conns = spec->num_smux_conns;
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 = spec->num_smux_conns;
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 spec->num_smux_conns = num_conns;
516 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
517 return -ENOMEM;
518 return 0;
519}
520
521static int patch_ad1983(struct hda_codec *codec)
522{
523 static const hda_nid_t conn_0c[] = { 0x08 };
524 static const hda_nid_t conn_0d[] = { 0x09 };
525 struct ad198x_spec *spec;
526 int err;
527
528 err = alloc_ad_spec(codec);
529 if (err < 0)
530 return err;
531 spec = codec->spec;
532
533 spec->gen.mixer_nid = 0x0e;
534 spec->gen.beep_nid = 0x10;
535 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
536
537
538 snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);
539 snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);
540
541 err = ad198x_parse_auto_config(codec, false);
542 if (err < 0)
543 goto error;
544 err = ad1983_add_spdif_mux_ctl(codec);
545 if (err < 0)
546 goto error;
547 return 0;
548
549 error:
550 snd_hda_gen_free(codec);
551 return err;
552}
553
554
555
556
557
558
559static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
560 const struct hda_fixup *fix, int action)
561{
562 struct ad198x_spec *spec = codec->spec;
563
564 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
565 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
566 spec->eapd_nid = 0x05;
567 }
568}
569
570
571
572
573static void ad1981_fixup_amp_override(struct hda_codec *codec,
574 const struct hda_fixup *fix, int action)
575{
576 if (action == HDA_FIXUP_ACT_PRE_PROBE)
577 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
578 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
579 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
580 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
581 (1 << AC_AMPCAP_MUTE_SHIFT));
582}
583
584enum {
585 AD1981_FIXUP_AMP_OVERRIDE,
586 AD1981_FIXUP_HP_EAPD,
587};
588
589static const struct hda_fixup ad1981_fixups[] = {
590 [AD1981_FIXUP_AMP_OVERRIDE] = {
591 .type = HDA_FIXUP_FUNC,
592 .v.func = ad1981_fixup_amp_override,
593 },
594 [AD1981_FIXUP_HP_EAPD] = {
595 .type = HDA_FIXUP_FUNC,
596 .v.func = ad1981_fixup_hp_eapd,
597 .chained = true,
598 .chain_id = AD1981_FIXUP_AMP_OVERRIDE,
599 },
600};
601
602static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
603 SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
604 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
605 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
606
607 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
608 {}
609};
610
611static int patch_ad1981(struct hda_codec *codec)
612{
613 struct ad198x_spec *spec;
614 int err;
615
616 err = alloc_ad_spec(codec);
617 if (err < 0)
618 return -ENOMEM;
619 spec = codec->spec;
620
621 spec->gen.mixer_nid = 0x0e;
622 spec->gen.beep_nid = 0x10;
623 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
624
625 snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
626 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
627
628 err = ad198x_parse_auto_config(codec, false);
629 if (err < 0)
630 goto error;
631 err = ad1983_add_spdif_mux_ctl(codec);
632 if (err < 0)
633 goto error;
634
635 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
636
637 return 0;
638
639 error:
640 snd_hda_gen_free(codec);
641 return err;
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
728
729
730static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
731 struct snd_ctl_elem_info *uinfo)
732{
733 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
734 struct ad198x_spec *spec = codec->spec;
735 static const char * const texts[] = {
736 "PCM", "ADC1", "ADC2", "ADC3",
737 };
738 int num_conns = spec->num_smux_conns;
739
740 if (num_conns > 4)
741 num_conns = 4;
742 return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
743}
744
745static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
746 struct snd_ctl_elem_value *ucontrol)
747{
748 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
749 struct ad198x_spec *spec = codec->spec;
750
751 ucontrol->value.enumerated.item[0] = spec->cur_smux;
752 return 0;
753}
754
755static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
756 struct snd_ctl_elem_value *ucontrol)
757{
758 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
759 struct ad198x_spec *spec = codec->spec;
760 unsigned int val = ucontrol->value.enumerated.item[0];
761 struct nid_path *path;
762 int num_conns = spec->num_smux_conns;
763
764 if (val >= num_conns)
765 return -EINVAL;
766 if (spec->cur_smux == val)
767 return 0;
768
769 mutex_lock(&codec->control_mutex);
770 path = snd_hda_get_path_from_idx(codec,
771 spec->smux_paths[spec->cur_smux]);
772 if (path)
773 snd_hda_activate_path(codec, path, false, true);
774 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
775 if (path)
776 snd_hda_activate_path(codec, path, true, true);
777 spec->cur_smux = val;
778 mutex_unlock(&codec->control_mutex);
779 return 1;
780}
781
782static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
783 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
784 .name = "IEC958 Playback Source",
785 .info = ad1988_auto_smux_enum_info,
786 .get = ad1988_auto_smux_enum_get,
787 .put = ad1988_auto_smux_enum_put,
788};
789
790static int ad1988_auto_init(struct hda_codec *codec)
791{
792 struct ad198x_spec *spec = codec->spec;
793 int i, err;
794
795 err = snd_hda_gen_init(codec);
796 if (err < 0)
797 return err;
798 if (!spec->gen.autocfg.dig_outs)
799 return 0;
800
801 for (i = 0; i < 4; i++) {
802 struct nid_path *path;
803 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
804 if (path)
805 snd_hda_activate_path(codec, path, path->active, false);
806 }
807
808 return 0;
809}
810
811static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
812{
813 struct ad198x_spec *spec = codec->spec;
814 int i, num_conns;
815
816
817
818 static const struct nid_path fake_paths[4] = {
819 {
820 .depth = 3,
821 .path = { 0x02, 0x1d, 0x1b },
822 .idx = { 0, 0, 0 },
823 .multi = { 0, 0, 0 },
824 },
825 {
826 .depth = 4,
827 .path = { 0x08, 0x0b, 0x1d, 0x1b },
828 .idx = { 0, 0, 1, 0 },
829 .multi = { 0, 1, 0, 0 },
830 },
831 {
832 .depth = 4,
833 .path = { 0x09, 0x0b, 0x1d, 0x1b },
834 .idx = { 0, 1, 1, 0 },
835 .multi = { 0, 1, 0, 0 },
836 },
837 {
838 .depth = 4,
839 .path = { 0x0f, 0x0b, 0x1d, 0x1b },
840 .idx = { 0, 2, 1, 0 },
841 .multi = { 0, 1, 0, 0 },
842 },
843 };
844
845
846 if (!spec->gen.autocfg.dig_outs ||
847 get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
848 return 0;
849
850 num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
851 if (num_conns != 3 && num_conns != 4)
852 return 0;
853 spec->num_smux_conns = num_conns;
854
855 for (i = 0; i < num_conns; i++) {
856 struct nid_path *path = snd_array_new(&spec->gen.paths);
857 if (!path)
858 return -ENOMEM;
859 *path = fake_paths[i];
860 if (!i)
861 path->active = 1;
862 spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
863 }
864
865 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
866 return -ENOMEM;
867
868 codec->patch_ops.init = ad1988_auto_init;
869
870 return 0;
871}
872
873
874
875
876enum {
877 AD1988_FIXUP_6STACK_DIG,
878};
879
880static const struct hda_fixup ad1988_fixups[] = {
881 [AD1988_FIXUP_6STACK_DIG] = {
882 .type = HDA_FIXUP_PINS,
883 .v.pins = (const struct hda_pintbl[]) {
884 { 0x11, 0x02214130 },
885 { 0x12, 0x01014010 },
886 { 0x14, 0x02a19122 },
887 { 0x15, 0x01813021 },
888 { 0x16, 0x01011012 },
889 { 0x17, 0x01a19020 },
890 { 0x1b, 0x0145f1f0 },
891 { 0x24, 0x01016011 },
892 { 0x25, 0x01012013 },
893 { }
894 }
895 },
896};
897
898static const struct hda_model_fixup ad1988_fixup_models[] = {
899 { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
900 {}
901};
902
903static int patch_ad1988(struct hda_codec *codec)
904{
905 struct ad198x_spec *spec;
906 int err;
907
908 err = alloc_ad_spec(codec);
909 if (err < 0)
910 return err;
911 spec = codec->spec;
912
913 spec->gen.mixer_nid = 0x20;
914 spec->gen.mixer_merge_nid = 0x21;
915 spec->gen.beep_nid = 0x10;
916 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
917
918 snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
919 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
920
921 err = ad198x_parse_auto_config(codec, true);
922 if (err < 0)
923 goto error;
924 err = ad1988_add_spdif_mux_ctl(codec);
925 if (err < 0)
926 goto error;
927
928 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
929
930 return 0;
931
932 error:
933 snd_hda_gen_free(codec);
934 return err;
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
962
963
964
965
966
967static void ad1884_fixup_amp_override(struct hda_codec *codec,
968 const struct hda_fixup *fix, int action)
969{
970 if (action == HDA_FIXUP_ACT_PRE_PROBE)
971 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
972 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
973 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
974 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
975 (1 << AC_AMPCAP_MUTE_SHIFT));
976}
977
978
979static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
980{
981 struct hda_codec *codec = private_data;
982 struct ad198x_spec *spec = codec->spec;
983
984 if (spec->eapd_nid)
985 ad_vmaster_eapd_hook(private_data, enabled);
986 snd_hda_codec_write_cache(codec, 0x01, 0,
987 AC_VERB_SET_GPIO_DATA,
988 enabled ? 0x00 : 0x02);
989}
990
991static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
992 const struct hda_fixup *fix, int action)
993{
994 struct ad198x_spec *spec = codec->spec;
995
996 switch (action) {
997 case HDA_FIXUP_ACT_PRE_PROBE:
998 spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
999 spec->gen.own_eapd_ctl = 1;
1000 snd_hda_codec_write_cache(codec, 0x01, 0,
1001 AC_VERB_SET_GPIO_MASK, 0x02);
1002 snd_hda_codec_write_cache(codec, 0x01, 0,
1003 AC_VERB_SET_GPIO_DIRECTION, 0x02);
1004 snd_hda_codec_write_cache(codec, 0x01, 0,
1005 AC_VERB_SET_GPIO_DATA, 0x02);
1006 break;
1007 case HDA_FIXUP_ACT_PROBE:
1008 if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
1009 spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
1010 else
1011 spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
1012 break;
1013 }
1014}
1015
1016static void ad1884_fixup_thinkpad(struct hda_codec *codec,
1017 const struct hda_fixup *fix, int action)
1018{
1019 struct ad198x_spec *spec = codec->spec;
1020
1021 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
1022 spec->gen.keep_eapd_on = 1;
1023 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
1024 spec->eapd_nid = 0x12;
1025
1026 spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
1027 spec->gen.beep_nid = 0;
1028 }
1029}
1030
1031
1032static const struct hda_verb ad1884_dmic_init_verbs[] = {
1033 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
1034 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
1035 {}
1036};
1037
1038enum {
1039 AD1884_FIXUP_AMP_OVERRIDE,
1040 AD1884_FIXUP_HP_EAPD,
1041 AD1884_FIXUP_DMIC_COEF,
1042 AD1884_FIXUP_THINKPAD,
1043 AD1884_FIXUP_HP_TOUCHSMART,
1044};
1045
1046static const struct hda_fixup ad1884_fixups[] = {
1047 [AD1884_FIXUP_AMP_OVERRIDE] = {
1048 .type = HDA_FIXUP_FUNC,
1049 .v.func = ad1884_fixup_amp_override,
1050 },
1051 [AD1884_FIXUP_HP_EAPD] = {
1052 .type = HDA_FIXUP_FUNC,
1053 .v.func = ad1884_fixup_hp_eapd,
1054 .chained = true,
1055 .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
1056 },
1057 [AD1884_FIXUP_DMIC_COEF] = {
1058 .type = HDA_FIXUP_VERBS,
1059 .v.verbs = ad1884_dmic_init_verbs,
1060 },
1061 [AD1884_FIXUP_THINKPAD] = {
1062 .type = HDA_FIXUP_FUNC,
1063 .v.func = ad1884_fixup_thinkpad,
1064 .chained = true,
1065 .chain_id = AD1884_FIXUP_DMIC_COEF,
1066 },
1067 [AD1884_FIXUP_HP_TOUCHSMART] = {
1068 .type = HDA_FIXUP_VERBS,
1069 .v.verbs = ad1884_dmic_init_verbs,
1070 .chained = true,
1071 .chain_id = AD1884_FIXUP_HP_EAPD,
1072 },
1073};
1074
1075static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
1076 SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
1077 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
1078 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
1079 {}
1080};
1081
1082
1083static int patch_ad1884(struct hda_codec *codec)
1084{
1085 struct ad198x_spec *spec;
1086 int err;
1087
1088 err = alloc_ad_spec(codec);
1089 if (err < 0)
1090 return err;
1091 spec = codec->spec;
1092
1093 spec->gen.mixer_nid = 0x20;
1094 spec->gen.mixer_merge_nid = 0x21;
1095 spec->gen.beep_nid = 0x10;
1096 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1097
1098 snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
1099 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1100
1101 err = ad198x_parse_auto_config(codec, true);
1102 if (err < 0)
1103 goto error;
1104 err = ad1983_add_spdif_mux_ctl(codec);
1105 if (err < 0)
1106 goto error;
1107
1108 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1109
1110 return 0;
1111
1112 error:
1113 snd_hda_gen_free(codec);
1114 return err;
1115}
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129static int patch_ad1882(struct hda_codec *codec)
1130{
1131 struct ad198x_spec *spec;
1132 int err;
1133
1134 err = alloc_ad_spec(codec);
1135 if (err < 0)
1136 return err;
1137 spec = codec->spec;
1138
1139 spec->gen.mixer_nid = 0x20;
1140 spec->gen.mixer_merge_nid = 0x21;
1141 spec->gen.beep_nid = 0x10;
1142 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1143 err = ad198x_parse_auto_config(codec, true);
1144 if (err < 0)
1145 goto error;
1146 err = ad1988_add_spdif_mux_ctl(codec);
1147 if (err < 0)
1148 goto error;
1149 return 0;
1150
1151 error:
1152 snd_hda_gen_free(codec);
1153 return err;
1154}
1155
1156
1157
1158
1159
1160static const struct hda_device_id snd_hda_id_analog[] = {
1161 HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
1162 HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
1163 HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
1164 HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
1165 HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
1166 HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
1167 HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
1168 HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
1169 HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
1170 HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
1171 HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
1172 HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
1173 HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
1174 HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
1175 HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
1176 {}
1177};
1178MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
1179
1180MODULE_LICENSE("GPL");
1181MODULE_DESCRIPTION("Analog Devices HD-audio codec");
1182
1183static struct hda_codec_driver analog_driver = {
1184 .id = snd_hda_id_analog,
1185};
1186
1187module_hda_codec_driver(analog_driver);
1188