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