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