hdaa_patches.c revision 252148
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: stable/9/sys/dev/sound/pci/hda/hdaa_patches.c 252148 2013-06-24 09:20:14Z glebius $");
46230130Smav
47230130Smavstatic const struct {
48230130Smav	uint32_t model;
49230130Smav	uint32_t id;
50230130Smav	uint32_t set, unset;
51230130Smav	uint32_t gpio;
52230130Smav} hdac_quirks[] = {
53230130Smav	/*
54230130Smav	 * XXX Force stereo quirk. Monoural recording / playback
55230130Smav	 *     on few codecs (especially ALC880) seems broken or
56230130Smav	 *     perhaps unsupported.
57230130Smav	 */
58230130Smav	{ HDA_MATCH_ALL, HDA_MATCH_ALL,
59230130Smav	    HDAA_QUIRK_FORCESTEREO | HDAA_QUIRK_IVREF, 0,
60230130Smav	    0 },
61230130Smav	{ ACER_ALL_SUBVENDOR, HDA_MATCH_ALL,
62230130Smav	    0, 0,
63230130Smav	    HDAA_GPIO_SET(0) },
64230130Smav	{ ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660,
65230130Smav	    0, 0,
66230130Smav	    HDAA_GPIO_SET(0) },
67230130Smav	{ ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880,
68230130Smav	    0, 0,
69230130Smav	    HDAA_GPIO_SET(0) },
70230130Smav	{ ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880,
71230130Smav	    0, 0,
72230130Smav	    HDAA_GPIO_SET(0) },
73230130Smav	{ ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882,
74230130Smav	    0, 0,
75230130Smav	    HDAA_GPIO_SET(0) },
76230130Smav	{ ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882,
77230130Smav	    0, 0,
78230130Smav	    HDAA_GPIO_SET(0) },
79230130Smav	{ ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A,
80230130Smav	    HDAA_QUIRK_EAPDINV, 0,
81230130Smav	    0 },
82230130Smav	{ ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A,
83230130Smav	    HDAA_QUIRK_EAPDINV, 0,
84230130Smav	    0 },
85230130Smav	{ ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861,
86230130Smav	    HDAA_QUIRK_OVREF, 0,
87230130Smav	    0 },
88230130Smav	{ UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861,
89230130Smav	    HDAA_QUIRK_OVREF, 0,
90230130Smav	    0 },
91230130Smav	/*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988,
92230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
93230130Smav	    0 },*/
94230130Smav	{ MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880,
95230130Smav	    0, 0,
96230130Smav	    HDAA_GPIO_SET(1) },
97230130Smav	{ LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A,
98230130Smav	    HDAA_QUIRK_EAPDINV | HDAA_QUIRK_SENSEINV, 0,
99230130Smav	    0 },
100230130Smav	{ SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A,
101230130Smav	    HDAA_QUIRK_EAPDINV, 0,
102230130Smav	    0 },
103230130Smav	{ APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885,
104230130Smav	    HDAA_QUIRK_OVREF50, 0,
105230130Smav	    HDAA_GPIO_SET(0) },
106230130Smav	{ APPLE_INTEL_MAC, HDA_CODEC_STAC9221,
107230130Smav	    0, 0,
108230130Smav	    HDAA_GPIO_SET(0) | HDAA_GPIO_SET(1) },
109230130Smav	{ APPLE_MACBOOKPRO55, HDA_CODEC_CS4206,
110230130Smav	    0, 0,
111230130Smav	    HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
112230130Smav	{ DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X,
113230130Smav	    0, 0,
114230130Smav	    HDAA_GPIO_SET(0) },
115230130Smav	{ DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X,
116230130Smav	    0, 0,
117230130Smav	    HDAA_GPIO_SET(2) },
118230130Smav	{ DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X,
119230130Smav	    0, 0,
120230130Smav	    HDAA_GPIO_SET(0) },
121230130Smav	{ HDA_MATCH_ALL, HDA_CODEC_AD1988,
122230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
123230130Smav	    0 },
124230130Smav	{ HDA_MATCH_ALL, HDA_CODEC_AD1988B,
125230130Smav	    HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
126230130Smav	    0 },
127230130Smav	{ HDA_MATCH_ALL, HDA_CODEC_CX20549,
128230130Smav	    0, HDAA_QUIRK_FORCESTEREO,
129230130Smav	    0 }
130230130Smav};
131230130Smav#define HDAC_QUIRKS_LEN (sizeof(hdac_quirks) / sizeof(hdac_quirks[0]))
132230130Smav
133230130Smavstatic void
134230130Smavhdac_pin_patch(struct hdaa_widget *w)
135230130Smav{
136230130Smav	const char *patch = NULL;
137230130Smav	uint32_t config, orig, id, subid;
138230130Smav	nid_t nid = w->nid;
139230130Smav
140230130Smav	config = orig = w->wclass.pin.config;
141230130Smav	id = hdaa_codec_id(w->devinfo);
142243060Smav	subid = hdaa_card_id(w->devinfo);
143230130Smav
144230130Smav	/* XXX: Old patches require complete review.
145230130Smav	 * Now they may create more problem then solve due to
146230130Smav	 * incorrect associations.
147230130Smav	 */
148230130Smav	if (id == HDA_CODEC_ALC880 && subid == LG_LW20_SUBVENDOR) {
149230130Smav		switch (nid) {
150230130Smav		case 26:
151230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
152230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
153230130Smav			break;
154230130Smav		case 27:
155230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
156230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
157230130Smav			break;
158230130Smav		default:
159230130Smav			break;
160230130Smav		}
161230130Smav	} else if (id == HDA_CODEC_ALC880 &&
162230130Smav	    (subid == CLEVO_D900T_SUBVENDOR ||
163230130Smav	    subid == ASUS_M5200_SUBVENDOR)) {
164230130Smav		/*
165230130Smav		 * Super broken BIOS
166230130Smav		 */
167230130Smav		switch (nid) {
168230130Smav		case 24:	/* MIC1 */
169230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
170230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
171230130Smav			break;
172230130Smav		case 25:	/* XXX MIC2 */
173230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
174230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
175230130Smav			break;
176230130Smav		case 26:	/* LINE1 */
177230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
178230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
179230130Smav			break;
180230130Smav		case 27:	/* XXX LINE2 */
181230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
182230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
183230130Smav			break;
184230130Smav		case 28:	/* CD */
185230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
186230130Smav			config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
187230130Smav			break;
188230130Smav		}
189230130Smav	} else if (id == HDA_CODEC_ALC883 &&
190230130Smav	    (subid == MSI_MS034A_SUBVENDOR ||
191230130Smav	    HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subid))) {
192230130Smav		switch (nid) {
193230130Smav		case 25:
194230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
195230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
196230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
197230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
198230130Smav			break;
199230130Smav		case 28:
200230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
201230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
202230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
203230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
204230130Smav			break;
205230130Smav		}
206230130Smav	} else if (id == HDA_CODEC_CX20549 && subid ==
207230130Smav	    HP_V3000_SUBVENDOR) {
208230130Smav		switch (nid) {
209230130Smav		case 18:
210230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
211230130Smav			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
212230130Smav			break;
213230130Smav		case 20:
214230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
215230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
216230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
217230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
218230130Smav			break;
219230130Smav		case 21:
220230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
221230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
222230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
223230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
224230130Smav			break;
225230130Smav		}
226230130Smav	} else if (id == HDA_CODEC_CX20551 && subid ==
227230130Smav	    HP_DV5000_SUBVENDOR) {
228230130Smav		switch (nid) {
229230130Smav		case 20:
230230130Smav		case 21:
231230130Smav			config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
232230130Smav			config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
233230130Smav			break;
234230130Smav		}
235230130Smav	} else if (id == HDA_CODEC_ALC861 && subid ==
236230130Smav	    ASUS_W6F_SUBVENDOR) {
237230130Smav		switch (nid) {
238230130Smav		case 11:
239230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
240230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
241230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
242230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
243230130Smav			break;
244230130Smav		case 12:
245230130Smav		case 14:
246230130Smav		case 16:
247230130Smav		case 31:
248230130Smav		case 32:
249230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
250230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
251230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
252230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
253230130Smav			break;
254230130Smav		case 15:
255230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
256230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
257230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
258230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
259230130Smav			break;
260230130Smav		}
261230130Smav	} else if (id == HDA_CODEC_ALC861 && subid ==
262230130Smav	    UNIWILL_9075_SUBVENDOR) {
263230130Smav		switch (nid) {
264230130Smav		case 15:
265230130Smav			config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
266230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
267230130Smav			config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
268230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
269230130Smav			break;
270230130Smav		}
271230130Smav	}
272230130Smav
273230130Smav	/* New patches */
274244712Smav	if (id == HDA_CODEC_AD1984A &&
275244712Smav	    subid == LENOVO_X300_SUBVENDOR) {
276244712Smav		switch (nid) {
277244712Smav		case 17: /* Headphones with redirection */
278244712Smav			patch = "as=1 seq=15";
279244712Smav			break;
280244712Smav		case 20: /* Two mics together */
281244712Smav			patch = "as=2 seq=15";
282244712Smav			break;
283244712Smav		}
284244712Smav	} else if (id == HDA_CODEC_AD1986A &&
285230130Smav	    (subid == ASUS_M2NPVMX_SUBVENDOR ||
286230130Smav	    subid == ASUS_A8NVMCSM_SUBVENDOR ||
287230130Smav	    subid == ASUS_P5PL2_SUBVENDOR)) {
288230130Smav		switch (nid) {
289230130Smav		case 26: /* Headphones with redirection */
290230130Smav			patch = "as=1 seq=15";
291230130Smav			break;
292230130Smav		case 28: /* 5.1 out => 2.0 out + 1 input */
293230130Smav			patch = "device=Line-in as=8 seq=1";
294230130Smav			break;
295230130Smav		case 29: /* Can't use this as input, as the only available mic
296230130Smav			  * preamplifier is busy by front panel mic (nid 31).
297230130Smav			  * If you want to use this rear connector as mic input,
298230130Smav			  * you have to disable the front panel one. */
299230130Smav			patch = "as=0";
300230130Smav			break;
301230130Smav		case 31: /* Lot of inputs configured with as=15 and unusable */
302230130Smav			patch = "as=8 seq=3";
303230130Smav			break;
304230130Smav		case 32:
305230130Smav			patch = "as=8 seq=4";
306230130Smav			break;
307230130Smav		case 34:
308230130Smav			patch = "as=8 seq=5";
309230130Smav			break;
310230130Smav		case 36:
311230130Smav			patch = "as=8 seq=6";
312230130Smav			break;
313230130Smav		}
314230130Smav	} else if (id == HDA_CODEC_ALC260 &&
315230130Smav	    HDA_DEV_MATCH(SONY_S5_SUBVENDOR, subid)) {
316230130Smav		switch (nid) {
317230130Smav		case 16:
318230130Smav			patch = "seq=15 device=Headphones";
319230130Smav			break;
320230130Smav		}
321230130Smav	} else if (id == HDA_CODEC_ALC268) {
322230130Smav	    if (subid == ACER_T5320_SUBVENDOR) {
323230130Smav		switch (nid) {
324230130Smav		case 20: /* Headphones Jack */
325230130Smav			patch = "as=1 seq=15";
326230130Smav			break;
327230130Smav		}
328230130Smav	    }
329230130Smav	} else if (id == HDA_CODEC_CX20561 &&
330230130Smav	    subid == LENOVO_B450_SUBVENDOR) {
331230130Smav		switch (nid) {
332230130Smav		case 22:
333230130Smav			patch = "as=1 seq=15";
334230130Smav			break;
335230130Smav		}
336248148Smav	} else if (id == HDA_CODEC_CX20590 &&
337252148Sglebius	    (subid == LENOVO_X1_SUBVENDOR ||
338252148Sglebius	    subid == LENOVO_X220_SUBVENDOR ||
339252148Sglebius	    subid == LENOVO_T420_SUBVENDOR ||
340252148Sglebius	    subid == LENOVO_T520_SUBVENDOR)) {
341248148Smav		switch (nid) {
342248148Smav		case 25:
343248148Smav			patch = "as=1 seq=15";
344248148Smav			break;
345252148Sglebius		/*
346252148Sglebius		 * Group onboard mic and headphone mic
347252148Sglebius		 * together.  Fixes onboard mic.
348252148Sglebius		 */
349252148Sglebius		case 27:
350252148Sglebius			patch = "as=2 seq=15";
351252148Sglebius			break;
352252148Sglebius		case 35:
353252148Sglebius			patch = "as=2";
354252148Sglebius			break;
355248148Smav		}
356252148Sglebius	} else if (id == HDA_CODEC_ALC269 &&
357252148Sglebius	    (subid == LENOVO_X1CRBN_SUBVENDOR ||
358252148Sglebius	    subid == LENOVO_T430_SUBVENDOR ||
359252148Sglebius	    subid == LENOVO_T430S_SUBVENDOR ||
360252148Sglebius	    subid == LENOVO_T530_SUBVENDOR)) {
361252148Sglebius		switch (nid) {
362252148Sglebius		case 21:
363252148Sglebius			patch = "as=1 seq=15";
364252148Sglebius			break;
365252148Sglebius		}
366230130Smav	}
367230130Smav
368230130Smav	if (patch != NULL)
369230130Smav		config = hdaa_widget_pin_patch(config, patch);
370230130Smav	HDA_BOOTVERBOSE(
371230130Smav		if (config != orig)
372230130Smav			device_printf(w->devinfo->dev,
373230130Smav			    "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
374230130Smav			    nid, orig, config);
375230130Smav	);
376230130Smav	w->wclass.pin.config = config;
377230130Smav}
378230130Smav
379230130Smavstatic void
380230130Smavhdaa_widget_patch(struct hdaa_widget *w)
381230130Smav{
382230130Smav	struct hdaa_devinfo *devinfo = w->devinfo;
383230130Smav	uint32_t orig;
384230130Smav	nid_t beeper = -1;
385230130Smav
386230130Smav	orig = w->param.widget_cap;
387230130Smav	/* On some codecs beeper is an input pin, but it is not recordable
388230130Smav	   alone. Also most of BIOSes does not declare beeper pin.
389230130Smav	   Change beeper pin node type to beeper to help parser. */
390230130Smav	switch (hdaa_codec_id(devinfo)) {
391230130Smav	case HDA_CODEC_AD1882:
392230130Smav	case HDA_CODEC_AD1883:
393230130Smav	case HDA_CODEC_AD1984:
394230130Smav	case HDA_CODEC_AD1984A:
395230130Smav	case HDA_CODEC_AD1984B:
396230130Smav	case HDA_CODEC_AD1987:
397230130Smav	case HDA_CODEC_AD1988:
398230130Smav	case HDA_CODEC_AD1988B:
399230130Smav	case HDA_CODEC_AD1989B:
400230130Smav		beeper = 26;
401230130Smav		break;
402230130Smav	case HDA_CODEC_ALC260:
403230130Smav		beeper = 23;
404230130Smav		break;
405230130Smav	}
406230130Smav	if (hda_get_vendor_id(devinfo->dev) == REALTEK_VENDORID &&
407230130Smav	    hdaa_codec_id(devinfo) != HDA_CODEC_ALC260)
408230130Smav		beeper = 29;
409230130Smav	if (w->nid == beeper) {
410230130Smav		w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
411230130Smav		w->param.widget_cap |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
412230130Smav		    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
413230130Smav		w->waspin = 1;
414230130Smav	}
415244712Smav	/*
416244712Smav	 * Clear "digital" flag from digital mic input, as its signal then goes
417244712Smav	 * to "analog" mixer and this separation just limits functionaity.
418244712Smav	 */
419244712Smav	if (hdaa_codec_id(devinfo) == HDA_CODEC_AD1984A &&
420244712Smav	    w->nid == 23)
421244712Smav		w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK;
422230130Smav	HDA_BOOTVERBOSE(
423230130Smav		if (w->param.widget_cap != orig) {
424230130Smav			device_printf(w->devinfo->dev,
425230130Smav			    "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
426230130Smav			    w->nid, orig, w->param.widget_cap);
427230130Smav		}
428230130Smav	);
429230130Smav
430230130Smav	if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
431230130Smav		hdac_pin_patch(w);
432230130Smav}
433230130Smav
434230130Smavvoid
435230130Smavhdaa_patch(struct hdaa_devinfo *devinfo)
436230130Smav{
437230130Smav	struct hdaa_widget *w;
438230130Smav	uint32_t id, subid;
439230130Smav	int i;
440230130Smav
441230130Smav	id = hdaa_codec_id(devinfo);
442243060Smav	subid = hdaa_card_id(devinfo);
443230130Smav
444230130Smav	/*
445230130Smav	 * Quirks
446230130Smav	 */
447230130Smav	for (i = 0; i < HDAC_QUIRKS_LEN; i++) {
448230130Smav		if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subid) &&
449230130Smav		    HDA_DEV_MATCH(hdac_quirks[i].id, id)))
450230130Smav			continue;
451238131Smav		devinfo->quirks |= hdac_quirks[i].set;
452238131Smav		devinfo->quirks &= ~(hdac_quirks[i].unset);
453238131Smav		devinfo->gpio = hdac_quirks[i].gpio;
454230130Smav	}
455230130Smav
456230130Smav	/* Apply per-widget patch. */
457230130Smav	for (i = devinfo->startnode; i < devinfo->endnode; i++) {
458230130Smav		w = hdaa_widget_get(devinfo, i);
459230130Smav		if (w == NULL)
460230130Smav			continue;
461230130Smav		hdaa_widget_patch(w);
462230130Smav	}
463230130Smav
464230130Smav	switch (id) {
465230130Smav	case HDA_CODEC_AD1983:
466230130Smav		/*
467230130Smav		 * This CODEC has several possible usages, but none
468230130Smav		 * fit the parser best. Help parser to choose better.
469230130Smav		 */
470230130Smav		/* Disable direct unmixed playback to get pcm volume. */
471230130Smav		w = hdaa_widget_get(devinfo, 5);
472230130Smav		if (w != NULL)
473230130Smav			w->connsenable[0] = 0;
474230130Smav		w = hdaa_widget_get(devinfo, 6);
475230130Smav		if (w != NULL)
476230130Smav			w->connsenable[0] = 0;
477230130Smav		w = hdaa_widget_get(devinfo, 11);
478230130Smav		if (w != NULL)
479230130Smav			w->connsenable[0] = 0;
480230130Smav		/* Disable mic and line selectors. */
481230130Smav		w = hdaa_widget_get(devinfo, 12);
482230130Smav		if (w != NULL)
483230130Smav			w->connsenable[1] = 0;
484230130Smav		w = hdaa_widget_get(devinfo, 13);
485230130Smav		if (w != NULL)
486230130Smav			w->connsenable[1] = 0;
487230130Smav		/* Disable recording from mono playback mix. */
488230130Smav		w = hdaa_widget_get(devinfo, 20);
489230130Smav		if (w != NULL)
490230130Smav			w->connsenable[3] = 0;
491230130Smav		break;
492230130Smav	case HDA_CODEC_AD1986A:
493230130Smav		/*
494230130Smav		 * This CODEC has overcomplicated input mixing.
495230130Smav		 * Make some cleaning there.
496230130Smav		 */
497230130Smav		/* Disable input mono mixer. Not needed and not supported. */
498230130Smav		w = hdaa_widget_get(devinfo, 43);
499230130Smav		if (w != NULL)
500230130Smav			w->enable = 0;
501230130Smav		/* Disable any with any input mixing mesh. Use separately. */
502230130Smav		w = hdaa_widget_get(devinfo, 39);
503230130Smav		if (w != NULL)
504230130Smav			w->enable = 0;
505230130Smav		w = hdaa_widget_get(devinfo, 40);
506230130Smav		if (w != NULL)
507230130Smav			w->enable = 0;
508230130Smav		w = hdaa_widget_get(devinfo, 41);
509230130Smav		if (w != NULL)
510230130Smav			w->enable = 0;
511230130Smav		w = hdaa_widget_get(devinfo, 42);
512230130Smav		if (w != NULL)
513230130Smav			w->enable = 0;
514230130Smav		/* Disable duplicate mixer node connector. */
515230130Smav		w = hdaa_widget_get(devinfo, 15);
516230130Smav		if (w != NULL)
517230130Smav			w->connsenable[3] = 0;
518230130Smav		/* There is only one mic preamplifier, use it effectively. */
519230130Smav		w = hdaa_widget_get(devinfo, 31);
520230130Smav		if (w != NULL) {
521230130Smav			if ((w->wclass.pin.config &
522230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
523230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
524230130Smav				w = hdaa_widget_get(devinfo, 16);
525230130Smav				if (w != NULL)
526230130Smav				    w->connsenable[2] = 0;
527230130Smav			} else {
528230130Smav				w = hdaa_widget_get(devinfo, 15);
529230130Smav				if (w != NULL)
530230130Smav				    w->connsenable[0] = 0;
531230130Smav			}
532230130Smav		}
533230130Smav		w = hdaa_widget_get(devinfo, 32);
534230130Smav		if (w != NULL) {
535230130Smav			if ((w->wclass.pin.config &
536230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
537230130Smav			    HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
538230130Smav				w = hdaa_widget_get(devinfo, 16);
539230130Smav				if (w != NULL)
540230130Smav				    w->connsenable[0] = 0;
541230130Smav			} else {
542230130Smav				w = hdaa_widget_get(devinfo, 15);
543230130Smav				if (w != NULL)
544230130Smav				    w->connsenable[1] = 0;
545230130Smav			}
546230130Smav		}
547230130Smav
548230130Smav		if (subid == ASUS_A8X_SUBVENDOR) {
549230130Smav			/*
550230130Smav			 * This is just plain ridiculous.. There
551230130Smav			 * are several A8 series that share the same
552230130Smav			 * pci id but works differently (EAPD).
553230130Smav			 */
554230130Smav			w = hdaa_widget_get(devinfo, 26);
555230130Smav			if (w != NULL && w->type ==
556230130Smav			    HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
557230130Smav			    (w->wclass.pin.config &
558230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
559230130Smav			    HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
560230130Smav				devinfo->quirks &=
561230130Smav				    ~HDAA_QUIRK_EAPDINV;
562230130Smav		}
563230130Smav		break;
564230130Smav	case HDA_CODEC_AD1981HD:
565230130Smav		/*
566230130Smav		 * This CODEC has very unusual design with several
567230130Smav		 * points inappropriate for the present parser.
568230130Smav		 */
569230130Smav		/* Disable recording from mono playback mix. */
570230130Smav		w = hdaa_widget_get(devinfo, 21);
571230130Smav		if (w != NULL)
572230130Smav			w->connsenable[3] = 0;
573230130Smav		/* Disable rear to front mic mixer, use separately. */
574230130Smav		w = hdaa_widget_get(devinfo, 31);
575230130Smav		if (w != NULL)
576230130Smav			w->enable = 0;
577230130Smav		/* Disable direct playback, use mixer. */
578230130Smav		w = hdaa_widget_get(devinfo, 5);
579230130Smav		if (w != NULL)
580230130Smav			w->connsenable[0] = 0;
581230130Smav		w = hdaa_widget_get(devinfo, 6);
582230130Smav		if (w != NULL)
583230130Smav			w->connsenable[0] = 0;
584230130Smav		w = hdaa_widget_get(devinfo, 9);
585230130Smav		if (w != NULL)
586230130Smav			w->connsenable[0] = 0;
587230130Smav		w = hdaa_widget_get(devinfo, 24);
588230130Smav		if (w != NULL)
589230130Smav			w->connsenable[0] = 0;
590230130Smav		break;
591243064Smav	case HDA_CODEC_ALC269:
592243064Smav		/*
593243064Smav		 * ASUS EeePC 1001px has strange variant of ALC269 CODEC,
594243064Smav		 * that mutes speaker if unused mixer at NID 15 is muted.
595243064Smav		 * Probably CODEC incorrectly reports internal connections.
596243064Smav		 * Hide that muter from the driver.  There are several CODECs
597243064Smav		 * sharing this ID and I have not enough information about
598243064Smav		 * them to implement more universal solution.
599243064Smav		 */
600243064Smav		if (subid == 0x84371043) {
601243064Smav			w = hdaa_widget_get(devinfo, 15);
602243064Smav			if (w != NULL)
603243064Smav				w->param.inamp_cap = 0;
604243064Smav		}
605243064Smav		break;
606230130Smav	case HDA_CODEC_CX20582:
607230130Smav	case HDA_CODEC_CX20583:
608230130Smav	case HDA_CODEC_CX20584:
609230130Smav	case HDA_CODEC_CX20585:
610230130Smav	case HDA_CODEC_CX20590:
611230130Smav		/*
612230130Smav		 * These codecs have extra connectivity on record side
613230130Smav		 * too reach for the present parser.
614230130Smav		 */
615230130Smav		w = hdaa_widget_get(devinfo, 20);
616230130Smav		if (w != NULL)
617230130Smav			w->connsenable[1] = 0;
618230130Smav		w = hdaa_widget_get(devinfo, 21);
619230130Smav		if (w != NULL)
620230130Smav			w->connsenable[1] = 0;
621230130Smav		w = hdaa_widget_get(devinfo, 22);
622230130Smav		if (w != NULL)
623230130Smav			w->connsenable[0] = 0;
624230130Smav		break;
625230130Smav	case HDA_CODEC_VT1708S_0:
626230130Smav	case HDA_CODEC_VT1708S_1:
627230130Smav	case HDA_CODEC_VT1708S_2:
628230130Smav	case HDA_CODEC_VT1708S_3:
629230130Smav	case HDA_CODEC_VT1708S_4:
630230130Smav	case HDA_CODEC_VT1708S_5:
631230130Smav	case HDA_CODEC_VT1708S_6:
632230130Smav	case HDA_CODEC_VT1708S_7:
633230130Smav		/*
634230130Smav		 * These codecs have hidden mic boost controls.
635230130Smav		 */
636230130Smav		w = hdaa_widget_get(devinfo, 26);
637230130Smav		if (w != NULL)
638230130Smav			w->param.inamp_cap =
639230130Smav			    (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
640230130Smav			    (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
641230130Smav			    (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
642230130Smav		w = hdaa_widget_get(devinfo, 30);
643230130Smav		if (w != NULL)
644230130Smav			w->param.inamp_cap =
645230130Smav			    (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
646230130Smav			    (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
647230130Smav			    (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
648230130Smav		break;
649230130Smav	}
650230130Smav}
651230130Smav
652230130Smavvoid
653230130Smavhdaa_patch_direct(struct hdaa_devinfo *devinfo)
654230130Smav{
655230130Smav	device_t dev = devinfo->dev;
656230130Smav	uint32_t id, subid, val;
657230130Smav
658230130Smav	id = hdaa_codec_id(devinfo);
659243060Smav	subid = hdaa_card_id(devinfo);
660230130Smav
661230130Smav	switch (id) {
662230130Smav	case HDA_CODEC_VT1708S_0:
663230130Smav	case HDA_CODEC_VT1708S_1:
664230130Smav	case HDA_CODEC_VT1708S_2:
665230130Smav	case HDA_CODEC_VT1708S_3:
666230130Smav	case HDA_CODEC_VT1708S_4:
667230130Smav	case HDA_CODEC_VT1708S_5:
668230130Smav	case HDA_CODEC_VT1708S_6:
669230130Smav	case HDA_CODEC_VT1708S_7:
670230130Smav		/* Enable Mic Boost Volume controls. */
671230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
672230130Smav		    0xf98, 0x01));
673241742Smav		/* Fall though */
674241742Smav	case HDA_CODEC_VT1818S:
675230130Smav		/* Don't bypass mixer. */
676230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
677230130Smav		    0xf88, 0xc0));
678230130Smav		break;
679230130Smav	}
680230130Smav	if (subid == APPLE_INTEL_MAC)
681230130Smav		hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
682230130Smav		    0x7e7, 0));
683230130Smav	if (id == HDA_CODEC_ALC269) {
684232798Smav		if (subid == 0x16e31043 || subid == 0x831a1043 ||
685232798Smav		    subid == 0x834a1043 || subid == 0x83981043 ||
686232798Smav		    subid == 0x83ce1043) {
687230130Smav			/*
688230130Smav			 * The ditital mics on some Asus laptops produce
689230130Smav			 * differential signals instead of expected stereo.
690230130Smav			 * That results in silence if downmix it to mono.
691230130Smav			 * To workaround, make codec to handle signal as mono.
692230130Smav			 */
693230130Smav			hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
694230130Smav			val = hda_command(dev, HDA_CMD_GET_PROCESSING_COEFF(0, 0x20));
695230130Smav			hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
696230130Smav			hda_command(dev, HDA_CMD_SET_PROCESSING_COEFF(0, 0x20, val|0x80));
697230130Smav		}
698230130Smav	}
699230130Smav}
700