1230130Smav/*-
2230130Smav * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
3230130Smav * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
4230130Smav * Copyright (c) 2008-2012 Alexander Motin <mav@FreeBSD.org>
5230130Smav * All rights reserved.
6230130Smav *
7230130Smav * Redistribution and use in source and binary forms, with or without
8230130Smav * modification, are permitted provided that the following conditions
9230130Smav * are met:
10230130Smav * 1. Redistributions of source code must retain the above copyright
11230130Smav *    notice, this list of conditions and the following disclaimer.
12230130Smav * 2. Redistributions in binary form must reproduce the above copyright
13230130Smav *    notice, this list of conditions and the following disclaimer in the
14230130Smav *    documentation and/or other materials provided with the distribution.
15230130Smav *
16230130Smav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17230130Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18230130Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19230130Smav * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20230130Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21230130Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22230130Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23230130Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24230130Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25230130Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26230130Smav * SUCH DAMAGE.
27230130Smav */
28230130Smav
29230130Smav/*
30230130Smav * Intel High Definition Audio (Audio function quirks) driver for FreeBSD.
31230130Smav */
32230130Smav
33230130Smav#ifdef HAVE_KERNEL_OPTION_HEADERS
34230130Smav#include "opt_snd.h"
35230130Smav#endif
36230130Smav
37230130Smav#include <dev/sound/pcm/sound.h>
38230130Smav
39230130Smav#include <sys/ctype.h>
40230130Smav
41230130Smav#include <dev/sound/pci/hda/hdac.h>
42230130Smav#include <dev/sound/pci/hda/hdaa.h>
43230130Smav#include <dev/sound/pci/hda/hda_reg.h>
44230130Smav
45230130SmavSND_DECLARE_FILE("$FreeBSD: releng/11.0/sys/dev/sound/pci/hda/hdaa_patches.c 285723 2015-07-20 17:48:00Z mav $");
46230130Smav
47230130Smavstatic const struct {
48230130Smav	uint32_t model;
49230130Smav	uint32_t id;
50248786Smav	uint32_t subsystemid;
51230130Smav	uint32_t set, unset;
52230130Smav	uint32_t gpio;
53230130Smav} hdac_quirks[] = {
54230130Smav	/*
55230130Smav	 * XXX Force stereo quirk. Monoural recording / playback
56230130Smav	 *     on few codecs (especially ALC880) seems broken or
57230130Smav	 *     perhaps unsupported.
58230130Smav	 */
59248786Smav	{ HDA_MATCH_ALL, HDA_MATCH_ALL, HDA_MATCH_ALL,
60230130Smav	    HDAA_QUIRK_FORCESTEREO | HDAA_QUIRK_IVREF, 0,
61230130Smav	    0 },
62248786Smav	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL, HDA_MATCH_ALL,
63230130Smav	    0, 0,
64230130Smav	    HDAA_GPIO_SET(0) },
65248786Smav	{ ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660, HDA_MATCH_ALL,
66230130Smav	    0, 0,
67230130Smav	    HDAA_GPIO_SET(0) },
68248786Smav	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
69230130Smav	    0, 0,
70230130Smav	    HDAA_GPIO_SET(0) },
71248786Smav	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
72230130Smav	    0, 0,
73230130Smav	    HDAA_GPIO_SET(0) },
74248786Smav	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882, HDA_MATCH_ALL,
75230130Smav	    0, 0,
76230130Smav	    HDAA_GPIO_SET(0) },
77248786Smav	{ ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882, HDA_MATCH_ALL,
78230130Smav	    0, 0,
79230130Smav	    HDAA_GPIO_SET(0) },
80248786Smav	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
81230130Smav	    HDAA_QUIRK_EAPDINV, 0,
82230130Smav	    0 },
83248786Smav	{ ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
84230130Smav	    HDAA_QUIRK_EAPDINV, 0,
85230130Smav	    0 },
86248786Smav	{ ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861, HDA_MATCH_ALL,
87230130Smav	    HDAA_QUIRK_OVREF, 0,
88230130Smav	    0 },
89248786Smav	{ UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861, HDA_MATCH_ALL,
90230130Smav	    HDAA_QUIRK_OVREF, 0,
91230130Smav	    0 },
92248786Smav	/*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988, HDA_MATCH_ALL,
93230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
94230130Smav	    0 },*/
95248786Smav	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
96230130Smav	    0, 0,
97230130Smav	    HDAA_GPIO_SET(1) },
98248786Smav	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
99230130Smav	    HDAA_QUIRK_EAPDINV | HDAA_QUIRK_SENSEINV, 0,
100230130Smav	    0 },
101248786Smav	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
102230130Smav	    HDAA_QUIRK_EAPDINV, 0,
103230130Smav	    0 },
104248786Smav	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885, HDA_MATCH_ALL,
105230130Smav	    HDAA_QUIRK_OVREF50, 0,
106230130Smav	    HDAA_GPIO_SET(0) },
107248786Smav	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDA_MATCH_ALL,
108230130Smav	    0, 0,
109230130Smav	    HDAA_GPIO_SET(0) | HDAA_GPIO_SET(1) },
110261507Shselasky	{ APPLE_MACBOOKAIR31, HDA_CODEC_CS4206, HDA_MATCH_ALL,
111261507Shselasky	    0, 0,
112261507Shselasky	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
113248786Smav	{ APPLE_MACBOOKPRO55, HDA_CODEC_CS4206, HDA_MATCH_ALL,
114230130Smav	    0, 0,
115230130Smav	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
116261507Shselasky	{ APPLE_MACBOOKPRO71, HDA_CODEC_CS4206, HDA_MATCH_ALL,
117261507Shselasky	    0, 0,
118261507Shselasky	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
119261507Shselasky	{ HDA_INTEL_MACBOOKPRO92, HDA_CODEC_CS4206, HDA_MATCH_ALL,
120261507Shselasky	    0, 0,
121261507Shselasky	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
122248786Smav	{ DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X, HDA_MATCH_ALL,
123230130Smav	    0, 0,
124230130Smav	    HDAA_GPIO_SET(0) },
125248786Smav	{ DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X, HDA_MATCH_ALL,
126230130Smav	    0, 0,
127230130Smav	    HDAA_GPIO_SET(2) },
128248786Smav	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X, HDA_MATCH_ALL,
129230130Smav	    0, 0,
130230130Smav	    HDAA_GPIO_SET(0) },
131248786Smav	{ HDA_MATCH_ALL, HDA_CODEC_AD1988, HDA_MATCH_ALL,
132230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
133230130Smav	    0 },
134248786Smav	{ HDA_MATCH_ALL, HDA_CODEC_AD1988B, HDA_MATCH_ALL,
135230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
136230130Smav	    0 },
137248786Smav	{ HDA_MATCH_ALL, HDA_CODEC_CX20549, HDA_MATCH_ALL,
138230130Smav	    0, HDAA_QUIRK_FORCESTEREO,
139248786Smav	    0 },
140248786Smav	/* Mac Pro 1,1 requires ovref for proper volume level. */
141248786Smav	{ 0x00000000, HDA_CODEC_ALC885, 0x106b0c00,
142248786Smav	    0, HDAA_QUIRK_OVREF,
143230130Smav	    0 }
144230130Smav};
145230130Smav
146230130Smavstatic void
147230130Smavhdac_pin_patch(struct hdaa_widget *w)
148230130Smav{
149230130Smav	const char *patch = NULL;
150230130Smav	uint32_t config, orig, id, subid;
151230130Smav	nid_t nid = w->nid;
152230130Smav
153230130Smav	config = orig = w->wclass.pin.config;
154230130Smav	id = hdaa_codec_id(w->devinfo);
155242352Smav	subid = hdaa_card_id(w->devinfo);
156230130Smav
157230130Smav	/* XXX: Old patches require complete review.
158230130Smav	 * Now they may create more problem then solve due to
159230130Smav	 * incorrect associations.
160230130Smav	 */
161230130Smav	if (id == HDA_CODEC_ALC880 && subid == LG_LW20_SUBVENDOR) {
162230130Smav		switch (nid) {
163230130Smav		case 26:
164230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
165230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
166230130Smav			break;
167230130Smav		case 27:
168230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
169230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
170230130Smav			break;
171230130Smav		default:
172230130Smav			break;
173230130Smav		}
174230130Smav	} else if (id == HDA_CODEC_ALC880 &&
175230130Smav	    (subid == CLEVO_D900T_SUBVENDOR ||
176230130Smav	    subid == ASUS_M5200_SUBVENDOR)) {
177230130Smav		/*
178230130Smav		 * Super broken BIOS
179230130Smav		 */
180230130Smav		switch (nid) {
181230130Smav		case 24:	/* MIC1 */
182230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
183230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
184230130Smav			break;
185230130Smav		case 25:	/* XXX MIC2 */
186230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
187230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
188230130Smav			break;
189230130Smav		case 26:	/* LINE1 */
190230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
191230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
192230130Smav			break;
193230130Smav		case 27:	/* XXX LINE2 */
194230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
195230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
196230130Smav			break;
197230130Smav		case 28:	/* CD */
198230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
199230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
200230130Smav			break;
201230130Smav		}
202230130Smav	} else if (id == HDA_CODEC_ALC883 &&
203230130Smav	    (subid == MSI_MS034A_SUBVENDOR ||
204230130Smav	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subid))) {
205230130Smav		switch (nid) {
206230130Smav		case 25:
207230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
208230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
209230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
210230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
211230130Smav			break;
212230130Smav		case 28:
213230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
214230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
215230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
216230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
217230130Smav			break;
218230130Smav		}
219230130Smav	} else if (id == HDA_CODEC_CX20549 && subid ==
220230130Smav	    HP_V3000_SUBVENDOR) {
221230130Smav		switch (nid) {
222230130Smav		case 18:
223230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
224230130Smav			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
225230130Smav			break;
226230130Smav		case 20:
227230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
228230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
229230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
230230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
231230130Smav			break;
232230130Smav		case 21:
233230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
234230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
235230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
236230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
237230130Smav			break;
238230130Smav		}
239230130Smav	} else if (id == HDA_CODEC_CX20551 && subid ==
240230130Smav	    HP_DV5000_SUBVENDOR) {
241230130Smav		switch (nid) {
242230130Smav		case 20:
243230130Smav		case 21:
244230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
245230130Smav			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
246230130Smav			break;
247230130Smav		}
248230130Smav	} else if (id == HDA_CODEC_ALC861 && subid ==
249230130Smav	    ASUS_W6F_SUBVENDOR) {
250230130Smav		switch (nid) {
251230130Smav		case 11:
252230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
253230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
254230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
255230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
256230130Smav			break;
257230130Smav		case 12:
258230130Smav		case 14:
259230130Smav		case 16:
260230130Smav		case 31:
261230130Smav		case 32:
262230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
263230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
264230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
265230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
266230130Smav			break;
267230130Smav		case 15:
268230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
269230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
270230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
271230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
272230130Smav			break;
273230130Smav		}
274230130Smav	} else if (id == HDA_CODEC_ALC861 && subid ==
275230130Smav	    UNIWILL_9075_SUBVENDOR) {
276230130Smav		switch (nid) {
277230130Smav		case 15:
278230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
279230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
280230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
281230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
282230130Smav			break;
283230130Smav		}
284230130Smav	}
285230130Smav
286230130Smav	/* New patches */
287244145Smav	if (id == HDA_CODEC_AD1984A &&
288244145Smav	    subid == LENOVO_X300_SUBVENDOR) {
289244145Smav		switch (nid) {
290244145Smav		case 17: /* Headphones with redirection */
291244145Smav			patch = "as=1 seq=15";
292244145Smav			break;
293244145Smav		case 20: /* Two mics together */
294244145Smav			patch = "as=2 seq=15";
295244145Smav			break;
296244145Smav		}
297244145Smav	} else if (id == HDA_CODEC_AD1986A &&
298230130Smav	    (subid == ASUS_M2NPVMX_SUBVENDOR ||
299230130Smav	    subid == ASUS_A8NVMCSM_SUBVENDOR ||
300230130Smav	    subid == ASUS_P5PL2_SUBVENDOR)) {
301230130Smav		switch (nid) {
302230130Smav		case 26: /* Headphones with redirection */
303230130Smav			patch = "as=1 seq=15";
304230130Smav			break;
305230130Smav		case 28: /* 5.1 out => 2.0 out + 1 input */
306230130Smav			patch = "device=Line-in as=8 seq=1";
307230130Smav			break;
308230130Smav		case 29: /* Can't use this as input, as the only available mic
309230130Smav			  * preamplifier is busy by front panel mic (nid 31).
310230130Smav			  * If you want to use this rear connector as mic input,
311230130Smav			  * you have to disable the front panel one. */
312230130Smav			patch = "as=0";
313230130Smav			break;
314230130Smav		case 31: /* Lot of inputs configured with as=15 and unusable */
315230130Smav			patch = "as=8 seq=3";
316230130Smav			break;
317230130Smav		case 32:
318230130Smav			patch = "as=8 seq=4";
319230130Smav			break;
320230130Smav		case 34:
321230130Smav			patch = "as=8 seq=5";
322230130Smav			break;
323230130Smav		case 36:
324230130Smav			patch = "as=8 seq=6";
325230130Smav			break;
326230130Smav		}
327230130Smav	} else if (id == HDA_CODEC_ALC260 &&
328230130Smav	    HDA_DEV_MATCH(SONY_S5_SUBVENDOR, subid)) {
329230130Smav		switch (nid) {
330230130Smav		case 16:
331230130Smav			patch = "seq=15 device=Headphones";
332230130Smav			break;
333230130Smav		}
334230130Smav	} else if (id == HDA_CODEC_ALC268) {
335230130Smav	    if (subid == ACER_T5320_SUBVENDOR) {
336230130Smav		switch (nid) {
337230130Smav		case 20: /* Headphones Jack */
338230130Smav			patch = "as=1 seq=15";
339230130Smav			break;
340230130Smav		}
341230130Smav	    }
342230130Smav	} else if (id == HDA_CODEC_CX20561 &&
343230130Smav	    subid == LENOVO_B450_SUBVENDOR) {
344230130Smav		switch (nid) {
345230130Smav		case 22:
346230130Smav			patch = "as=1 seq=15";
347230130Smav			break;
348230130Smav		}
349269152Sadrian	} else if (id == HDA_CODEC_CX20561 &&
350269152Sadrian	    subid == LENOVO_T400_SUBVENDOR) {
351269152Sadrian		switch (nid) {
352269152Sadrian		case 22:
353269152Sadrian			patch = "as=1 seq=15";
354269152Sadrian			break;
355269152Sadrian		case 26:
356269152Sadrian			patch = "as=1 seq=0";
357269152Sadrian			break;
358269152Sadrian		}
359247815Smav	} else if (id == HDA_CODEC_CX20590 &&
360247911Sglebius	    (subid == LENOVO_X1_SUBVENDOR ||
361247911Sglebius	    subid == LENOVO_X220_SUBVENDOR ||
362247911Sglebius	    subid == LENOVO_T420_SUBVENDOR ||
363268584Smarkj	    subid == LENOVO_T520_SUBVENDOR ||
364268584Smarkj	    subid == LENOVO_G580_SUBVENDOR)) {
365247815Smav		switch (nid) {
366247815Smav		case 25:
367247815Smav			patch = "as=1 seq=15";
368247815Smav			break;
369264831Smarius		/*
370250797Ssbruno		 * Group onboard mic and headphone mic
371250797Ssbruno		 * together.  Fixes onboard mic.
372250797Ssbruno		 */
373250797Ssbruno		case 27:
374250797Ssbruno			patch = "as=2 seq=15";
375250797Ssbruno			break;
376250797Ssbruno		case 35:
377250797Ssbruno			patch = "as=2";
378250797Ssbruno			break;
379247815Smav		}
380247911Sglebius	} else if (id == HDA_CODEC_ALC269 &&
381248187Sglebius	    (subid == LENOVO_X1CRBN_SUBVENDOR ||
382248187Sglebius	    subid == LENOVO_T430_SUBVENDOR ||
383248254Sdelphij	    subid == LENOVO_T430S_SUBVENDOR ||
384248254Sdelphij	    subid == LENOVO_T530_SUBVENDOR)) {
385247911Sglebius		switch (nid) {
386247911Sglebius		case 21:
387247911Sglebius			patch = "as=1 seq=15";
388247911Sglebius			break;
389247911Sglebius		}
390253036Smav	} else if (id == HDA_CODEC_ALC269 &&
391253036Smav	    subid == ASUS_UX31A_SUBVENDOR) {
392253036Smav		switch (nid) {
393253036Smav		case 33:
394253036Smav			patch = "as=1 seq=15";
395253036Smav			break;
396253036Smav		}
397264831Smarius	} else if (id == HDA_CODEC_ALC892 &&
398264831Smarius	    subid == INTEL_DH87RL_SUBVENDOR) {
399264831Smarius		switch (nid) {
400264831Smarius		case 27:
401264831Smarius			patch = "as=1 seq=15";
402264831Smarius			break;
403264831Smarius		}
404281544Srpaulo	} else if (id == HDA_CODEC_ALC292 &&
405281544Srpaulo	    subid == LENOVO_X120BS_SUBVENDOR) {
406281544Srpaulo		switch (nid) {
407281544Srpaulo		case 21:
408281544Srpaulo			patch = "as=1 seq=15";
409281544Srpaulo			break;
410281544Srpaulo		}
411230130Smav	}
412230130Smav
413230130Smav	if (patch != NULL)
414230130Smav		config = hdaa_widget_pin_patch(config, patch);
415230130Smav	HDA_BOOTVERBOSE(
416230130Smav		if (config != orig)
417230130Smav			device_printf(w->devinfo->dev,
418230130Smav			    "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
419230130Smav			    nid, orig, config);
420230130Smav	);
421230130Smav	w->wclass.pin.config = config;
422230130Smav}
423230130Smav
424230130Smavstatic void
425230130Smavhdaa_widget_patch(struct hdaa_widget *w)
426230130Smav{
427230130Smav	struct hdaa_devinfo *devinfo = w->devinfo;
428230130Smav	uint32_t orig;
429230130Smav	nid_t beeper = -1;
430230130Smav
431230130Smav	orig = w->param.widget_cap;
432230130Smav	/* On some codecs beeper is an input pin, but it is not recordable
433230130Smav	   alone. Also most of BIOSes does not declare beeper pin.
434230130Smav	   Change beeper pin node type to beeper to help parser. */
435230130Smav	switch (hdaa_codec_id(devinfo)) {
436230130Smav	case HDA_CODEC_AD1882:
437230130Smav	case HDA_CODEC_AD1883:
438230130Smav	case HDA_CODEC_AD1984:
439230130Smav	case HDA_CODEC_AD1984A:
440230130Smav	case HDA_CODEC_AD1984B:
441230130Smav	case HDA_CODEC_AD1987:
442230130Smav	case HDA_CODEC_AD1988:
443230130Smav	case HDA_CODEC_AD1988B:
444230130Smav	case HDA_CODEC_AD1989B:
445230130Smav		beeper = 26;
446230130Smav		break;
447230130Smav	case HDA_CODEC_ALC260:
448230130Smav		beeper = 23;
449230130Smav		break;
450230130Smav	}
451230130Smav	if (hda_get_vendor_id(devinfo->dev) == REALTEK_VENDORID &&
452230130Smav	    hdaa_codec_id(devinfo) != HDA_CODEC_ALC260)
453230130Smav		beeper = 29;
454230130Smav	if (w->nid == beeper) {
455230130Smav		w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
456230130Smav		w->param.widget_cap |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
457230130Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
458230130Smav		w->waspin = 1;
459230130Smav	}
460244145Smav	/*
461244145Smav	 * Clear "digital" flag from digital mic input, as its signal then goes
462244145Smav	 * to "analog" mixer and this separation just limits functionaity.
463244145Smav	 */
464244145Smav	if (hdaa_codec_id(devinfo) == HDA_CODEC_AD1984A &&
465244145Smav	    w->nid == 23)
466244145Smav		w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK;
467230130Smav	HDA_BOOTVERBOSE(
468230130Smav		if (w->param.widget_cap != orig) {
469230130Smav			device_printf(w->devinfo->dev,
470230130Smav			    "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
471230130Smav			    w->nid, orig, w->param.widget_cap);
472230130Smav		}
473230130Smav	);
474230130Smav
475230130Smav	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
476230130Smav		hdac_pin_patch(w);
477230130Smav}
478230130Smav
479230130Smavvoid
480230130Smavhdaa_patch(struct hdaa_devinfo *devinfo)
481230130Smav{
482230130Smav	struct hdaa_widget *w;
483248786Smav	uint32_t id, subid, subsystemid;
484230130Smav	int i;
485230130Smav
486230130Smav	id = hdaa_codec_id(devinfo);
487242352Smav	subid = hdaa_card_id(devinfo);
488248786Smav	subsystemid = hda_get_subsystem_id(devinfo->dev);
489230130Smav
490230130Smav	/*
491230130Smav	 * Quirks
492230130Smav	 */
493261508Shselasky	for (i = 0; i < nitems(hdac_quirks); i++) {
494230130Smav		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subid) &&
495248786Smav		    HDA_DEV_MATCH(hdac_quirks[i].id, id) &&
496248786Smav		    HDA_DEV_MATCH(hdac_quirks[i].subsystemid, subsystemid)))
497230130Smav			continue;
498238011Smav		devinfo->quirks |= hdac_quirks[i].set;
499238011Smav		devinfo->quirks &= ~(hdac_quirks[i].unset);
500238011Smav		devinfo->gpio = hdac_quirks[i].gpio;
501230130Smav	}
502230130Smav
503230130Smav	/* Apply per-widget patch. */
504230130Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
505230130Smav		w = hdaa_widget_get(devinfo, i);
506230130Smav		if (w == NULL)
507230130Smav			continue;
508230130Smav		hdaa_widget_patch(w);
509230130Smav	}
510230130Smav
511230130Smav	switch (id) {
512230130Smav	case HDA_CODEC_AD1983:
513230130Smav		/*
514230130Smav		 * This CODEC has several possible usages, but none
515230130Smav		 * fit the parser best. Help parser to choose better.
516230130Smav		 */
517230130Smav		/* Disable direct unmixed playback to get pcm volume. */
518230130Smav		w = hdaa_widget_get(devinfo, 5);
519230130Smav		if (w != NULL)
520230130Smav			w->connsenable[0] = 0;
521230130Smav		w = hdaa_widget_get(devinfo, 6);
522230130Smav		if (w != NULL)
523230130Smav			w->connsenable[0] = 0;
524230130Smav		w = hdaa_widget_get(devinfo, 11);
525230130Smav		if (w != NULL)
526230130Smav			w->connsenable[0] = 0;
527230130Smav		/* Disable mic and line selectors. */
528230130Smav		w = hdaa_widget_get(devinfo, 12);
529230130Smav		if (w != NULL)
530230130Smav			w->connsenable[1] = 0;
531230130Smav		w = hdaa_widget_get(devinfo, 13);
532230130Smav		if (w != NULL)
533230130Smav			w->connsenable[1] = 0;
534230130Smav		/* Disable recording from mono playback mix. */
535230130Smav		w = hdaa_widget_get(devinfo, 20);
536230130Smav		if (w != NULL)
537230130Smav			w->connsenable[3] = 0;
538230130Smav		break;
539230130Smav	case HDA_CODEC_AD1986A:
540230130Smav		/*
541230130Smav		 * This CODEC has overcomplicated input mixing.
542230130Smav		 * Make some cleaning there.
543230130Smav		 */
544230130Smav		/* Disable input mono mixer. Not needed and not supported. */
545230130Smav		w = hdaa_widget_get(devinfo, 43);
546230130Smav		if (w != NULL)
547230130Smav			w->enable = 0;
548230130Smav		/* Disable any with any input mixing mesh. Use separately. */
549230130Smav		w = hdaa_widget_get(devinfo, 39);
550230130Smav		if (w != NULL)
551230130Smav			w->enable = 0;
552230130Smav		w = hdaa_widget_get(devinfo, 40);
553230130Smav		if (w != NULL)
554230130Smav			w->enable = 0;
555230130Smav		w = hdaa_widget_get(devinfo, 41);
556230130Smav		if (w != NULL)
557230130Smav			w->enable = 0;
558230130Smav		w = hdaa_widget_get(devinfo, 42);
559230130Smav		if (w != NULL)
560230130Smav			w->enable = 0;
561230130Smav		/* Disable duplicate mixer node connector. */
562230130Smav		w = hdaa_widget_get(devinfo, 15);
563230130Smav		if (w != NULL)
564230130Smav			w->connsenable[3] = 0;
565230130Smav		/* There is only one mic preamplifier, use it effectively. */
566230130Smav		w = hdaa_widget_get(devinfo, 31);
567230130Smav		if (w != NULL) {
568230130Smav			if ((w->wclass.pin.config &
569230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
570230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
571230130Smav				w = hdaa_widget_get(devinfo, 16);
572230130Smav				if (w != NULL)
573230130Smav				    w->connsenable[2] = 0;
574230130Smav			} else {
575230130Smav				w = hdaa_widget_get(devinfo, 15);
576230130Smav				if (w != NULL)
577230130Smav				    w->connsenable[0] = 0;
578230130Smav			}
579230130Smav		}
580230130Smav		w = hdaa_widget_get(devinfo, 32);
581230130Smav		if (w != NULL) {
582230130Smav			if ((w->wclass.pin.config &
583230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
584230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
585230130Smav				w = hdaa_widget_get(devinfo, 16);
586230130Smav				if (w != NULL)
587230130Smav				    w->connsenable[0] = 0;
588230130Smav			} else {
589230130Smav				w = hdaa_widget_get(devinfo, 15);
590230130Smav				if (w != NULL)
591230130Smav				    w->connsenable[1] = 0;
592230130Smav			}
593230130Smav		}
594230130Smav
595230130Smav		if (subid == ASUS_A8X_SUBVENDOR) {
596230130Smav			/*
597230130Smav			 * This is just plain ridiculous.. There
598230130Smav			 * are several A8 series that share the same
599230130Smav			 * pci id but works differently (EAPD).
600230130Smav			 */
601230130Smav			w = hdaa_widget_get(devinfo, 26);
602230130Smav			if (w != NULL && w->type ==
603230130Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
604230130Smav			    (w->wclass.pin.config &
605230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
606230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
607230130Smav				devinfo->quirks &=
608230130Smav				    ~HDAA_QUIRK_EAPDINV;
609230130Smav		}
610230130Smav		break;
611230130Smav	case HDA_CODEC_AD1981HD:
612230130Smav		/*
613230130Smav		 * This CODEC has very unusual design with several
614230130Smav		 * points inappropriate for the present parser.
615230130Smav		 */
616230130Smav		/* Disable recording from mono playback mix. */
617230130Smav		w = hdaa_widget_get(devinfo, 21);
618230130Smav		if (w != NULL)
619230130Smav			w->connsenable[3] = 0;
620230130Smav		/* Disable rear to front mic mixer, use separately. */
621230130Smav		w = hdaa_widget_get(devinfo, 31);
622230130Smav		if (w != NULL)
623230130Smav			w->enable = 0;
624230130Smav		/* Disable direct playback, use mixer. */
625230130Smav		w = hdaa_widget_get(devinfo, 5);
626230130Smav		if (w != NULL)
627230130Smav			w->connsenable[0] = 0;
628230130Smav		w = hdaa_widget_get(devinfo, 6);
629230130Smav		if (w != NULL)
630230130Smav			w->connsenable[0] = 0;
631230130Smav		w = hdaa_widget_get(devinfo, 9);
632230130Smav		if (w != NULL)
633230130Smav			w->connsenable[0] = 0;
634230130Smav		w = hdaa_widget_get(devinfo, 24);
635230130Smav		if (w != NULL)
636230130Smav			w->connsenable[0] = 0;
637230130Smav		break;
638242417Smav	case HDA_CODEC_ALC269:
639242417Smav		/*
640242417Smav		 * ASUS EeePC 1001px has strange variant of ALC269 CODEC,
641242417Smav		 * that mutes speaker if unused mixer at NID 15 is muted.
642242417Smav		 * Probably CODEC incorrectly reports internal connections.
643242417Smav		 * Hide that muter from the driver.  There are several CODECs
644242417Smav		 * sharing this ID and I have not enough information about
645242417Smav		 * them to implement more universal solution.
646242417Smav		 */
647242417Smav		if (subid == 0x84371043) {
648242417Smav			w = hdaa_widget_get(devinfo, 15);
649242417Smav			if (w != NULL)
650242417Smav				w->param.inamp_cap = 0;
651242417Smav		}
652242417Smav		break;
653230130Smav	case HDA_CODEC_CX20582:
654230130Smav	case HDA_CODEC_CX20583:
655230130Smav	case HDA_CODEC_CX20584:
656230130Smav	case HDA_CODEC_CX20585:
657230130Smav	case HDA_CODEC_CX20590:
658230130Smav		/*
659230130Smav		 * These codecs have extra connectivity on record side
660230130Smav		 * too reach for the present parser.
661230130Smav		 */
662230130Smav		w = hdaa_widget_get(devinfo, 20);
663230130Smav		if (w != NULL)
664230130Smav			w->connsenable[1] = 0;
665230130Smav		w = hdaa_widget_get(devinfo, 21);
666230130Smav		if (w != NULL)
667230130Smav			w->connsenable[1] = 0;
668230130Smav		w = hdaa_widget_get(devinfo, 22);
669230130Smav		if (w != NULL)
670230130Smav			w->connsenable[0] = 0;
671230130Smav		break;
672230130Smav	case HDA_CODEC_VT1708S_0:
673230130Smav	case HDA_CODEC_VT1708S_1:
674230130Smav	case HDA_CODEC_VT1708S_2:
675230130Smav	case HDA_CODEC_VT1708S_3:
676230130Smav	case HDA_CODEC_VT1708S_4:
677230130Smav	case HDA_CODEC_VT1708S_5:
678230130Smav	case HDA_CODEC_VT1708S_6:
679230130Smav	case HDA_CODEC_VT1708S_7:
680230130Smav		/*
681230130Smav		 * These codecs have hidden mic boost controls.
682230130Smav		 */
683230130Smav		w = hdaa_widget_get(devinfo, 26);
684230130Smav		if (w != NULL)
685230130Smav			w->param.inamp_cap =
686230130Smav			    (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
687230130Smav			    (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
688230130Smav			    (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
689230130Smav		w = hdaa_widget_get(devinfo, 30);
690230130Smav		if (w != NULL)
691230130Smav			w->param.inamp_cap =
692230130Smav			    (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
693230130Smav			    (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
694230130Smav			    (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
695230130Smav		break;
696230130Smav	}
697230130Smav}
698230130Smav
699285723Smavstatic uint32_t
700285723Smavhdaa_read_coef(device_t dev, nid_t nid, uint16_t idx)
701285723Smav{
702285723Smav
703285723Smav	hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, nid, idx));
704285723Smav	return (hda_command(dev, HDA_CMD_GET_PROCESSING_COEFF(0, nid)));
705285723Smav}
706285723Smav
707285723Smavstatic uint32_t
708285723Smavhdaa_write_coef(device_t dev, nid_t nid, uint16_t idx, uint16_t val)
709285723Smav{
710285723Smav
711285723Smav	hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, nid, idx));
712285723Smav	return (hda_command(dev, HDA_CMD_SET_PROCESSING_COEFF(0, nid, val)));
713285723Smav}
714285723Smav
715230130Smavvoid
716230130Smavhdaa_patch_direct(struct hdaa_devinfo *devinfo)
717230130Smav{
718230130Smav	device_t dev = devinfo->dev;
719230130Smav	uint32_t id, subid, val;
720230130Smav
721230130Smav	id = hdaa_codec_id(devinfo);
722242352Smav	subid = hdaa_card_id(devinfo);
723230130Smav
724230130Smav	switch (id) {
725230130Smav	case HDA_CODEC_VT1708S_0:
726230130Smav	case HDA_CODEC_VT1708S_1:
727230130Smav	case HDA_CODEC_VT1708S_2:
728230130Smav	case HDA_CODEC_VT1708S_3:
729230130Smav	case HDA_CODEC_VT1708S_4:
730230130Smav	case HDA_CODEC_VT1708S_5:
731230130Smav	case HDA_CODEC_VT1708S_6:
732230130Smav	case HDA_CODEC_VT1708S_7:
733230130Smav		/* Enable Mic Boost Volume controls. */
734230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
735230130Smav		    0xf98, 0x01));
736241375Smav		/* Fall though */
737241375Smav	case HDA_CODEC_VT1818S:
738230130Smav		/* Don't bypass mixer. */
739230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
740230130Smav		    0xf88, 0xc0));
741230130Smav		break;
742230130Smav	}
743230130Smav	if (subid == APPLE_INTEL_MAC)
744230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
745230130Smav		    0x7e7, 0));
746230130Smav	if (id == HDA_CODEC_ALC269) {
747230532Smav		if (subid == 0x16e31043 || subid == 0x831a1043 ||
748230532Smav		    subid == 0x834a1043 || subid == 0x83981043 ||
749230532Smav		    subid == 0x83ce1043) {
750230130Smav			/*
751230130Smav			 * The ditital mics on some Asus laptops produce
752230130Smav			 * differential signals instead of expected stereo.
753230130Smav			 * That results in silence if downmix it to mono.
754230130Smav			 * To workaround, make codec to handle signal as mono.
755230130Smav			 */
756285723Smav			val = hdaa_read_coef(dev, 0x20, 0x07);
757285723Smav			hdaa_write_coef(dev, 0x20, 0x07, val|0x80);
758230130Smav		}
759285723Smav		if (subid == 0x15171043) {
760285723Smav			/* Increase output amp on ASUS UX31A by +5dB. */
761285723Smav			hdaa_write_coef(dev, 0x20, 0x12, 0x2800);
762285723Smav		}
763230130Smav	}
764230130Smav}
765