blob: e283966bdbb199d8e88d1f9923cbec8f16ef8c37 [file] [log] [blame]
Thomas Gleixnerd0fa1172019-05-20 19:07:57 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Takashi Iwai0ac85512007-06-20 15:46:13 +02003 * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
4 * AD1986A, AD1988
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 *
Takashi Iwai2bac6472007-05-18 18:21:41 +02006 * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/slab.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040011#include <linux/module.h>
Ingo Molnar62932df2006-01-16 16:34:20 +010012
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <sound/core.h>
Pierre-Louis Bossartbe57bff2018-08-22 15:24:57 -050014#include <sound/hda_codec.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include "hda_local.h"
Takashi Iwai128bc4b2012-05-07 17:42:31 +020016#include "hda_auto_parser.h"
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010017#include "hda_beep.h"
Takashi Iwai1835a0f2011-10-27 22:12:46 +020018#include "hda_jack.h"
Takashi Iwai78bb3cb2012-12-21 15:17:06 +010019#include "hda_generic.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020
Takashi Iwai9ff4bc82013-01-22 16:45:58 +010021
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020022struct ad198x_spec {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +010023 struct hda_gen_spec gen;
24
Takashi Iwai272f3ea2013-01-22 15:31:33 +010025 /* for auto parser */
26 int smux_paths[4];
27 unsigned int cur_smux;
Takashi Iwaia928bd22013-01-22 18:18:42 +010028 hda_nid_t eapd_nid;
Takashi Iwai272f3ea2013-01-22 15:31:33 +010029
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010030 unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */
Linus Torvalds1da177e2005-04-16 15:20:36 -070031};
32
Takashi Iwai2134ea42008-01-10 16:53:55 +010033
Takashi Iwai67d634c2009-11-16 15:35:59 +010034#ifdef CONFIG_SND_HDA_INPUT_BEEP
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010035/* additional beep mixers; the actual parameters are overwritten at build */
Takashi Iwai498f5b12011-05-02 11:33:15 +020036static const struct snd_kcontrol_new ad_beep_mixer[] = {
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010037 HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
Jaroslav Kysela123c07a2009-10-21 14:48:23 +020038 HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010039 { } /* end */
40};
41
42#define set_beep_amp(spec, nid, idx, dir) \
43 ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
Takashi Iwai67d634c2009-11-16 15:35:59 +010044#else
45#define set_beep_amp(spec, nid, idx, dir) /* NOP */
46#endif
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +010047
Takashi Iwai78bb3cb2012-12-21 15:17:06 +010048#ifdef CONFIG_SND_HDA_INPUT_BEEP
49static 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
Takashi Iwai632408a2013-07-05 14:14:14 +020057 for (knew = ad_beep_mixer ; knew->name; knew++) {
Takashi Iwai78bb3cb2012-12-21 15:17:06 +010058 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
Takashi Iwai4a3fdf32005-04-14 13:35:51 +020074
Daniel T Chenea52bf22009-12-27 18:48:29 -050075static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
76 hda_nid_t hp)
77{
Raymond Yaua01ef052011-06-01 15:09:48 +080078 if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
79 snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
Takashi Iwai78bb3cb2012-12-21 15:17:06 +010080 !codec->inv_eapd ? 0x00 : 0x02);
Raymond Yaua01ef052011-06-01 15:09:48 +080081 if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
82 snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
Takashi Iwai78bb3cb2012-12-21 15:17:06 +010083 !codec->inv_eapd ? 0x00 : 0x02);
Daniel T Chenea52bf22009-12-27 18:48:29 -050084}
85
86static void ad198x_power_eapd(struct hda_codec *codec)
87{
88 /* We currently only handle front, HP */
Takashi Iwai7639a062015-03-03 10:07:24 +010089 switch (codec->core.vendor_id) {
Daniel T Chenea52bf22009-12-27 18:48:29 -050090 case 0x11d41882:
91 case 0x11d4882a:
92 case 0x11d41884:
93 case 0x11d41984:
94 case 0x11d41883:
95 case 0x11d4184a:
96 case 0x11d4194a:
97 case 0x11d4194b:
Takashi Iwai4dffbe02011-06-03 10:05:02 +020098 case 0x11d41988:
99 case 0x11d4198b:
100 case 0x11d4989a:
101 case 0x11d4989b:
Daniel T Chenea52bf22009-12-27 18:48:29 -0500102 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;
Daniel T Chenea52bf22009-12-27 18:48:29 -0500111 }
112}
113
Takashi Iwai0da26922011-04-26 15:18:33 +0200114static void ad198x_shutup(struct hda_codec *codec)
115{
116 snd_hda_shutup_pins(codec);
117 ad198x_power_eapd(codec);
118}
119
Takashi Iwai2a439522011-07-26 09:52:50 +0200120#ifdef CONFIG_PM
Takashi Iwai68cb2b52012-07-02 15:20:37 +0200121static int ad198x_suspend(struct hda_codec *codec)
Daniel T Chenea52bf22009-12-27 18:48:29 -0500122{
123 ad198x_shutup(codec);
Daniel T Chenea52bf22009-12-27 18:48:29 -0500124 return 0;
125}
Daniel T Chenea52bf22009-12-27 18:48:29 -0500126#endif
127
Takashi Iwaif710a9f2013-11-13 09:42:56 +0100128/* follow EAPD via vmaster hook */
129static 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;
Takashi Iwaice8e0fd2013-12-02 15:01:35 +0100136 if (codec->inv_eapd)
137 enabled = !enabled;
Takashi Iwai401caff2018-06-27 11:43:09 +0200138 snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,
Takashi Iwaif710a9f2013-11-13 09:42:56 +0100139 AC_VERB_SET_EAPD_BTLENABLE,
140 enabled ? 0x02 : 0x00);
141}
Takashi Iwai9230d212006-03-13 13:49:49 +0100142
Takashi Iwai18a815d2006-03-01 19:54:39 +0100143/*
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100144 * Automatic parse of I/O pins from the BIOS configuration
145 */
146
147static 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
160static 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,
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100164 .free = snd_hda_gen_free,
Takashi Iwai8a6c21a2013-01-18 07:51:17 +0100165 .unsol_event = snd_hda_jack_unsol_event,
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100166#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
Takashi Iwaicbd209f2014-01-13 12:40:07 +0100174static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100175{
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
Takashi Iwaicbd209f2014-01-13 12:40:07 +0100184 spec->gen.indep_hp = indep_hp;
Takashi Iwai74f14b32014-12-15 13:43:59 +0100185 if (!spec->gen.add_stereo_mix_input)
186 spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100187
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
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100195 return 0;
196}
197
198/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200199 * AD1986A specific
200 */
201
Takashi Iwai361dab32012-05-09 14:35:27 +0200202static 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;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100210 snd_hda_gen_spec_init(&spec->gen);
Takashi Iwai225068a2015-05-29 10:42:14 +0200211 codec->patch_ops = ad198x_auto_patch_ops;
Takashi Iwai361dab32012-05-09 14:35:27 +0200212 return 0;
213}
214
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100215/*
Takashi Iwaia928bd22013-01-22 18:18:42 +0100216 * AD1986A fixup codes
217 */
218
219/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
220static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
221 const struct hda_fixup *fix, int action)
222{
Takashi Iwai7a3e6102013-11-13 09:39:08 +0100223 struct ad198x_spec *spec = codec->spec;
224
225 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
Takashi Iwaia928bd22013-01-22 18:18:42 +0100226 codec->inv_jack_detect = 1;
Takashi Iwai7a3e6102013-11-13 09:39:08 +0100227 spec->gen.keep_eapd_on = 1;
Takashi Iwaif710a9f2013-11-13 09:42:56 +0100228 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
229 spec->eapd_nid = 0x1b;
Takashi Iwai7a3e6102013-11-13 09:39:08 +0100230 }
Takashi Iwaia928bd22013-01-22 18:18:42 +0100231}
232
Takashi Iwai4528eb12014-02-04 07:39:06 +0100233/* Toshiba Satellite L40 implements EAPD in a standard way unlike others */
234static 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
Takashi Iwai73276432014-12-15 13:47:25 +0100246/* enable stereo-mix input for avoiding regression on KDE (bko#88251) */
247static 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
Takashi Iwaia928bd22013-01-22 18:18:42 +0100258enum {
259 AD1986A_FIXUP_INV_JACK_DETECT,
Takashi Iwaie0b27162013-07-04 16:50:46 +0200260 AD1986A_FIXUP_ULTRA,
Takashi Iwaif8c0ab12013-07-04 17:06:04 +0200261 AD1986A_FIXUP_SAMSUNG,
Takashi Iwai632408a2013-07-05 14:14:14 +0200262 AD1986A_FIXUP_3STACK,
263 AD1986A_FIXUP_LAPTOP,
264 AD1986A_FIXUP_LAPTOP_IMIC,
Takashi Iwai4528eb12014-02-04 07:39:06 +0100265 AD1986A_FIXUP_EAPD,
Takashi Iwai73276432014-12-15 13:47:25 +0100266 AD1986A_FIXUP_EAPD_MIX_IN,
267 AD1986A_FIXUP_EASYNOTE,
Takashi Iwaia928bd22013-01-22 18:18:42 +0100268};
269
270static 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 },
Takashi Iwaie0b27162013-07-04 16:50:46 +0200275 [AD1986A_FIXUP_ULTRA] = {
276 .type = HDA_FIXUP_PINS,
277 .v.pins = (const struct hda_pintbl[]) {
278 { 0x1b, 0x90170110 }, /* speaker */
279 { 0x1d, 0x90a7013e }, /* int mic */
280 {}
281 },
282 },
Takashi Iwaif8c0ab12013-07-04 17:06:04 +0200283 [AD1986A_FIXUP_SAMSUNG] = {
284 .type = HDA_FIXUP_PINS,
285 .v.pins = (const struct hda_pintbl[]) {
286 { 0x1b, 0x90170110 }, /* speaker */
287 { 0x1d, 0x90a7013e }, /* int mic */
288 { 0x20, 0x411111f0 }, /* N/A */
289 { 0x24, 0x411111f0 }, /* N/A */
290 {}
291 },
292 },
Takashi Iwai632408a2013-07-05 14:14:14 +0200293 [AD1986A_FIXUP_3STACK] = {
294 .type = HDA_FIXUP_PINS,
295 .v.pins = (const struct hda_pintbl[]) {
296 { 0x1a, 0x02214021 }, /* headphone */
297 { 0x1b, 0x01014011 }, /* front */
Takashi Iwaied0e0d02014-01-07 17:48:11 +0100298 { 0x1c, 0x01813030 }, /* line-in */
299 { 0x1d, 0x01a19020 }, /* rear mic */
Takashi Iwai632408a2013-07-05 14:14:14 +0200300 { 0x1e, 0x411111f0 }, /* N/A */
301 { 0x1f, 0x02a190f0 }, /* mic */
Takashi Iwaied0e0d02014-01-07 17:48:11 +0100302 { 0x20, 0x411111f0 }, /* N/A */
Takashi Iwai632408a2013-07-05 14:14:14 +0200303 {}
304 },
305 },
306 [AD1986A_FIXUP_LAPTOP] = {
307 .type = HDA_FIXUP_PINS,
308 .v.pins = (const struct hda_pintbl[]) {
309 { 0x1a, 0x02214021 }, /* headphone */
310 { 0x1b, 0x90170110 }, /* speaker */
311 { 0x1c, 0x411111f0 }, /* N/A */
312 { 0x1d, 0x411111f0 }, /* N/A */
313 { 0x1e, 0x411111f0 }, /* N/A */
314 { 0x1f, 0x02a191f0 }, /* mic */
315 { 0x20, 0x411111f0 }, /* N/A */
316 {}
317 },
318 },
319 [AD1986A_FIXUP_LAPTOP_IMIC] = {
320 .type = HDA_FIXUP_PINS,
321 .v.pins = (const struct hda_pintbl[]) {
322 { 0x1d, 0x90a7013e }, /* int mic */
323 {}
324 },
325 .chained_before = 1,
326 .chain_id = AD1986A_FIXUP_LAPTOP,
327 },
Takashi Iwai4528eb12014-02-04 07:39:06 +0100328 [AD1986A_FIXUP_EAPD] = {
329 .type = HDA_FIXUP_FUNC,
330 .v.func = ad1986a_fixup_eapd,
331 },
Takashi Iwai73276432014-12-15 13:47:25 +0100332 [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 }, /* headphone */
340 { 0x1b, 0x90170110 }, /* speaker */
341 { 0x1c, 0x411111f0 }, /* N/A */
342 { 0x1d, 0x90a70130 }, /* int mic */
343 { 0x1e, 0x411111f0 }, /* N/A */
344 { 0x1f, 0x04a19040 }, /* mic */
345 { 0x20, 0x411111f0 }, /* N/A */
346 { 0x21, 0x411111f0 }, /* N/A */
347 { 0x22, 0x411111f0 }, /* N/A */
348 { 0x23, 0x411111f0 }, /* N/A */
349 { 0x24, 0x411111f0 }, /* N/A */
350 { 0x25, 0x411111f0 }, /* N/A */
351 {}
352 },
353 .chained = true,
354 .chain_id = AD1986A_FIXUP_EAPD_MIX_IN,
355 },
Takashi Iwaia928bd22013-01-22 18:18:42 +0100356};
357
358static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
Takashi Iwai632408a2013-07-05 14:14:14 +0200359 SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
Takashi Iwaif62f5ef2014-12-09 19:58:53 +0100360 SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
Takashi Iwai598e3062014-05-23 09:21:06 +0200361 SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
Takashi Iwai632408a2013-07-05 14:14:14 +0200362 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
363 SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
364 SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
Takashi Iwai4528eb12014-02-04 07:39:06 +0100365 SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),
Takashi Iwai632408a2013-07-05 14:14:14 +0200366 SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
Takashi Iwaif8c0ab12013-07-04 17:06:04 +0200367 SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
Takashi Iwaie0b27162013-07-04 16:50:46 +0200368 SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
Takashi Iwai73276432014-12-15 13:47:25 +0100369 SND_PCI_QUIRK(0x1631, 0xc022, "PackardBell EasyNote MX65", AD1986A_FIXUP_EASYNOTE),
Takashi Iwaia928bd22013-01-22 18:18:42 +0100370 SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
Takashi Iwai632408a2013-07-05 14:14:14 +0200371 SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
372 SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
373 {}
374};
375
376static const struct hda_model_fixup ad1986a_fixup_models[] = {
377 { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
378 { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
379 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
380 { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
Takashi Iwai9faa73f2014-12-10 13:58:37 +0100381 { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
Takashi Iwaia928bd22013-01-22 18:18:42 +0100382 {}
383};
384
385/*
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100386 */
Takashi Iwai632408a2013-07-05 14:14:14 +0200387static int patch_ad1986a(struct hda_codec *codec)
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100388{
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100389 int err;
390 struct ad198x_spec *spec;
Takashi Iwai36907392013-12-10 17:29:26 +0100391 static hda_nid_t preferred_pairs[] = {
392 0x1a, 0x03,
393 0x1b, 0x03,
394 0x1c, 0x04,
395 0x1d, 0x05,
396 0x1e, 0x03,
397 0
398 };
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100399
400 err = alloc_ad_spec(codec);
401 if (err < 0)
402 return err;
403 spec = codec->spec;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100404
405 /* AD1986A has the inverted EAPD implementation */
406 codec->inv_eapd = 1;
407
Takashi Iwaif2f8be42013-01-21 16:40:16 +0100408 spec->gen.mixer_nid = 0x07;
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100409 spec->gen.beep_nid = 0x19;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100410 set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
411
412 /* AD1986A has a hardware problem that it can't share a stream
413 * with multiple output pins. The copy of front to surrounds
414 * causes noisy or silent outputs at a certain timing, e.g.
415 * changing the volume.
416 * So, let's disable the shared stream.
417 */
418 spec->gen.multiout.no_share_stream = 1;
Takashi Iwai36907392013-12-10 17:29:26 +0100419 /* give fixed DAC/pin pairs */
420 spec->gen.preferred_dacs = preferred_pairs;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100421
Takashi Iwaib3bd4fc2013-12-02 15:04:03 +0100422 /* AD1986A can't manage the dynamic pin on/off smoothly */
423 spec->gen.auto_mute_via_amp = 1;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100424
Takashi Iwai632408a2013-07-05 14:14:14 +0200425 snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
426 ad1986a_fixups);
Takashi Iwaia928bd22013-01-22 18:18:42 +0100427 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
428
Takashi Iwaicbd209f2014-01-13 12:40:07 +0100429 err = ad198x_parse_auto_config(codec, false);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100430 if (err < 0) {
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100431 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100432 return err;
433 }
434
Takashi Iwaia928bd22013-01-22 18:18:42 +0100435 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
436
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100437 return 0;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100438}
439
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440
441/*
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200442 * AD1983 specific
443 */
444
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100445/*
446 * SPDIF mux control for AD1983 auto-parser
447 */
448static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
449 struct snd_ctl_elem_info *uinfo)
450{
451 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
452 struct ad198x_spec *spec = codec->spec;
453 static const char * const texts2[] = { "PCM", "ADC" };
454 static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
455 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
456 int num_conns = snd_hda_get_num_conns(codec, dig_out);
457
458 if (num_conns == 2)
459 return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
460 else if (num_conns == 3)
461 return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
462 else
463 return -EINVAL;
464}
465
466static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
467 struct snd_ctl_elem_value *ucontrol)
468{
469 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
470 struct ad198x_spec *spec = codec->spec;
471
472 ucontrol->value.enumerated.item[0] = spec->cur_smux;
473 return 0;
474}
475
476static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
477 struct snd_ctl_elem_value *ucontrol)
478{
479 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
480 struct ad198x_spec *spec = codec->spec;
481 unsigned int val = ucontrol->value.enumerated.item[0];
482 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
483 int num_conns = snd_hda_get_num_conns(codec, dig_out);
484
485 if (val >= num_conns)
486 return -EINVAL;
487 if (spec->cur_smux == val)
488 return 0;
489 spec->cur_smux = val;
490 snd_hda_codec_write_cache(codec, dig_out, 0,
491 AC_VERB_SET_CONNECT_SEL, val);
492 return 1;
493}
494
Bhumika Goyalfdbf0482017-08-16 14:14:11 +0530495static const struct snd_kcontrol_new ad1983_auto_smux_mixer = {
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100496 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
497 .name = "IEC958 Playback Source",
498 .info = ad1983_auto_smux_enum_info,
499 .get = ad1983_auto_smux_enum_get,
500 .put = ad1983_auto_smux_enum_put,
501};
502
503static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
504{
505 struct ad198x_spec *spec = codec->spec;
506 hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
507 int num_conns;
508
509 if (!dig_out)
510 return 0;
511 num_conns = snd_hda_get_num_conns(codec, dig_out);
512 if (num_conns != 2 && num_conns != 3)
513 return 0;
514 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
515 return -ENOMEM;
516 return 0;
517}
518
Takashi Iwaibd450dc2013-07-04 15:48:04 +0200519static int patch_ad1983(struct hda_codec *codec)
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100520{
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200521 struct ad198x_spec *spec;
Takashi Iwai276ab332014-02-05 08:49:41 +0100522 static hda_nid_t conn_0c[] = { 0x08 };
523 static hda_nid_t conn_0d[] = { 0x09 };
Takashi Iwaic5a4bcd2009-02-06 17:22:05 +0100524 int err;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200525
Takashi Iwai361dab32012-05-09 14:35:27 +0200526 err = alloc_ad_spec(codec);
527 if (err < 0)
528 return err;
529 spec = codec->spec;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200530
Takashi Iwaic7579fe2014-02-05 07:28:10 +0100531 spec->gen.mixer_nid = 0x0e;
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100532 spec->gen.beep_nid = 0x10;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100533 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
Takashi Iwai276ab332014-02-05 08:49:41 +0100534
535 /* limit the loopback routes not to confuse the parser */
536 snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);
537 snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);
538
Takashi Iwaicbd209f2014-01-13 12:40:07 +0100539 err = ad198x_parse_auto_config(codec, false);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100540 if (err < 0)
541 goto error;
542 err = ad1983_add_spdif_mux_ctl(codec);
543 if (err < 0)
544 goto error;
545 return 0;
546
547 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100548 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100549 return err;
550}
551
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200552
553/*
554 * AD1981 HD specific
555 */
556
Takashi Iwaia928bd22013-01-22 18:18:42 +0100557static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
558 const struct hda_fixup *fix, int action)
559{
560 struct ad198x_spec *spec = codec->spec;
561
562 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
563 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
564 spec->eapd_nid = 0x05;
565 }
566}
567
568/* set the upper-limit for mixer amp to 0dB for avoiding the possible
569 * damage by overloading
570 */
571static void ad1981_fixup_amp_override(struct hda_codec *codec,
572 const struct hda_fixup *fix, int action)
573{
574 if (action == HDA_FIXUP_ACT_PRE_PROBE)
575 snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
576 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
577 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
578 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
579 (1 << AC_AMPCAP_MUTE_SHIFT));
580}
581
582enum {
583 AD1981_FIXUP_AMP_OVERRIDE,
584 AD1981_FIXUP_HP_EAPD,
585};
586
587static const struct hda_fixup ad1981_fixups[] = {
588 [AD1981_FIXUP_AMP_OVERRIDE] = {
589 .type = HDA_FIXUP_FUNC,
590 .v.func = ad1981_fixup_amp_override,
591 },
592 [AD1981_FIXUP_HP_EAPD] = {
593 .type = HDA_FIXUP_FUNC,
594 .v.func = ad1981_fixup_hp_eapd,
595 .chained = true,
596 .chain_id = AD1981_FIXUP_AMP_OVERRIDE,
597 },
598};
599
600static const struct snd_pci_quirk ad1981_fixup_tbl[] = {
601 SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
602 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
603 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
604 /* HP nx6320 (reversed SSID, H/W bug) */
605 SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
606 {}
607};
608
Takashi Iwaibd450dc2013-07-04 15:48:04 +0200609static int patch_ad1981(struct hda_codec *codec)
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100610{
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200611 struct ad198x_spec *spec;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100612 int err;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200613
Takashi Iwai361dab32012-05-09 14:35:27 +0200614 err = alloc_ad_spec(codec);
615 if (err < 0)
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200616 return -ENOMEM;
Takashi Iwai361dab32012-05-09 14:35:27 +0200617 spec = codec->spec;
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200618
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100619 spec->gen.mixer_nid = 0x0e;
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100620 spec->gen.beep_nid = 0x10;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100621 set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
Takashi Iwaia928bd22013-01-22 18:18:42 +0100622
623 snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
624 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
625
Takashi Iwaicbd209f2014-01-13 12:40:07 +0100626 err = ad198x_parse_auto_config(codec, false);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100627 if (err < 0)
628 goto error;
629 err = ad1983_add_spdif_mux_ctl(codec);
630 if (err < 0)
631 goto error;
Takashi Iwaia928bd22013-01-22 18:18:42 +0100632
633 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
634
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100635 return 0;
636
637 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100638 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100639 return err;
640}
641
Takashi Iwai4a3fdf32005-04-14 13:35:51 +0200642
643/*
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100644 * AD1988
645 *
646 * Output pins and routes
647 *
Takashi Iwaid32410b12005-11-24 16:06:23 +0100648 * Pin Mix Sel DAC (*)
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100649 * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
650 * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
651 * port-C 0x15 (mute) <- 0x2c <- 0x31 <- 05/0a
652 * port-D 0x12 (mute/hp) <- 0x29 <- 04
653 * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
654 * port-F 0x16 (mute) <- 0x2a <- 06
655 * port-G 0x24 (mute) <- 0x27 <- 05
656 * port-H 0x25 (mute) <- 0x28 <- 0a
657 * mono 0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
658 *
Takashi Iwaid32410b12005-11-24 16:06:23 +0100659 * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
660 * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100661 *
662 * Input pins and routes
663 *
664 * pin boost mix input # / adc input #
665 * port-A 0x11 -> 0x38 -> mix 2, ADC 0
666 * port-B 0x14 -> 0x39 -> mix 0, ADC 1
667 * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
668 * port-D 0x12 -> 0x3d -> mix 3, ADC 8
669 * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
670 * port-F 0x16 -> 0x3b -> mix 5, ADC 3
671 * port-G 0x24 -> N/A -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
672 * port-H 0x25 -> N/A -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
673 *
674 *
675 * DAC assignment
Takashi Iwaid32410b12005-11-24 16:06:23 +0100676 * 6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
Takashi Iwaif8c7c7b2005-11-24 16:17:20 +0100677 * 3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100678 *
679 * Inputs of Analog Mix (0x20)
680 * 0:Port-B (front mic)
681 * 1:Port-C/G/H (line-in)
682 * 2:Port-A
683 * 3:Port-D (line-in/2)
684 * 4:Port-E/G/H (mic-in)
685 * 5:Port-F (mic2-in)
686 * 6:CD
687 * 7:Beep
688 *
689 * ADC selection
690 * 0:Port-A
691 * 1:Port-B (front mic-in)
692 * 2:Port-C (line-in)
693 * 3:Port-F (mic2-in)
694 * 4:Port-E (mic-in)
695 * 5:CD
696 * 6:Port-G
697 * 7:Port-H
698 * 8:Port-D (line-in/2)
699 * 9:Mix
700 *
701 * Proposed pin assignments by the datasheet
702 *
703 * 6-stack
704 * Port-A front headphone
705 * B front mic-in
706 * C rear line-in
707 * D rear front-out
708 * E rear mic-in
709 * F rear surround
710 * G rear CLFE
711 * H rear side
712 *
713 * 3-stack
714 * Port-A front headphone
715 * B front mic
716 * C rear line-in/surround
717 * D rear front-out
718 * E rear mic-in/CLFE
719 *
720 * laptop
721 * Port-A headphone
722 * B mic-in
723 * C docking station
724 * D internal speaker (with EAPD)
725 * E/F quad mic array
726 */
727
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100728static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
729 struct snd_ctl_elem_info *uinfo)
730{
731 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
732 static const char * const texts[] = {
733 "PCM", "ADC1", "ADC2", "ADC3",
734 };
735 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
736 if (num_conns > 4)
737 num_conns = 4;
738 return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
739}
740
741static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
742 struct snd_ctl_elem_value *ucontrol)
743{
744 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
745 struct ad198x_spec *spec = codec->spec;
746
747 ucontrol->value.enumerated.item[0] = spec->cur_smux;
748 return 0;
749}
750
751static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
752 struct snd_ctl_elem_value *ucontrol)
753{
754 struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
755 struct ad198x_spec *spec = codec->spec;
756 unsigned int val = ucontrol->value.enumerated.item[0];
757 struct nid_path *path;
758 int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
759
760 if (val >= num_conns)
761 return -EINVAL;
762 if (spec->cur_smux == val)
763 return 0;
764
765 mutex_lock(&codec->control_mutex);
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100766 path = snd_hda_get_path_from_idx(codec,
767 spec->smux_paths[spec->cur_smux]);
768 if (path)
769 snd_hda_activate_path(codec, path, false, true);
770 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
771 if (path)
772 snd_hda_activate_path(codec, path, true, true);
773 spec->cur_smux = val;
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100774 mutex_unlock(&codec->control_mutex);
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100775 return 1;
776}
777
Bhumika Goyalfdbf0482017-08-16 14:14:11 +0530778static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100779 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
780 .name = "IEC958 Playback Source",
781 .info = ad1988_auto_smux_enum_info,
782 .get = ad1988_auto_smux_enum_get,
783 .put = ad1988_auto_smux_enum_put,
784};
785
786static int ad1988_auto_init(struct hda_codec *codec)
787{
788 struct ad198x_spec *spec = codec->spec;
789 int i, err;
790
791 err = snd_hda_gen_init(codec);
792 if (err < 0)
793 return err;
794 if (!spec->gen.autocfg.dig_outs)
795 return 0;
796
797 for (i = 0; i < 4; i++) {
798 struct nid_path *path;
799 path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
800 if (path)
801 snd_hda_activate_path(codec, path, path->active, false);
802 }
803
804 return 0;
805}
806
807static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
808{
809 struct ad198x_spec *spec = codec->spec;
810 int i, num_conns;
811 /* we create four static faked paths, since AD codecs have odd
812 * widget connections regarding the SPDIF out source
813 */
814 static struct nid_path fake_paths[4] = {
815 {
816 .depth = 3,
817 .path = { 0x02, 0x1d, 0x1b },
818 .idx = { 0, 0, 0 },
819 .multi = { 0, 0, 0 },
820 },
821 {
822 .depth = 4,
823 .path = { 0x08, 0x0b, 0x1d, 0x1b },
824 .idx = { 0, 0, 1, 0 },
825 .multi = { 0, 1, 0, 0 },
826 },
827 {
828 .depth = 4,
829 .path = { 0x09, 0x0b, 0x1d, 0x1b },
830 .idx = { 0, 1, 1, 0 },
831 .multi = { 0, 1, 0, 0 },
832 },
833 {
834 .depth = 4,
835 .path = { 0x0f, 0x0b, 0x1d, 0x1b },
836 .idx = { 0, 2, 1, 0 },
837 .multi = { 0, 1, 0, 0 },
838 },
839 };
840
841 /* SPDIF source mux appears to be present only on AD1988A */
842 if (!spec->gen.autocfg.dig_outs ||
843 get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
844 return 0;
845
846 num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
847 if (num_conns != 3 && num_conns != 4)
848 return 0;
849
850 for (i = 0; i < num_conns; i++) {
851 struct nid_path *path = snd_array_new(&spec->gen.paths);
852 if (!path)
853 return -ENOMEM;
854 *path = fake_paths[i];
855 if (!i)
856 path->active = 1;
857 spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
858 }
859
860 if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
861 return -ENOMEM;
862
863 codec->patch_ops.init = ad1988_auto_init;
864
865 return 0;
866}
867
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100868/*
Takashi Iwaid32410b12005-11-24 16:06:23 +0100869 */
870
Takashi Iwai36ad4532013-07-04 16:34:20 +0200871enum {
872 AD1988_FIXUP_6STACK_DIG,
873};
874
875static const struct hda_fixup ad1988_fixups[] = {
876 [AD1988_FIXUP_6STACK_DIG] = {
877 .type = HDA_FIXUP_PINS,
878 .v.pins = (const struct hda_pintbl[]) {
879 { 0x11, 0x02214130 }, /* front-hp */
880 { 0x12, 0x01014010 }, /* line-out */
881 { 0x14, 0x02a19122 }, /* front-mic */
882 { 0x15, 0x01813021 }, /* line-in */
883 { 0x16, 0x01011012 }, /* line-out */
884 { 0x17, 0x01a19020 }, /* mic */
885 { 0x1b, 0x0145f1f0 }, /* SPDIF */
886 { 0x24, 0x01016011 }, /* line-out */
887 { 0x25, 0x01012013 }, /* line-out */
888 { }
889 }
890 },
891};
892
893static const struct hda_model_fixup ad1988_fixup_models[] = {
894 { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
895 {}
896};
897
898static int patch_ad1988(struct hda_codec *codec)
Takashi Iwaid32410b12005-11-24 16:06:23 +0100899{
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100900 struct ad198x_spec *spec;
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100901 int err;
Takashi Iwaid32410b12005-11-24 16:06:23 +0100902
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100903 err = alloc_ad_spec(codec);
904 if (err < 0)
905 return err;
906 spec = codec->spec;
907
Takashi Iwaif2f8be42013-01-21 16:40:16 +0100908 spec->gen.mixer_nid = 0x20;
Takashi Iwaie4a395e2013-01-23 17:00:31 +0100909 spec->gen.mixer_merge_nid = 0x21;
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100910 spec->gen.beep_nid = 0x10;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +0100911 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
Takashi Iwai36ad4532013-07-04 16:34:20 +0200912
913 snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
914 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
915
Takashi Iwaicbd209f2014-01-13 12:40:07 +0100916 err = ad198x_parse_auto_config(codec, true);
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100917 if (err < 0)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100918 goto error;
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100919 err = ad1988_add_spdif_mux_ctl(codec);
920 if (err < 0)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100921 goto error;
Takashi Iwai36ad4532013-07-04 16:34:20 +0200922
923 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
924
Takashi Iwai272f3ea2013-01-22 15:31:33 +0100925 return 0;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100926
927 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +0100928 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +0100929 return err;
Takashi Iwaid32410b12005-11-24 16:06:23 +0100930}
931
Takashi Iwaifd66e0d2005-11-17 15:31:34 +0100932
933/*
Takashi Iwai2bac6472007-05-18 18:21:41 +0200934 * AD1884 / AD1984
935 *
936 * port-B - front line/mic-in
937 * port-E - aux in/out
938 * port-F - aux in/out
939 * port-C - rear line/mic-in
940 * port-D - rear line/hp-out
941 * port-A - front line/hp-out
942 *
943 * AD1984 = AD1884 + two digital mic-ins
944 *
Takashi Iwai5ccc618f2013-07-04 15:36:56 +0200945 * AD1883 / AD1884A / AD1984A / AD1984B
946 *
947 * port-B (0x14) - front mic-in
948 * port-E (0x1c) - rear mic-in
949 * port-F (0x16) - CD / ext out
950 * port-C (0x15) - rear line-in
951 * port-D (0x12) - rear line-out
952 * port-A (0x11) - front hp-out
953 *
954 * AD1984A = AD1884A + digital-mic
955 * AD1883 = equivalent with AD1984A
956 * AD1984B = AD1984A + extra SPDIF-out
Takashi Iwai2bac6472007-05-18 18:21:41 +0200957 */
958
Takashi Iwaia928bd22013-01-22 18:18:42 +0100959/* set the upper-limit for mixer amp to 0dB for avoiding the possible
960 * damage by overloading
961 */
962static void ad1884_fixup_amp_override(struct hda_codec *codec,
963 const struct hda_fixup *fix, int action)
964{
965 if (action == HDA_FIXUP_ACT_PRE_PROBE)
966 snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
967 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
968 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
969 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
970 (1 << AC_AMPCAP_MUTE_SHIFT));
971}
972
Takashi Iwai1a39b5e2013-07-04 14:32:16 +0200973/* toggle GPIO1 according to the mute state */
974static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
975{
976 struct hda_codec *codec = private_data;
977 struct ad198x_spec *spec = codec->spec;
978
979 if (spec->eapd_nid)
980 ad_vmaster_eapd_hook(private_data, enabled);
Takashi Iwai401caff2018-06-27 11:43:09 +0200981 snd_hda_codec_write_cache(codec, 0x01, 0,
Takashi Iwai1a39b5e2013-07-04 14:32:16 +0200982 AC_VERB_SET_GPIO_DATA,
983 enabled ? 0x00 : 0x02);
984}
985
Takashi Iwaia928bd22013-01-22 18:18:42 +0100986static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
987 const struct hda_fixup *fix, int action)
988{
989 struct ad198x_spec *spec = codec->spec;
990
Takashi Iwai8f0b3b72013-07-04 12:54:22 +0200991 switch (action) {
992 case HDA_FIXUP_ACT_PRE_PROBE:
Takashi Iwai1a39b5e2013-07-04 14:32:16 +0200993 spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
Takashi Iwai1cd9b2f2013-12-02 13:19:45 +0100994 spec->gen.own_eapd_ctl = 1;
Takashi Iwaia551d912015-02-26 12:34:49 +0100995 snd_hda_codec_write_cache(codec, 0x01, 0,
996 AC_VERB_SET_GPIO_MASK, 0x02);
997 snd_hda_codec_write_cache(codec, 0x01, 0,
998 AC_VERB_SET_GPIO_DIRECTION, 0x02);
999 snd_hda_codec_write_cache(codec, 0x01, 0,
1000 AC_VERB_SET_GPIO_DATA, 0x02);
Takashi Iwai8f0b3b72013-07-04 12:54:22 +02001001 break;
1002 case HDA_FIXUP_ACT_PROBE:
Takashi Iwaia928bd22013-01-22 18:18:42 +01001003 if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
1004 spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
1005 else
1006 spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
Takashi Iwai8f0b3b72013-07-04 12:54:22 +02001007 break;
Takashi Iwaia928bd22013-01-22 18:18:42 +01001008 }
1009}
1010
Takashi Iwai1ac32932013-10-26 00:24:14 +02001011static void ad1884_fixup_thinkpad(struct hda_codec *codec,
1012 const struct hda_fixup *fix, int action)
1013{
1014 struct ad198x_spec *spec = codec->spec;
1015
Takashi Iwaiafb5a772013-10-26 00:33:58 +02001016 if (action == HDA_FIXUP_ACT_PRE_PROBE) {
Takashi Iwai1ac32932013-10-26 00:24:14 +02001017 spec->gen.keep_eapd_on = 1;
Takashi Iwaiafb5a772013-10-26 00:33:58 +02001018 spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
1019 spec->eapd_nid = 0x12;
Takashi Iwaif3e9b592014-03-05 12:00:29 +01001020 /* Analog PC Beeper - allow firmware/ACPI beeps */
1021 spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
1022 spec->gen.beep_nid = 0; /* no digital beep */
Takashi Iwaiafb5a772013-10-26 00:33:58 +02001023 }
Takashi Iwai1ac32932013-10-26 00:24:14 +02001024}
1025
Takashi Iwai6a699be2013-07-04 14:45:37 +02001026/* set magic COEFs for dmic */
1027static const struct hda_verb ad1884_dmic_init_verbs[] = {
1028 {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
1029 {0x01, AC_VERB_SET_PROC_COEF, 0x08},
1030 {}
1031};
1032
Takashi Iwaia928bd22013-01-22 18:18:42 +01001033enum {
1034 AD1884_FIXUP_AMP_OVERRIDE,
1035 AD1884_FIXUP_HP_EAPD,
Takashi Iwai6a699be2013-07-04 14:45:37 +02001036 AD1884_FIXUP_DMIC_COEF,
Takashi Iwai1ac32932013-10-26 00:24:14 +02001037 AD1884_FIXUP_THINKPAD,
Takashi Iwaif4046272013-07-04 15:14:17 +02001038 AD1884_FIXUP_HP_TOUCHSMART,
Takashi Iwaia928bd22013-01-22 18:18:42 +01001039};
1040
1041static const struct hda_fixup ad1884_fixups[] = {
1042 [AD1884_FIXUP_AMP_OVERRIDE] = {
1043 .type = HDA_FIXUP_FUNC,
1044 .v.func = ad1884_fixup_amp_override,
1045 },
1046 [AD1884_FIXUP_HP_EAPD] = {
1047 .type = HDA_FIXUP_FUNC,
1048 .v.func = ad1884_fixup_hp_eapd,
1049 .chained = true,
1050 .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
1051 },
Takashi Iwai6a699be2013-07-04 14:45:37 +02001052 [AD1884_FIXUP_DMIC_COEF] = {
1053 .type = HDA_FIXUP_VERBS,
1054 .v.verbs = ad1884_dmic_init_verbs,
1055 },
Takashi Iwai1ac32932013-10-26 00:24:14 +02001056 [AD1884_FIXUP_THINKPAD] = {
1057 .type = HDA_FIXUP_FUNC,
1058 .v.func = ad1884_fixup_thinkpad,
1059 .chained = true,
1060 .chain_id = AD1884_FIXUP_DMIC_COEF,
1061 },
Takashi Iwaif4046272013-07-04 15:14:17 +02001062 [AD1884_FIXUP_HP_TOUCHSMART] = {
1063 .type = HDA_FIXUP_VERBS,
1064 .v.verbs = ad1884_dmic_init_verbs,
1065 .chained = true,
1066 .chain_id = AD1884_FIXUP_HP_EAPD,
1067 },
Takashi Iwaia928bd22013-01-22 18:18:42 +01001068};
1069
1070static const struct snd_pci_quirk ad1884_fixup_tbl[] = {
Takashi Iwaif4046272013-07-04 15:14:17 +02001071 SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
Takashi Iwaia928bd22013-01-22 18:18:42 +01001072 SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
Takashi Iwai1ac32932013-10-26 00:24:14 +02001073 SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
Takashi Iwaia928bd22013-01-22 18:18:42 +01001074 {}
1075};
1076
1077
Takashi Iwai5ccc618f2013-07-04 15:36:56 +02001078static int patch_ad1884(struct hda_codec *codec)
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001079{
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001080 struct ad198x_spec *spec;
Takashi Iwai272f3ea2013-01-22 15:31:33 +01001081 int err;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001082
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001083 err = alloc_ad_spec(codec);
1084 if (err < 0)
1085 return err;
1086 spec = codec->spec;
1087
Takashi Iwaif2f8be42013-01-21 16:40:16 +01001088 spec->gen.mixer_nid = 0x20;
Takashi Iwaic5eda4c2014-03-05 11:52:24 +01001089 spec->gen.mixer_merge_nid = 0x21;
Takashi Iwai7504b6c2013-03-18 11:25:51 +01001090 spec->gen.beep_nid = 0x10;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001091 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
Takashi Iwaia928bd22013-01-22 18:18:42 +01001092
1093 snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
1094 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
1095
Takashi Iwaicbd209f2014-01-13 12:40:07 +01001096 err = ad198x_parse_auto_config(codec, true);
Takashi Iwai272f3ea2013-01-22 15:31:33 +01001097 if (err < 0)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001098 goto error;
Takashi Iwai272f3ea2013-01-22 15:31:33 +01001099 err = ad1983_add_spdif_mux_ctl(codec);
1100 if (err < 0)
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001101 goto error;
Takashi Iwaia928bd22013-01-22 18:18:42 +01001102
1103 snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
1104
Takashi Iwai272f3ea2013-01-22 15:31:33 +01001105 return 0;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001106
1107 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +01001108 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001109 return err;
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001110}
1111
Takashi Iwaic5059252008-02-16 09:43:56 +01001112/*
Takashi Iwai9e44c6e2008-08-18 13:53:07 +02001113 * AD1882 / AD1882A
Takashi Iwai0ac85512007-06-20 15:46:13 +02001114 *
1115 * port-A - front hp-out
1116 * port-B - front mic-in
1117 * port-C - rear line-in, shared surr-out (3stack)
1118 * port-D - rear line-out
1119 * port-E - rear mic-in, shared clfe-out (3stack)
1120 * port-F - rear surr-out (6stack)
1121 * port-G - rear clfe-out (6stack)
1122 */
1123
Takashi Iwaiaa95d612013-07-04 15:16:31 +02001124static int patch_ad1882(struct hda_codec *codec)
Takashi Iwai78bb3cb2012-12-21 15:17:06 +01001125{
Takashi Iwai0ac85512007-06-20 15:46:13 +02001126 struct ad198x_spec *spec;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001127 int err;
Takashi Iwai0ac85512007-06-20 15:46:13 +02001128
Takashi Iwai361dab32012-05-09 14:35:27 +02001129 err = alloc_ad_spec(codec);
1130 if (err < 0)
1131 return err;
1132 spec = codec->spec;
Takashi Iwai0ac85512007-06-20 15:46:13 +02001133
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001134 spec->gen.mixer_nid = 0x20;
Takashi Iwaie4a395e2013-01-23 17:00:31 +01001135 spec->gen.mixer_merge_nid = 0x21;
Takashi Iwai7504b6c2013-03-18 11:25:51 +01001136 spec->gen.beep_nid = 0x10;
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001137 set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
Takashi Iwaicbd209f2014-01-13 12:40:07 +01001138 err = ad198x_parse_auto_config(codec, true);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001139 if (err < 0)
1140 goto error;
1141 err = ad1988_add_spdif_mux_ctl(codec);
1142 if (err < 0)
1143 goto error;
1144 return 0;
1145
1146 error:
Takashi Iwai7504b6c2013-03-18 11:25:51 +01001147 snd_hda_gen_free(codec);
Takashi Iwai9ff4bc82013-01-22 16:45:58 +01001148 return err;
1149}
1150
Takashi Iwai0ac85512007-06-20 15:46:13 +02001151
1152/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001153 * patch entries
1154 */
Takashi Iwaib9a94a92015-10-01 16:20:04 +02001155static const struct hda_device_id snd_hda_id_analog[] = {
1156 HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
1157 HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
1158 HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
1159 HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
1160 HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
1161 HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
1162 HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
1163 HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
1164 HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
1165 HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
1166 HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
1167 HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
1168 HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
1169 HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
1170 HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001171 {} /* terminator */
1172};
Takashi Iwaib9a94a92015-10-01 16:20:04 +02001173MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
Takashi Iwai1289e9e2008-11-27 15:47:11 +01001174
1175MODULE_LICENSE("GPL");
1176MODULE_DESCRIPTION("Analog Devices HD-audio codec");
1177
Takashi Iwaid8a766a2015-02-17 15:25:37 +01001178static struct hda_codec_driver analog_driver = {
Takashi Iwaib9a94a92015-10-01 16:20:04 +02001179 .id = snd_hda_id_analog,
Takashi Iwai1289e9e2008-11-27 15:47:11 +01001180};
1181
Takashi Iwaid8a766a2015-02-17 15:25:37 +01001182module_hda_codec_driver(analog_driver);