source: GPL/trunk/alsa-kernel/pci/hda/patch_analog.c

Last change on this file was 777, checked in by David Azarewicz, 7 months ago

Merge from uniaud32-exp branch

File size: 33.5 KB
Line 
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
4 * AD1986A, AD1988
5 *
6 * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
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#ifdef TARGET_OS2
22#define KBUILD_MODNAME "patch_analog"
23#endif
24
25struct ad198x_spec {
26 struct hda_gen_spec gen;
27
28 /* for auto parser */
29 int smux_paths[4];
30 unsigned int cur_smux;
31 hda_nid_t eapd_nid;
32
33 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
34 int num_smux_conns;
35};
36
37
38#ifdef CONFIG_SND_HDA_INPUT_BEEP
39/* additional beep mixers; the actual parameters are overwritten at build */
40static const struct snd_kcontrol_new ad_beep_mixer[] = {
41 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
42 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
43 {0} /* end */
44};
45
46#define set_beep_amp(spec, nid, idx, dir) \
47 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
48#else
49#define set_beep_amp(spec, nid, idx, dir) /* NOP */
50#endif
51
52#ifdef CONFIG_SND_HDA_INPUT_BEEP
53static int create_beep_ctls(struct hda_codec *codec)
54{
55 struct ad198x_spec *spec = codec->spec;
56 const struct snd_kcontrol_new *knew;
57
58 if (!spec->beep_amp)
59 return 0;
60
61 for (knew = ad_beep_mixer ; knew->name; knew++) {
62 int err;
63 struct snd_kcontrol *kctl;
64 kctl = snd_ctl_new1(knew, codec);
65 if (!kctl)
66 return -ENOMEM;
67 kctl->private_value = spec->beep_amp;
68 err = snd_hda_ctl_add(codec, 0, kctl);
69 if (err < 0)
70 return err;
71 }
72 return 0;
73}
74#else
75#define create_beep_ctls(codec) 0
76#endif
77
78static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
79 hda_nid_t hp)
80{
81 if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
82 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
83 !codec->inv_eapd ? 0x00 : 0x02);
84 if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
85 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
86 !codec->inv_eapd ? 0x00 : 0x02);
87}
88
89static void ad198x_power_eapd(struct hda_codec *codec)
90{
91 /* We currently only handle front, HP */
92 switch (codec->core.vendor_id) {
93 case 0x11d41882:
94 case 0x11d4882a:
95 case 0x11d41884:
96 case 0x11d41984:
97 case 0x11d41883:
98 case 0x11d4184a:
99 case 0x11d4194a:
100 case 0x11d4194b:
101 case 0x11d41988:
102 case 0x11d4198b:
103 case 0x11d4989a:
104 case 0x11d4989b:
105 ad198x_power_eapd_write(codec, 0x12, 0x11);
106 break;
107 case 0x11d41981:
108 case 0x11d41983:
109 ad198x_power_eapd_write(codec, 0x05, 0x06);
110 break;
111 case 0x11d41986:
112 ad198x_power_eapd_write(codec, 0x1b, 0x1a);
113 break;
114 }
115}
116
117static int ad198x_suspend(struct hda_codec *codec)
118{
119 snd_hda_shutup_pins(codec);
120 ad198x_power_eapd(codec);
121 return 0;
122}
123
124/* follow EAPD via vmaster hook */
125static void ad_vmaster_eapd_hook(void *private_data, int enabled)
126{
127 struct hda_codec *codec = private_data;
128 struct ad198x_spec *spec = codec->spec;
129
130 if (!spec->eapd_nid)
131 return;
132 if (codec->inv_eapd)
133 enabled = !enabled;
134 snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,
135 AC_VERB_SET_EAPD_BTLENABLE,
136 enabled ? 0x02 : 0x00);
137}
138
139/*
140 * Automatic parse of I/O pins from the BIOS configuration
141 */
142
143static int ad198x_auto_build_controls(struct hda_codec *codec)
144{
145 int err;
146
147 err = snd_hda_gen_build_controls(codec);
148 if (err < 0)
149 return err;
150 err = create_beep_ctls(codec);
151 if (err < 0)
152 return err;
153 return 0;
154}
155
156static const struct hda_codec_ops ad198x_auto_patch_ops = {
157 .build_controls = ad198x_auto_build_controls,
158 .build_pcms = snd_hda_gen_build_pcms,
159 .init = snd_hda_gen_init,
160 .free = snd_hda_gen_free,
161 .unsol_event = snd_hda_jack_unsol_event,
162 .check_power_status = snd_hda_gen_check_power_status,
163 .suspend = ad198x_suspend,
164};
165
166
167static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
168{
169 struct ad198x_spec *spec = codec->spec;
170 struct auto_pin_cfg *cfg = &spec->gen.autocfg;
171 int err;
172
173 codec->spdif_status_reset = 1;
174 codec->no_trigger_sense = 1;
175 codec->no_sticky_stream = 1;
176
177 spec->gen.indep_hp = indep_hp;
178 if (!spec->gen.add_stereo_mix_input)
179 spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
180
181 err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
182 if (err < 0)
183 return err;
184 err = snd_hda_gen_parse_auto_config(codec, cfg);
185 if (err < 0)
186 return err;
187
188 return 0;
189}
190
191/*
192 * AD1986A specific
193 */
194
195static int alloc_ad_spec(struct hda_codec *codec)
196{
197 struct ad198x_spec *spec;
198
199 spec = kzalloc(sizeof(*spec), GFP_KERNEL);
200 if (!spec)
201 return -ENOMEM;
202 codec->spec = spec;
203 snd_hda_gen_spec_init(&spec->gen);
204 codec->patch_ops = ad198x_auto_patch_ops;
205 return 0;
206}
207
208/*
209 * AD1986A fixup codes
210 */
211
212/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
213static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
214 const struct hda_fixup *fix, int action)
215{
216 struct ad198x_spec *spec = codec->spec;
217
218 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
219 codec->inv_jack_detect = 1;
220 spec->gen.keep_eapd_on = 1;
221 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
222 spec->eapd_nid = 0x1b;
223 }
224}
225
226/* Toshiba Satellite L40 implements EAPD in a standard way unlike others */
227static void ad1986a_fixup_eapd(struct hda_codec *codec,
228 const struct hda_fixup *fix, int action)
229{
230 struct ad198x_spec *spec = codec->spec;
231
232 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
233 codec->inv_eapd = 0;
234 spec->gen.keep_eapd_on = 1;
235 spec->eapd_nid = 0x1b;
236 }
237}
238
239/* enable stereo-mix input for avoiding regression on KDE (bko#88251) */
240static void ad1986a_fixup_eapd_mix_in(struct hda_codec *codec,
241 const struct hda_fixup *fix, int action)
242{
243 struct ad198x_spec *spec = codec->spec;
244
245 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
246 ad1986a_fixup_eapd(codec, fix, action);
247 spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_ENABLE;
248 }
249}
250
251enum {
252 AD1986A_FIXUP_INV_JACK_DETECT,
253 AD1986A_FIXUP_ULTRA,
254 AD1986A_FIXUP_SAMSUNG,
255 AD1986A_FIXUP_3STACK,
256 AD1986A_FIXUP_LAPTOP,
257 AD1986A_FIXUP_LAPTOP_IMIC,
258 AD1986A_FIXUP_EAPD,
259 AD1986A_FIXUP_EAPD_MIX_IN,
260 AD1986A_FIXUP_EASYNOTE,
261};
262
263#ifdef TARGET_OS2
264static const struct hda_pintbl AD1986A_FIXUP_ULTRA_PINS[] = {
265 { 0x1b, 0x90170110 }, /* speaker */
266 { 0x1d, 0x90a7013e }, /* int mic */
267 {0}
268 };
269
270static const struct hda_pintbl AD1986A_FIXUP_SAMSUNG_PINS[] = {
271 { 0x1b, 0x90170110 }, /* speaker */
272 { 0x1d, 0x90a7013e }, /* int mic */
273 { 0x20, 0x411111f0 }, /* N/A */
274 { 0x24, 0x411111f0 }, /* N/A */
275 {0}
276 };
277
278static const struct hda_pintbl AD1986A_FIXUP_3STACK_PINS[] = {
279 { 0x1a, 0x02214021 }, /* headphone */
280 { 0x1b, 0x01014011 }, /* front */
281 { 0x1c, 0x01813030 }, /* line-in */
282 { 0x1d, 0x01a19020 }, /* rear mic */
283 { 0x1e, 0x411111f0 }, /* N/A */
284 { 0x1f, 0x02a190f0 }, /* mic */
285 { 0x20, 0x411111f0 }, /* N/A */
286 {0}
287 };
288
289static const struct hda_pintbl AD1986A_FIXUP_LAPTOP_PINS[] = {
290 { 0x1a, 0x02214021 }, /* headphone */
291 { 0x1b, 0x90170110 }, /* speaker */
292 { 0x1c, 0x411111f0 }, /* N/A */
293 { 0x1d, 0x411111f0 }, /* N/A */
294 { 0x1e, 0x411111f0 }, /* N/A */
295 { 0x1f, 0x02a191f0 }, /* mic */
296 { 0x20, 0x411111f0 }, /* N/A */
297 {0}
298 };
299
300static const struct hda_pintbl AD1986A_FIXUP_LAPTOP_IMIC_PINS[] = {
301 { 0x1d, 0x90a7013e }, /* int mic */
302 {0}
303 };
304
305static const struct hda_pintbl AD1986A_FIXUP_EASYNOTE_PINS[] = {
306 { 0x1a, 0x0421402f }, /* headphone */
307 { 0x1b, 0x90170110 }, /* speaker */
308 { 0x1c, 0x411111f0 }, /* N/A */
309 { 0x1d, 0x90a70130 }, /* int mic */
310 { 0x1e, 0x411111f0 }, /* N/A */
311 { 0x1f, 0x04a19040 }, /* mic */
312 { 0x20, 0x411111f0 }, /* N/A */
313 { 0x21, 0x411111f0 }, /* N/A */
314 { 0x22, 0x411111f0 }, /* N/A */
315 { 0x23, 0x411111f0 }, /* N/A */
316 { 0x24, 0x411111f0 }, /* N/A */
317 { 0x25, 0x411111f0 }, /* N/A */
318 {0}
319 };
320#endif
321
322static const struct hda_fixup ad1986a_fixups[] = {
323 [AD1986A_FIXUP_INV_JACK_DETECT] = {
324 .type = HDA_FIXUP_FUNC,
325 .v.func = ad_fixup_inv_jack_detect,
326 },
327 [AD1986A_FIXUP_ULTRA] = {
328 .type = HDA_FIXUP_PINS,
329#ifndef TARGET_OS2
330 .v.pins = (const struct hda_pintbl[]) {
331 { 0x1b, 0x90170110 }, /* speaker */
332 { 0x1d, 0x90a7013e }, /* int mic */
333 {0}
334 },
335#else
336 .v.pins = AD1986A_FIXUP_ULTRA_PINS,
337#endif
338 },
339 [AD1986A_FIXUP_SAMSUNG] = {
340 .type = HDA_FIXUP_PINS,
341#ifndef TARGET_OS2
342 .v.pins = (const struct hda_pintbl[]) {
343 { 0x1b, 0x90170110 }, /* speaker */
344 { 0x1d, 0x90a7013e }, /* int mic */
345 { 0x20, 0x411111f0 }, /* N/A */
346 { 0x24, 0x411111f0 }, /* N/A */
347 {0}
348 },
349#else
350 .v.pins = AD1986A_FIXUP_SAMSUNG_PINS,
351#endif
352 },
353 [AD1986A_FIXUP_3STACK] = {
354 .type = HDA_FIXUP_PINS,
355#ifndef TARGET_OS2
356 .v.pins = (const struct hda_pintbl[]) {
357 { 0x1a, 0x02214021 }, /* headphone */
358 { 0x1b, 0x01014011 }, /* front */
359 { 0x1c, 0x01813030 }, /* line-in */
360 { 0x1d, 0x01a19020 }, /* rear mic */
361 { 0x1e, 0x411111f0 }, /* N/A */
362 { 0x1f, 0x02a190f0 }, /* mic */
363 { 0x20, 0x411111f0 }, /* N/A */
364 {0}
365 },
366#else
367 .v.pins = AD1986A_FIXUP_3STACK_PINS,
368#endif
369 },
370 [AD1986A_FIXUP_LAPTOP] = {
371 .type = HDA_FIXUP_PINS,
372#ifndef TARGET_OS2
373 .v.pins = (const struct hda_pintbl[]) {
374 { 0x1a, 0x02214021 }, /* headphone */
375 { 0x1b, 0x90170110 }, /* speaker */
376 { 0x1c, 0x411111f0 }, /* N/A */
377 { 0x1d, 0x411111f0 }, /* N/A */
378 { 0x1e, 0x411111f0 }, /* N/A */
379 { 0x1f, 0x02a191f0 }, /* mic */
380 { 0x20, 0x411111f0 }, /* N/A */
381 {0}
382 },
383#else
384 .v.pins = AD1986A_FIXUP_LAPTOP_PINS,
385#endif
386 },
387 [AD1986A_FIXUP_LAPTOP_IMIC] = {
388 .type = HDA_FIXUP_PINS,
389#ifndef TARGET_OS2
390 .v.pins = (const struct hda_pintbl[]) {
391 { 0x1d, 0x90a7013e }, /* int mic */
392 {0}
393 },
394#else
395 .v.pins = AD1986A_FIXUP_LAPTOP_IMIC_PINS,
396#endif
397 .chained_before = 1,
398 .chain_id = AD1986A_FIXUP_LAPTOP,
399 },
400 [AD1986A_FIXUP_EAPD] = {
401 .type = HDA_FIXUP_FUNC,
402 .v.func = ad1986a_fixup_eapd,
403 },
404 [AD1986A_FIXUP_EAPD_MIX_IN] = {
405 .type = HDA_FIXUP_FUNC,
406 .v.func = ad1986a_fixup_eapd_mix_in,
407 },
408 [AD1986A_FIXUP_EASYNOTE] = {
409 .type = HDA_FIXUP_PINS,
410#ifndef TARGET_OS2
411 .v.pins = (const struct hda_pintbl[]) {
412 { 0x1a, 0x0421402f }, /* headphone */
413 { 0x1b, 0x90170110 }, /* speaker */
414 { 0x1c, 0x411111f0 }, /* N/A */
415 { 0x1d, 0x90a70130 }, /* int mic */
416 { 0x1e, 0x411111f0 }, /* N/A */
417 { 0x1f, 0x04a19040 }, /* mic */
418 { 0x20, 0x411111f0 }, /* N/A */
419 { 0x21, 0x411111f0 }, /* N/A */
420 { 0x22, 0x411111f0 }, /* N/A */
421 { 0x23, 0x411111f0 }, /* N/A */
422 { 0x24, 0x411111f0 }, /* N/A */
423 { 0x25, 0x411111f0 }, /* N/A */
424 {0}
425 },
426#else
427 .v.pins = AD1986A_FIXUP_EASYNOTE_PINS,
428#endif
429 .chained = true,
430 .chain_id = AD1986A_FIXUP_EAPD_MIX_IN,
431 },
432};
433
434static const struct hda_quirk ad1986a_fixup_tbl[] = {
435 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
436 SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC),
437 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
438 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
439 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
440 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
441 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
442 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),
443 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
444 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
445 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
446 SND_PCI_QUIRK(0x1631, 0xc022, "PackardBell EasyNote MX65", AD1986A_FIXUP_EASYNOTE),
447 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
448 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
449 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
450 {0}
451};
452
453static const struct hda_model_fixup ad1986a_fixup_models[] = {
454 { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
455 { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
456 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
457 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
458 { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
459 {0}
460};
461
462/*
463 */
464static int patch_ad1986a(struct hda_codec *codec)
465{
466 int err;
467 struct ad198x_spec *spec;
468 static const hda_nid_t preferred_pairs[] = {
469 0x1a, 0x03,
470 0x1b, 0x03,
471 0x1c, 0x04,
472 0x1d, 0x05,
473 0x1e, 0x03,
474 0
475 };
476
477 err = alloc_ad_spec(codec);
478 if (err < 0)
479 return err;
480 spec = codec->spec;
481
482 /* AD1986A has the inverted EAPD implementation */
483 codec->inv_eapd = 1;
484
485 spec->gen.mixer_nid = 0x07;
486 spec->gen.beep_nid = 0x19;
487 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
488
489 /* AD1986A has a hardware problem that it can't share a stream
490 * with multiple output pins. The copy of front to surrounds
491 * causes noisy or silent outputs at a certain timing, e.g.
492 * changing the volume.
493 * So, let's disable the shared stream.
494 */
495 spec->gen.multiout.no_share_stream = 1;
496 /* give fixed DAC/pin pairs */
497 spec->gen.preferred_dacs = preferred_pairs;
498
499 /* AD1986A can't manage the dynamic pin on/off smoothly */
500 spec->gen.auto_mute_via_amp = 1;
501
502 snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
503 ad1986a_fixups);
504 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
505
506 err = ad198x_parse_auto_config(codec, false);
507 if (err < 0) {
508 snd_hda_gen_free(codec);
509 return err;
510 }
511
512 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
513
514 return 0;
515}
516
517
518/*
519 * AD1983 specific
520 */
521
522/*
523 * SPDIF mux control for AD1983 auto-parser
524 */
525static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
526 struct snd_ctl_elem_info *uinfo)
527{
528 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
529 struct ad198x_spec *spec = codec->spec;
530 static const char * const texts2[] = { "PCM", "ADC" };
531 static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
532 int num_conns = spec->num_smux_conns;
533
534 if (num_conns == 2)
535 return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
536 else if (num_conns == 3)
537 return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
538 else
539 return -EINVAL;
540}
541
542static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
543 struct snd_ctl_elem_value *ucontrol)
544{
545 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
546 struct ad198x_spec *spec = codec->spec;
547
548 ucontrol->value.enumerated.item[0] = spec->cur_smux;
549 return 0;
550}
551
552static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
553 struct snd_ctl_elem_value *ucontrol)
554{
555 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
556 struct ad198x_spec *spec = codec->spec;
557 unsigned int val = ucontrol->value.enumerated.item[0];
558 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
559 int num_conns = spec->num_smux_conns;
560
561 if (val >= num_conns)
562 return -EINVAL;
563 if (spec->cur_smux == val)
564 return 0;
565 spec->cur_smux = val;
566 snd_hda_codec_write_cache(codec, dig_out, 0,
567 AC_VERB_SET_CONNECT_SEL, val);
568 return 1;
569}
570
571static const struct snd_kcontrol_new ad1983_auto_smux_mixer = {
572 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
573 .name = "IEC958 Playback Source",
574 .info = ad1983_auto_smux_enum_info,
575 .get = ad1983_auto_smux_enum_get,
576 .put = ad1983_auto_smux_enum_put,
577};
578
579static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
580{
581 struct ad198x_spec *spec = codec->spec;
582 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
583 int num_conns;
584
585 if (!dig_out)
586 return 0;
587 num_conns = snd_hda_get_num_conns(codec, dig_out);
588 if (num_conns != 2 && num_conns != 3)
589 return 0;
590 spec->num_smux_conns = num_conns;
591 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
592 return -ENOMEM;
593 return 0;
594}
595
596static int patch_ad1983(struct hda_codec *codec)
597{
598 static const hda_nid_t conn_0c[] = { 0x08 };
599 static const hda_nid_t conn_0d[] = { 0x09 };
600 struct ad198x_spec *spec;
601 int err;
602
603 err = alloc_ad_spec(codec);
604 if (err < 0)
605 return err;
606 spec = codec->spec;
607
608 spec->gen.mixer_nid = 0x0e;
609 spec->gen.beep_nid = 0x10;
610 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
611
612 /* limit the loopback routes not to confuse the parser */
613 snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);
614 snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);
615
616 err = ad198x_parse_auto_config(codec, false);
617 if (err < 0)
618 goto error;
619 err = ad1983_add_spdif_mux_ctl(codec);
620 if (err < 0)
621 goto error;
622 return 0;
623
624 error:
625 snd_hda_gen_free(codec);
626 return err;
627}
628
629
630/*
631 * AD1981 HD specific
632 */
633
634static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
635 const struct hda_fixup *fix, int action)
636{
637 struct ad198x_spec *spec = codec->spec;
638
639 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
640 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
641 spec->eapd_nid = 0x05;
642 }
643}
644
645/* set the upper-limit for mixer amp to 0dB for avoiding the possible
646 * damage by overloading
647 */
648static void ad1981_fixup_amp_override(struct hda_codec *codec,
649 const struct hda_fixup *fix, int action)
650{
651 if (action == HDA_FIXUP_ACT_PRE_PROBE)
652 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
653 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
654 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
655 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
656 (1 << AC_AMPCAP_MUTE_SHIFT));
657}
658
659enum {
660 AD1981_FIXUP_AMP_OVERRIDE,
661 AD1981_FIXUP_HP_EAPD,
662};
663
664static const struct hda_fixup ad1981_fixups[] = {
665 [AD1981_FIXUP_AMP_OVERRIDE] = {
666 .type = HDA_FIXUP_FUNC,
667 .v.func = ad1981_fixup_amp_override,
668 },
669 [AD1981_FIXUP_HP_EAPD] = {
670 .type = HDA_FIXUP_FUNC,
671 .v.func = ad1981_fixup_hp_eapd,
672 .chained = true,
673 .chain_id = AD1981_FIXUP_AMP_OVERRIDE,
674 },
675};
676
677static const struct hda_quirk ad1981_fixup_tbl[] = {
678 SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
679 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
680 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
681 /* HP nx6320 (reversed SSID, H/W bug) */
682 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
683 {0}
684};
685
686static int patch_ad1981(struct hda_codec *codec)
687{
688 struct ad198x_spec *spec;
689 int err;
690
691 err = alloc_ad_spec(codec);
692 if (err < 0)
693 return -ENOMEM;
694 spec = codec->spec;
695
696 spec->gen.mixer_nid = 0x0e;
697 spec->gen.beep_nid = 0x10;
698 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
699
700 snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
701 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
702
703 err = ad198x_parse_auto_config(codec, false);
704 if (err < 0)
705 goto error;
706 err = ad1983_add_spdif_mux_ctl(codec);
707 if (err < 0)
708 goto error;
709
710 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
711
712 return 0;
713
714 error:
715 snd_hda_gen_free(codec);
716 return err;
717}
718
719
720/*
721 * AD1988
722 *
723 * Output pins and routes
724 *
725 * Pin Mix Sel DAC (*)
726 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
727 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
728 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
729 * port-D 0x12 (mute/hp) <- 0x29 <- 04
730 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
731 * port-F 0x16 (mute) <- 0x2a <- 06
732 * port-G 0x24 (mute) <- 0x27 <- 05
733 * port-H 0x25 (mute) <- 0x28 <- 0a
734 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
735 *
736 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
737 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
738 *
739 * Input pins and routes
740 *
741 * pin boost mix input # / adc input #
742 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
743 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
744 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
745 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
746 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
747 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
748 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
749 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
750 *
751 *
752 * DAC assignment
753 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
754 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
755 *
756 * Inputs of Analog Mix (0x20)
757 * 0:Port-B (front mic)
758 * 1:Port-C/G/H (line-in)
759 * 2:Port-A
760 * 3:Port-D (line-in/2)
761 * 4:Port-E/G/H (mic-in)
762 * 5:Port-F (mic2-in)
763 * 6:CD
764 * 7:Beep
765 *
766 * ADC selection
767 * 0:Port-A
768 * 1:Port-B (front mic-in)
769 * 2:Port-C (line-in)
770 * 3:Port-F (mic2-in)
771 * 4:Port-E (mic-in)
772 * 5:CD
773 * 6:Port-G
774 * 7:Port-H
775 * 8:Port-D (line-in/2)
776 * 9:Mix
777 *
778 * Proposed pin assignments by the datasheet
779 *
780 * 6-stack
781 * Port-A front headphone
782 * B front mic-in
783 * C rear line-in
784 * D rear front-out
785 * E rear mic-in
786 * F rear surround
787 * G rear CLFE
788 * H rear side
789 *
790 * 3-stack
791 * Port-A front headphone
792 * B front mic
793 * C rear line-in/surround
794 * D rear front-out
795 * E rear mic-in/CLFE
796 *
797 * laptop
798 * Port-A headphone
799 * B mic-in
800 * C docking station
801 * D internal speaker (with EAPD)
802 * E/F quad mic array
803 */
804
805static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
806 struct snd_ctl_elem_info *uinfo)
807{
808 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
809 struct ad198x_spec *spec = codec->spec;
810 static const char * const texts[] = {
811 "PCM", "ADC1", "ADC2", "ADC3",
812 };
813 int num_conns = spec->num_smux_conns;
814
815 if (num_conns > 4)
816 num_conns = 4;
817 return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
818}
819
820static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
821 struct snd_ctl_elem_value *ucontrol)
822{
823 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
824 struct ad198x_spec *spec = codec->spec;
825
826 ucontrol->value.enumerated.item[0] = spec->cur_smux;
827 return 0;
828}
829
830static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
831 struct snd_ctl_elem_value *ucontrol)
832{
833 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
834 struct ad198x_spec *spec = codec->spec;
835 unsigned int val = ucontrol->value.enumerated.item[0];
836 struct nid_path *path;
837 int num_conns = spec->num_smux_conns;
838
839 if (val >= num_conns)
840 return -EINVAL;
841 if (spec->cur_smux == val)
842 return 0;
843
844 mutex_lock(&codec->control_mutex);
845 path = snd_hda_get_path_from_idx(codec,
846 spec->smux_paths[spec->cur_smux]);
847 if (path)
848 snd_hda_activate_path(codec, path, false, true);
849 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
850 if (path)
851 snd_hda_activate_path(codec, path, true, true);
852 spec->cur_smux = val;
853 mutex_unlock(&codec->control_mutex);
854 return 1;
855}
856
857static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
858 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
859 .name = "IEC958 Playback Source",
860 .info = ad1988_auto_smux_enum_info,
861 .get = ad1988_auto_smux_enum_get,
862 .put = ad1988_auto_smux_enum_put,
863};
864
865static int ad1988_auto_init(struct hda_codec *codec)
866{
867 struct ad198x_spec *spec = codec->spec;
868 int i, err;
869
870 err = snd_hda_gen_init(codec);
871 if (err < 0)
872 return err;
873 if (!spec->gen.autocfg.dig_outs)
874 return 0;
875
876 for (i = 0; i < 4; i++) {
877 struct nid_path *path;
878 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
879 if (path)
880 snd_hda_activate_path(codec, path, path->active, false);
881 }
882
883 return 0;
884}
885
886static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
887{
888 struct ad198x_spec *spec = codec->spec;
889 int i, num_conns;
890 /* we create four static faked paths, since AD codecs have odd
891 * widget connections regarding the SPDIF out source
892 */
893 static const struct nid_path fake_paths[4] = {
894 {
895 .depth = 3,
896 .path = { 0x02, 0x1d, 0x1b },
897 .idx = { 0, 0, 0 },
898 .multi = { 0, 0, 0 },
899 },
900 {
901 .depth = 4,
902 .path = { 0x08, 0x0b, 0x1d, 0x1b },
903 .idx = { 0, 0, 1, 0 },
904 .multi = { 0, 1, 0, 0 },
905 },
906 {
907 .depth = 4,
908 .path = { 0x09, 0x0b, 0x1d, 0x1b },
909 .idx = { 0, 1, 1, 0 },
910 .multi = { 0, 1, 0, 0 },
911 },
912 {
913 .depth = 4,
914 .path = { 0x0f, 0x0b, 0x1d, 0x1b },
915 .idx = { 0, 2, 1, 0 },
916 .multi = { 0, 1, 0, 0 },
917 },
918 };
919
920 /* SPDIF source mux appears to be present only on AD1988A */
921 if (!spec->gen.autocfg.dig_outs ||
922 get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
923 return 0;
924
925 num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
926 if (num_conns != 3 && num_conns != 4)
927 return 0;
928 spec->num_smux_conns = num_conns;
929
930 for (i = 0; i < num_conns; i++) {
931 struct nid_path *path = snd_array_new(&spec->gen.paths);
932 if (!path)
933 return -ENOMEM;
934 *path = fake_paths[i];
935 if (!i)
936 path->active = 1;
937 spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
938 }
939
940 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
941 return -ENOMEM;
942
943 codec->patch_ops.init = ad1988_auto_init;
944
945 return 0;
946}
947
948/*
949 */
950
951enum {
952 AD1988_FIXUP_6STACK_DIG,
953};
954
955#ifdef TARGET_OS2
956static const struct hda_pintbl AD1988_FIXUP_6STACK_DIG_pins[] = {
957 { 0x11, 0x02214130 }, /* front-hp */
958 { 0x12, 0x01014010 }, /* line-out */
959 { 0x14, 0x02a19122 }, /* front-mic */
960 { 0x15, 0x01813021 }, /* line-in */
961 { 0x16, 0x01011012 }, /* line-out */
962 { 0x17, 0x01a19020 }, /* mic */
963 { 0x1b, 0x0145f1f0 }, /* SPDIF */
964 { 0x24, 0x01016011 }, /* line-out */
965 { 0x25, 0x01012013 }, /* line-out */
966 {0}
967 };
968
969#endif
970
971static const struct hda_fixup ad1988_fixups[] = {
972 [AD1988_FIXUP_6STACK_DIG] = {
973 .type = HDA_FIXUP_PINS,
974#ifndef TARGET_OS2
975 .v.pins = (const struct hda_pintbl[]) {
976 { 0x11, 0x02214130 }, /* front-hp */
977 { 0x12, 0x01014010 }, /* line-out */
978 { 0x14, 0x02a19122 }, /* front-mic */
979 { 0x15, 0x01813021 }, /* line-in */
980 { 0x16, 0x01011012 }, /* line-out */
981 { 0x17, 0x01a19020 }, /* mic */
982 { 0x1b, 0x0145f1f0 }, /* SPDIF */
983 { 0x24, 0x01016011 }, /* line-out */
984 { 0x25, 0x01012013 }, /* line-out */
985 {0}
986 }
987#else
988 .v.pins = AD1988_FIXUP_6STACK_DIG_pins,
989#endif
990 },
991};
992
993static const struct hda_model_fixup ad1988_fixup_models[] = {
994 { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
995 {0}
996};
997
998static int patch_ad1988(struct hda_codec *codec)
999{
1000 struct ad198x_spec *spec;
1001 int err;
1002
1003 err = alloc_ad_spec(codec);
1004 if (err < 0)
1005 return err;
1006 spec = codec->spec;
1007
1008 spec->gen.mixer_nid = 0x20;
1009 spec->gen.mixer_merge_nid = 0x21;
1010 spec->gen.beep_nid = 0x10;
1011 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1012
1013 snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
1014 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1015
1016 err = ad198x_parse_auto_config(codec, true);
1017 if (err < 0)
1018 goto error;
1019 err = ad1988_add_spdif_mux_ctl(codec);
1020 if (err < 0)
1021 goto error;
1022
1023 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1024
1025 return 0;
1026
1027 error:
1028 snd_hda_gen_free(codec);
1029 return err;
1030}
1031
1032
1033/*
1034 * AD1884 / AD1984
1035 *
1036 * port-B - front line/mic-in
1037 * port-E - aux in/out
1038 * port-F - aux in/out
1039 * port-C - rear line/mic-in
1040 * port-D - rear line/hp-out
1041 * port-A - front line/hp-out
1042 *
1043 * AD1984 = AD1884 + two digital mic-ins
1044 *
1045 * AD1883 / AD1884A / AD1984A / AD1984B
1046 *
1047 * port-B (0x14) - front mic-in
1048 * port-E (0x1c) - rear mic-in
1049 * port-F (0x16) - CD / ext out
1050 * port-C (0x15) - rear line-in
1051 * port-D (0x12) - rear line-out
1052 * port-A (0x11) - front hp-out
1053 *
1054 * AD1984A = AD1884A + digital-mic
1055 * AD1883 = equivalent with AD1984A
1056 * AD1984B = AD1984A + extra SPDIF-out
1057 */
1058
1059/* set the upper-limit for mixer amp to 0dB for avoiding the possible
1060 * damage by overloading
1061 */
1062static void ad1884_fixup_amp_override(struct hda_codec *codec,
1063 const struct hda_fixup *fix, int action)
1064{
1065 if (action == HDA_FIXUP_ACT_PRE_PROBE)
1066 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
1067 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
1068 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
1069 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
1070 (1 << AC_AMPCAP_MUTE_SHIFT));
1071}
1072
1073/* toggle GPIO1 according to the mute state */
1074static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
1075{
1076 struct hda_codec *codec = private_data;
1077 struct ad198x_spec *spec = codec->spec;
1078
1079 if (spec->eapd_nid)
1080 ad_vmaster_eapd_hook(private_data, enabled);
1081 snd_hda_codec_write_cache(codec, 0x01, 0,
1082 AC_VERB_SET_GPIO_DATA,
1083 enabled ? 0x00 : 0x02);
1084}
1085
1086static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
1087 const struct hda_fixup *fix, int action)
1088{
1089 struct ad198x_spec *spec = codec->spec;
1090
1091 switch (action) {
1092 case HDA_FIXUP_ACT_PRE_PROBE:
1093 spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
1094 spec->gen.own_eapd_ctl = 1;
1095 snd_hda_codec_write_cache(codec, 0x01, 0,
1096 AC_VERB_SET_GPIO_MASK, 0x02);
1097 snd_hda_codec_write_cache(codec, 0x01, 0,
1098 AC_VERB_SET_GPIO_DIRECTION, 0x02);
1099 snd_hda_codec_write_cache(codec, 0x01, 0,
1100 AC_VERB_SET_GPIO_DATA, 0x02);
1101 break;
1102 case HDA_FIXUP_ACT_PROBE:
1103 if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
1104 spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
1105 else
1106 spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
1107 break;
1108 }
1109}
1110
1111static void ad1884_fixup_thinkpad(struct hda_codec *codec,
1112 const struct hda_fixup *fix, int action)
1113{
1114 struct ad198x_spec *spec = codec->spec;
1115
1116 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
1117 spec->gen.keep_eapd_on = 1;
1118 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
1119 spec->eapd_nid = 0x12;
1120 /* Analog PC Beeper - allow firmware/ACPI beeps */
1121 spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
1122 spec->gen.beep_nid = 0; /* no digital beep */
1123 }
1124}
1125
1126/* set magic COEFs for dmic */
1127static const struct hda_verb ad1884_dmic_init_verbs[] = {
1128 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
1129 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
1130 {0}
1131};
1132
1133enum {
1134 AD1884_FIXUP_AMP_OVERRIDE,
1135 AD1884_FIXUP_HP_EAPD,
1136 AD1884_FIXUP_DMIC_COEF,
1137 AD1884_FIXUP_THINKPAD,
1138 AD1884_FIXUP_HP_TOUCHSMART,
1139};
1140
1141static const struct hda_fixup ad1884_fixups[] = {
1142 [AD1884_FIXUP_AMP_OVERRIDE] = {
1143 .type = HDA_FIXUP_FUNC,
1144 .v.func = ad1884_fixup_amp_override,
1145 },
1146 [AD1884_FIXUP_HP_EAPD] = {
1147 .type = HDA_FIXUP_FUNC,
1148 .v.func = ad1884_fixup_hp_eapd,
1149 .chained = true,
1150 .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
1151 },
1152 [AD1884_FIXUP_DMIC_COEF] = {
1153 .type = HDA_FIXUP_VERBS,
1154 .v.verbs = ad1884_dmic_init_verbs,
1155 },
1156 [AD1884_FIXUP_THINKPAD] = {
1157 .type = HDA_FIXUP_FUNC,
1158 .v.func = ad1884_fixup_thinkpad,
1159 .chained = true,
1160 .chain_id = AD1884_FIXUP_DMIC_COEF,
1161 },
1162 [AD1884_FIXUP_HP_TOUCHSMART] = {
1163 .type = HDA_FIXUP_VERBS,
1164 .v.verbs = ad1884_dmic_init_verbs,
1165 .chained = true,
1166 .chain_id = AD1884_FIXUP_HP_EAPD,
1167 },
1168};
1169
1170static const struct hda_quirk ad1884_fixup_tbl[] = {
1171 SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
1172 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
1173 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
1174 {0}
1175};
1176
1177
1178static int patch_ad1884(struct hda_codec *codec)
1179{
1180 struct ad198x_spec *spec;
1181 int err;
1182
1183 err = alloc_ad_spec(codec);
1184 if (err < 0)
1185 return err;
1186 spec = codec->spec;
1187
1188 spec->gen.mixer_nid = 0x20;
1189 spec->gen.mixer_merge_nid = 0x21;
1190 spec->gen.beep_nid = 0x10;
1191 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1192
1193 snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
1194 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1195
1196 err = ad198x_parse_auto_config(codec, true);
1197 if (err < 0)
1198 goto error;
1199 err = ad1983_add_spdif_mux_ctl(codec);
1200 if (err < 0)
1201 goto error;
1202
1203 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1204
1205 return 0;
1206
1207 error:
1208 snd_hda_gen_free(codec);
1209 return err;
1210}
1211
1212/*
1213 * AD1882 / AD1882A
1214 *
1215 * port-A - front hp-out
1216 * port-B - front mic-in
1217 * port-C - rear line-in, shared surr-out (3stack)
1218 * port-D - rear line-out
1219 * port-E - rear mic-in, shared clfe-out (3stack)
1220 * port-F - rear surr-out (6stack)
1221 * port-G - rear clfe-out (6stack)
1222 */
1223
1224static int patch_ad1882(struct hda_codec *codec)
1225{
1226 struct ad198x_spec *spec;
1227 int err;
1228
1229 err = alloc_ad_spec(codec);
1230 if (err < 0)
1231 return err;
1232 spec = codec->spec;
1233
1234 spec->gen.mixer_nid = 0x20;
1235 spec->gen.mixer_merge_nid = 0x21;
1236 spec->gen.beep_nid = 0x10;
1237 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
1238 err = ad198x_parse_auto_config(codec, true);
1239 if (err < 0)
1240 goto error;
1241 err = ad1988_add_spdif_mux_ctl(codec);
1242 if (err < 0)
1243 goto error;
1244 return 0;
1245
1246 error:
1247 snd_hda_gen_free(codec);
1248 return err;
1249}
1250
1251
1252/*
1253 * patch entries
1254 */
1255static const struct hda_device_id snd_hda_id_analog[] = {
1256 HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
1257 HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
1258 HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
1259 HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
1260 HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
1261 HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
1262 HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
1263 HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
1264 HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
1265 HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
1266 HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
1267 HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
1268 HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
1269 HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
1270 HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
1271 {0} /* terminator */
1272};
1273MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
1274
1275MODULE_LICENSE("GPL");
1276MODULE_DESCRIPTION("Analog Devices HD-audio codec");
1277
1278static struct hda_codec_driver analog_driver = {
1279 .id = snd_hda_id_analog,
1280};
1281
1282module_hda_codec_driver(analog_driver);
Note: See TracBrowser for help on using the repository browser.