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