12a1ad637SFrançois Tigeot /*-
22a1ad637SFrançois Tigeot * Copyright (c) 2006 Stephane E. Potvin <sepotvin@videotron.ca>
32a1ad637SFrançois Tigeot * Copyright (c) 2006 Ariff Abdullah <ariff@FreeBSD.org>
42a1ad637SFrançois Tigeot * Copyright (c) 2008-2012 Alexander Motin <mav@FreeBSD.org>
52a1ad637SFrançois Tigeot * All rights reserved.
62a1ad637SFrançois Tigeot *
72a1ad637SFrançois Tigeot * Redistribution and use in source and binary forms, with or without
82a1ad637SFrançois Tigeot * modification, are permitted provided that the following conditions
92a1ad637SFrançois Tigeot * are met:
102a1ad637SFrançois Tigeot * 1. Redistributions of source code must retain the above copyright
112a1ad637SFrançois Tigeot * notice, this list of conditions and the following disclaimer.
122a1ad637SFrançois Tigeot * 2. Redistributions in binary form must reproduce the above copyright
132a1ad637SFrançois Tigeot * notice, this list of conditions and the following disclaimer in the
142a1ad637SFrançois Tigeot * documentation and/or other materials provided with the distribution.
152a1ad637SFrançois Tigeot *
162a1ad637SFrançois Tigeot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
172a1ad637SFrançois Tigeot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182a1ad637SFrançois Tigeot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192a1ad637SFrançois Tigeot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
202a1ad637SFrançois Tigeot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212a1ad637SFrançois Tigeot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222a1ad637SFrançois Tigeot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232a1ad637SFrançois Tigeot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242a1ad637SFrançois Tigeot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252a1ad637SFrançois Tigeot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262a1ad637SFrançois Tigeot * SUCH DAMAGE.
272a1ad637SFrançois Tigeot */
282a1ad637SFrançois Tigeot
292a1ad637SFrançois Tigeot /*
302a1ad637SFrançois Tigeot * Intel High Definition Audio (Audio function quirks) driver for FreeBSD.
312a1ad637SFrançois Tigeot */
322a1ad637SFrançois Tigeot
332a1ad637SFrançois Tigeot #ifdef HAVE_KERNEL_OPTION_HEADERS
342a1ad637SFrançois Tigeot #include "opt_snd.h"
352a1ad637SFrançois Tigeot #endif
362a1ad637SFrançois Tigeot
372a1ad637SFrançois Tigeot #include <dev/sound/pcm/sound.h>
382a1ad637SFrançois Tigeot
392a1ad637SFrançois Tigeot #include <sys/ctype.h>
402a1ad637SFrançois Tigeot
412a1ad637SFrançois Tigeot #include <dev/sound/pci/hda/hdac.h>
422a1ad637SFrançois Tigeot #include <dev/sound/pci/hda/hdaa.h>
432a1ad637SFrançois Tigeot #include <dev/sound/pci/hda/hda_reg.h>
44536a8300SMatthew Dillon #include <dev/sound/pci/hda/hdaa_patches.h>
452a1ad637SFrançois Tigeot
462a1ad637SFrançois Tigeot SND_DECLARE_FILE("$FreeBSD: head/sys/dev/sound/pci/hda/hdaa_patches.c 269158 2014-07-27 20:14:22Z adrian $");
472a1ad637SFrançois Tigeot
482a1ad637SFrançois Tigeot static const struct {
492a1ad637SFrançois Tigeot uint32_t model;
502a1ad637SFrançois Tigeot uint32_t id;
512a1ad637SFrançois Tigeot uint32_t subsystemid;
522a1ad637SFrançois Tigeot uint32_t set, unset;
532a1ad637SFrançois Tigeot uint32_t gpio;
542a1ad637SFrançois Tigeot } hdac_quirks[] = {
552a1ad637SFrançois Tigeot /*
562a1ad637SFrançois Tigeot * XXX Force stereo quirk. Monoural recording / playback
572a1ad637SFrançois Tigeot * on few codecs (especially ALC880) seems broken or
582a1ad637SFrançois Tigeot * perhaps unsupported.
592a1ad637SFrançois Tigeot */
602a1ad637SFrançois Tigeot { HDA_MATCH_ALL, HDA_MATCH_ALL, HDA_MATCH_ALL,
612a1ad637SFrançois Tigeot HDAA_QUIRK_FORCESTEREO | HDAA_QUIRK_IVREF, 0,
622a1ad637SFrançois Tigeot 0 },
632a1ad637SFrançois Tigeot { ACER_ALL_SUBVENDOR, HDA_MATCH_ALL, HDA_MATCH_ALL,
642a1ad637SFrançois Tigeot 0, 0,
652a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
662a1ad637SFrançois Tigeot { ASUS_G2K_SUBVENDOR, HDA_CODEC_ALC660, HDA_MATCH_ALL,
672a1ad637SFrançois Tigeot 0, 0,
682a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
692a1ad637SFrançois Tigeot { ASUS_M5200_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
702a1ad637SFrançois Tigeot 0, 0,
712a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
722a1ad637SFrançois Tigeot { ASUS_A7M_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
732a1ad637SFrançois Tigeot 0, 0,
742a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
752a1ad637SFrançois Tigeot { ASUS_A7T_SUBVENDOR, HDA_CODEC_ALC882, HDA_MATCH_ALL,
762a1ad637SFrançois Tigeot 0, 0,
772a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
782a1ad637SFrançois Tigeot { ASUS_W2J_SUBVENDOR, HDA_CODEC_ALC882, HDA_MATCH_ALL,
792a1ad637SFrançois Tigeot 0, 0,
802a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
812a1ad637SFrançois Tigeot { ASUS_U5F_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
822a1ad637SFrançois Tigeot HDAA_QUIRK_EAPDINV, 0,
832a1ad637SFrançois Tigeot 0 },
842a1ad637SFrançois Tigeot { ASUS_A8X_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
852a1ad637SFrançois Tigeot HDAA_QUIRK_EAPDINV, 0,
862a1ad637SFrançois Tigeot 0 },
872a1ad637SFrançois Tigeot { ASUS_F3JC_SUBVENDOR, HDA_CODEC_ALC861, HDA_MATCH_ALL,
882a1ad637SFrançois Tigeot HDAA_QUIRK_OVREF, 0,
892a1ad637SFrançois Tigeot 0 },
902a1ad637SFrançois Tigeot { UNIWILL_9075_SUBVENDOR, HDA_CODEC_ALC861, HDA_MATCH_ALL,
912a1ad637SFrançois Tigeot HDAA_QUIRK_OVREF, 0,
922a1ad637SFrançois Tigeot 0 },
932a1ad637SFrançois Tigeot /*{ ASUS_M2N_SUBVENDOR, HDA_CODEC_AD1988, HDA_MATCH_ALL,
942a1ad637SFrançois Tigeot HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
952a1ad637SFrançois Tigeot 0 },*/
962a1ad637SFrançois Tigeot { MEDION_MD95257_SUBVENDOR, HDA_CODEC_ALC880, HDA_MATCH_ALL,
972a1ad637SFrançois Tigeot 0, 0,
982a1ad637SFrançois Tigeot HDAA_GPIO_SET(1) },
992a1ad637SFrançois Tigeot { LENOVO_3KN100_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
1002a1ad637SFrançois Tigeot HDAA_QUIRK_EAPDINV | HDAA_QUIRK_SENSEINV, 0,
1012a1ad637SFrançois Tigeot 0 },
1022a1ad637SFrançois Tigeot { SAMSUNG_Q1_SUBVENDOR, HDA_CODEC_AD1986A, HDA_MATCH_ALL,
1032a1ad637SFrançois Tigeot HDAA_QUIRK_EAPDINV, 0,
1042a1ad637SFrançois Tigeot 0 },
1052a1ad637SFrançois Tigeot { APPLE_MB3_SUBVENDOR, HDA_CODEC_ALC885, HDA_MATCH_ALL,
1062a1ad637SFrançois Tigeot HDAA_QUIRK_OVREF50, 0,
1072a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
1082a1ad637SFrançois Tigeot { APPLE_INTEL_MAC, HDA_CODEC_STAC9221, HDA_MATCH_ALL,
1092a1ad637SFrançois Tigeot 0, 0,
1102a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) | HDAA_GPIO_SET(1) },
1112a1ad637SFrançois Tigeot { APPLE_MACBOOKAIR31, HDA_CODEC_CS4206, HDA_MATCH_ALL,
1122a1ad637SFrançois Tigeot 0, 0,
1132a1ad637SFrançois Tigeot HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
1142a1ad637SFrançois Tigeot { APPLE_MACBOOKPRO55, HDA_CODEC_CS4206, HDA_MATCH_ALL,
1152a1ad637SFrançois Tigeot 0, 0,
1162a1ad637SFrançois Tigeot HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
1172a1ad637SFrançois Tigeot { APPLE_MACBOOKPRO71, HDA_CODEC_CS4206, HDA_MATCH_ALL,
1182a1ad637SFrançois Tigeot 0, 0,
1192a1ad637SFrançois Tigeot HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
1202a1ad637SFrançois Tigeot { HDA_INTEL_MACBOOKPRO92, HDA_CODEC_CS4206, HDA_MATCH_ALL,
1212a1ad637SFrançois Tigeot 0, 0,
1222a1ad637SFrançois Tigeot HDAA_GPIO_SET(1) | HDAA_GPIO_SET(3) },
1232a1ad637SFrançois Tigeot { DELL_D630_SUBVENDOR, HDA_CODEC_STAC9205X, HDA_MATCH_ALL,
1242a1ad637SFrançois Tigeot 0, 0,
1252a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
1262a1ad637SFrançois Tigeot { DELL_V1400_SUBVENDOR, HDA_CODEC_STAC9228X, HDA_MATCH_ALL,
1272a1ad637SFrançois Tigeot 0, 0,
1282a1ad637SFrançois Tigeot HDAA_GPIO_SET(2) },
1292a1ad637SFrançois Tigeot { DELL_V1500_SUBVENDOR, HDA_CODEC_STAC9205X, HDA_MATCH_ALL,
1302a1ad637SFrançois Tigeot 0, 0,
1312a1ad637SFrançois Tigeot HDAA_GPIO_SET(0) },
1322a1ad637SFrançois Tigeot { HDA_MATCH_ALL, HDA_CODEC_AD1988, HDA_MATCH_ALL,
1332a1ad637SFrançois Tigeot HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
1342a1ad637SFrançois Tigeot 0 },
1352a1ad637SFrançois Tigeot { HDA_MATCH_ALL, HDA_CODEC_AD1988B, HDA_MATCH_ALL,
1362a1ad637SFrançois Tigeot HDAA_QUIRK_IVREF80, HDAA_QUIRK_IVREF50 | HDAA_QUIRK_IVREF100,
1372a1ad637SFrançois Tigeot 0 },
1382a1ad637SFrançois Tigeot { HDA_MATCH_ALL, HDA_CODEC_CX20549, HDA_MATCH_ALL,
1392a1ad637SFrançois Tigeot 0, HDAA_QUIRK_FORCESTEREO,
1402a1ad637SFrançois Tigeot 0 },
1412a1ad637SFrançois Tigeot /* Mac Pro 1,1 requires ovref for proper volume level. */
1422a1ad637SFrançois Tigeot { 0x00000000, HDA_CODEC_ALC885, 0x106b0c00,
1432a1ad637SFrançois Tigeot 0, HDAA_QUIRK_OVREF,
1442a1ad637SFrançois Tigeot 0 }
1452a1ad637SFrançois Tigeot };
1462a1ad637SFrançois Tigeot
1472a1ad637SFrançois Tigeot static void
hdac_pin_patch(struct hdaa_widget * w)1482a1ad637SFrançois Tigeot hdac_pin_patch(struct hdaa_widget *w)
1492a1ad637SFrançois Tigeot {
1502a1ad637SFrançois Tigeot const char *patch = NULL;
1512a1ad637SFrançois Tigeot uint32_t config, orig, id, subid;
1522a1ad637SFrançois Tigeot nid_t nid = w->nid;
1532a1ad637SFrançois Tigeot
1542a1ad637SFrançois Tigeot config = orig = w->wclass.pin.config;
1552a1ad637SFrançois Tigeot id = hdaa_codec_id(w->devinfo);
1562a1ad637SFrançois Tigeot subid = hdaa_card_id(w->devinfo);
1572a1ad637SFrançois Tigeot
1582a1ad637SFrançois Tigeot /* XXX: Old patches require complete review.
1592a1ad637SFrançois Tigeot * Now they may create more problem then solve due to
1602a1ad637SFrançois Tigeot * incorrect associations.
1612a1ad637SFrançois Tigeot */
1622a1ad637SFrançois Tigeot if (id == HDA_CODEC_ALC880 && subid == LG_LW20_SUBVENDOR) {
1632a1ad637SFrançois Tigeot switch (nid) {
1642a1ad637SFrançois Tigeot case 26:
1652a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1662a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
1672a1ad637SFrançois Tigeot break;
1682a1ad637SFrançois Tigeot case 27:
1692a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1702a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT;
1712a1ad637SFrançois Tigeot break;
1722a1ad637SFrançois Tigeot default:
1732a1ad637SFrançois Tigeot break;
1742a1ad637SFrançois Tigeot }
1752a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC880 &&
1762a1ad637SFrançois Tigeot (subid == CLEVO_D900T_SUBVENDOR ||
1772a1ad637SFrançois Tigeot subid == ASUS_M5200_SUBVENDOR)) {
1782a1ad637SFrançois Tigeot /*
1792a1ad637SFrançois Tigeot * Super broken BIOS
1802a1ad637SFrançois Tigeot */
1812a1ad637SFrançois Tigeot switch (nid) {
1822a1ad637SFrançois Tigeot case 24: /* MIC1 */
1832a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1842a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
1852a1ad637SFrançois Tigeot break;
1862a1ad637SFrançois Tigeot case 25: /* XXX MIC2 */
1872a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1882a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN;
1892a1ad637SFrançois Tigeot break;
1902a1ad637SFrançois Tigeot case 26: /* LINE1 */
1912a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1922a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
1932a1ad637SFrançois Tigeot break;
1942a1ad637SFrançois Tigeot case 27: /* XXX LINE2 */
1952a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
1962a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_IN;
1972a1ad637SFrançois Tigeot break;
1982a1ad637SFrançois Tigeot case 28: /* CD */
1992a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_DEVICE_MASK;
2002a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_DEVICE_CD;
2012a1ad637SFrançois Tigeot break;
2022a1ad637SFrançois Tigeot }
2032a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC883 &&
2042a1ad637SFrançois Tigeot (subid == MSI_MS034A_SUBVENDOR ||
2052a1ad637SFrançois Tigeot HDA_DEV_MATCH(ACER_ALL_SUBVENDOR, subid))) {
2062a1ad637SFrançois Tigeot switch (nid) {
2072a1ad637SFrançois Tigeot case 25:
2082a1ad637SFrançois Tigeot config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2092a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2102a1ad637SFrançois Tigeot config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2112a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2122a1ad637SFrançois Tigeot break;
2132a1ad637SFrançois Tigeot case 28:
2142a1ad637SFrançois Tigeot config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2152a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2162a1ad637SFrançois Tigeot config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2172a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2182a1ad637SFrançois Tigeot break;
2192a1ad637SFrançois Tigeot }
2202a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_CX20549 && subid ==
2212a1ad637SFrançois Tigeot HP_V3000_SUBVENDOR) {
2222a1ad637SFrançois Tigeot switch (nid) {
2232a1ad637SFrançois Tigeot case 18:
2242a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2252a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2262a1ad637SFrançois Tigeot break;
2272a1ad637SFrançois Tigeot case 20:
2282a1ad637SFrançois Tigeot config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2292a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2302a1ad637SFrançois Tigeot config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2312a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2322a1ad637SFrançois Tigeot break;
2332a1ad637SFrançois Tigeot case 21:
2342a1ad637SFrançois Tigeot config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2352a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2362a1ad637SFrançois Tigeot config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_CD |
2372a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2382a1ad637SFrançois Tigeot break;
2392a1ad637SFrançois Tigeot }
2402a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_CX20551 && subid ==
2412a1ad637SFrançois Tigeot HP_DV5000_SUBVENDOR) {
2422a1ad637SFrançois Tigeot switch (nid) {
2432a1ad637SFrançois Tigeot case 20:
2442a1ad637SFrançois Tigeot case 21:
2452a1ad637SFrançois Tigeot config &= ~HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK;
2462a1ad637SFrançois Tigeot config |= HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE;
2472a1ad637SFrançois Tigeot break;
2482a1ad637SFrançois Tigeot }
2492a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC861 && subid ==
2502a1ad637SFrançois Tigeot ASUS_W6F_SUBVENDOR) {
2512a1ad637SFrançois Tigeot switch (nid) {
2522a1ad637SFrançois Tigeot case 11:
2532a1ad637SFrançois Tigeot config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2542a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2552a1ad637SFrançois Tigeot config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_LINE_OUT |
2562a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2572a1ad637SFrançois Tigeot break;
2582a1ad637SFrançois Tigeot case 12:
2592a1ad637SFrançois Tigeot case 14:
2602a1ad637SFrançois Tigeot case 16:
2612a1ad637SFrançois Tigeot case 31:
2622a1ad637SFrançois Tigeot case 32:
2632a1ad637SFrançois Tigeot config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2642a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2652a1ad637SFrançois Tigeot config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN |
2662a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_FIXED);
2672a1ad637SFrançois Tigeot break;
2682a1ad637SFrançois Tigeot case 15:
2692a1ad637SFrançois Tigeot config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2702a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2712a1ad637SFrançois Tigeot config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2722a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2732a1ad637SFrançois Tigeot break;
2742a1ad637SFrançois Tigeot }
2752a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC861 && subid ==
2762a1ad637SFrançois Tigeot UNIWILL_9075_SUBVENDOR) {
2772a1ad637SFrançois Tigeot switch (nid) {
2782a1ad637SFrançois Tigeot case 15:
2792a1ad637SFrançois Tigeot config &= ~(HDA_CONFIG_DEFAULTCONF_DEVICE_MASK |
2802a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK);
2812a1ad637SFrançois Tigeot config |= (HDA_CONFIG_DEFAULTCONF_DEVICE_HP_OUT |
2822a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_JACK);
2832a1ad637SFrançois Tigeot break;
2842a1ad637SFrançois Tigeot }
2852a1ad637SFrançois Tigeot }
2862a1ad637SFrançois Tigeot
2872a1ad637SFrançois Tigeot /* New patches */
288dad4f08aSMatthew Dillon if (id == HDA_CODEC_ALC283 && (subid == ACER_C720_SUBVENDOR ||
289dad4f08aSMatthew Dillon subid == ACER_C720_SUBVENDOR2)) {
290536a8300SMatthew Dillon switch (nid) {
291536a8300SMatthew Dillon case 20:
292536a8300SMatthew Dillon patch = "as=2 seq=0";
293536a8300SMatthew Dillon break;
294536a8300SMatthew Dillon case 25:
295536a8300SMatthew Dillon patch = "as=1 seq=0";
296536a8300SMatthew Dillon break;
297536a8300SMatthew Dillon case 27:
298536a8300SMatthew Dillon /*
299536a8300SMatthew Dillon patch = "device=Headphones conn=Fixed as=2 seq=15";
300536a8300SMatthew Dillon w->enable = 1;
301536a8300SMatthew Dillon */
302536a8300SMatthew Dillon break;
303536a8300SMatthew Dillon case 33:
304536a8300SMatthew Dillon break;
305536a8300SMatthew Dillon }
306536a8300SMatthew Dillon } else
3072a1ad637SFrançois Tigeot if (id == HDA_CODEC_AD1984A &&
3082a1ad637SFrançois Tigeot subid == LENOVO_X300_SUBVENDOR) {
3092a1ad637SFrançois Tigeot switch (nid) {
3102a1ad637SFrançois Tigeot case 17: /* Headphones with redirection */
3112a1ad637SFrançois Tigeot patch = "as=1 seq=15";
3122a1ad637SFrançois Tigeot break;
3132a1ad637SFrançois Tigeot case 20: /* Two mics together */
3142a1ad637SFrançois Tigeot patch = "as=2 seq=15";
3152a1ad637SFrançois Tigeot break;
3162a1ad637SFrançois Tigeot }
3172a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_AD1986A &&
3182a1ad637SFrançois Tigeot (subid == ASUS_M2NPVMX_SUBVENDOR ||
3192a1ad637SFrançois Tigeot subid == ASUS_A8NVMCSM_SUBVENDOR ||
3202a1ad637SFrançois Tigeot subid == ASUS_P5PL2_SUBVENDOR)) {
3212a1ad637SFrançois Tigeot switch (nid) {
3222a1ad637SFrançois Tigeot case 26: /* Headphones with redirection */
3232a1ad637SFrançois Tigeot patch = "as=1 seq=15";
3242a1ad637SFrançois Tigeot break;
3252a1ad637SFrançois Tigeot case 28: /* 5.1 out => 2.0 out + 1 input */
3262a1ad637SFrançois Tigeot patch = "device=Line-in as=8 seq=1";
3272a1ad637SFrançois Tigeot break;
3282a1ad637SFrançois Tigeot case 29: /* Can't use this as input, as the only available mic
3292a1ad637SFrançois Tigeot * preamplifier is busy by front panel mic (nid 31).
3302a1ad637SFrançois Tigeot * If you want to use this rear connector as mic input,
3312a1ad637SFrançois Tigeot * you have to disable the front panel one. */
3322a1ad637SFrançois Tigeot patch = "as=0";
3332a1ad637SFrançois Tigeot break;
3342a1ad637SFrançois Tigeot case 31: /* Lot of inputs configured with as=15 and unusable */
3352a1ad637SFrançois Tigeot patch = "as=8 seq=3";
3362a1ad637SFrançois Tigeot break;
3372a1ad637SFrançois Tigeot case 32:
3382a1ad637SFrançois Tigeot patch = "as=8 seq=4";
3392a1ad637SFrançois Tigeot break;
3402a1ad637SFrançois Tigeot case 34:
3412a1ad637SFrançois Tigeot patch = "as=8 seq=5";
3422a1ad637SFrançois Tigeot break;
3432a1ad637SFrançois Tigeot case 36:
3442a1ad637SFrançois Tigeot patch = "as=8 seq=6";
3452a1ad637SFrançois Tigeot break;
3462a1ad637SFrançois Tigeot }
3472a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC260 &&
3482a1ad637SFrançois Tigeot HDA_DEV_MATCH(SONY_S5_SUBVENDOR, subid)) {
3492a1ad637SFrançois Tigeot switch (nid) {
3502a1ad637SFrançois Tigeot case 16:
3512a1ad637SFrançois Tigeot patch = "seq=15 device=Headphones";
3522a1ad637SFrançois Tigeot break;
3532a1ad637SFrançois Tigeot }
3542a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC268) {
3552a1ad637SFrançois Tigeot if (subid == ACER_T5320_SUBVENDOR) {
3562a1ad637SFrançois Tigeot switch (nid) {
3572a1ad637SFrançois Tigeot case 20: /* Headphones Jack */
3582a1ad637SFrançois Tigeot patch = "as=1 seq=15";
3592a1ad637SFrançois Tigeot break;
3602a1ad637SFrançois Tigeot }
3612a1ad637SFrançois Tigeot }
3622a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_CX20561 &&
3632a1ad637SFrançois Tigeot subid == LENOVO_B450_SUBVENDOR) {
3642a1ad637SFrançois Tigeot switch (nid) {
3652a1ad637SFrançois Tigeot case 22:
3662a1ad637SFrançois Tigeot patch = "as=1 seq=15";
3672a1ad637SFrançois Tigeot break;
3682a1ad637SFrançois Tigeot }
3692a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_CX20561 &&
3702a1ad637SFrançois Tigeot subid == LENOVO_T400_SUBVENDOR) {
3712a1ad637SFrançois Tigeot switch (nid) {
3722a1ad637SFrançois Tigeot case 22:
3732a1ad637SFrançois Tigeot patch = "as=1 seq=15";
3742a1ad637SFrançois Tigeot break;
3752a1ad637SFrançois Tigeot case 26:
3762a1ad637SFrançois Tigeot patch = "as=1 seq=0";
3772a1ad637SFrançois Tigeot break;
3782a1ad637SFrançois Tigeot }
3792a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_CX20590 &&
3802a1ad637SFrançois Tigeot (subid == LENOVO_X1_SUBVENDOR ||
3812a1ad637SFrançois Tigeot subid == LENOVO_X220_SUBVENDOR ||
3822a1ad637SFrançois Tigeot subid == LENOVO_T420_SUBVENDOR ||
3832a1ad637SFrançois Tigeot subid == LENOVO_T520_SUBVENDOR ||
3842a1ad637SFrançois Tigeot subid == LENOVO_G580_SUBVENDOR)) {
3852a1ad637SFrançois Tigeot switch (nid) {
3862a1ad637SFrançois Tigeot case 25:
3872a1ad637SFrançois Tigeot patch = "as=1 seq=15";
3882a1ad637SFrançois Tigeot break;
3892a1ad637SFrançois Tigeot /*
3902a1ad637SFrançois Tigeot * Group onboard mic and headphone mic
3912a1ad637SFrançois Tigeot * together. Fixes onboard mic.
3922a1ad637SFrançois Tigeot */
3932a1ad637SFrançois Tigeot case 27:
3942a1ad637SFrançois Tigeot patch = "as=2 seq=15";
3952a1ad637SFrançois Tigeot break;
3962a1ad637SFrançois Tigeot case 35:
3972a1ad637SFrançois Tigeot patch = "as=2";
3982a1ad637SFrançois Tigeot break;
3992a1ad637SFrançois Tigeot }
4002a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC269 &&
4012a1ad637SFrançois Tigeot (subid == LENOVO_X1CRBN_SUBVENDOR ||
4022a1ad637SFrançois Tigeot subid == LENOVO_T430_SUBVENDOR ||
4032a1ad637SFrançois Tigeot subid == LENOVO_T430S_SUBVENDOR ||
4042a1ad637SFrançois Tigeot subid == LENOVO_T530_SUBVENDOR)) {
4052a1ad637SFrançois Tigeot switch (nid) {
4062a1ad637SFrançois Tigeot case 21:
4072a1ad637SFrançois Tigeot patch = "as=1 seq=15";
4082a1ad637SFrançois Tigeot break;
4092a1ad637SFrançois Tigeot }
4102a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC269 &&
4112a1ad637SFrançois Tigeot subid == ASUS_UX31A_SUBVENDOR) {
4122a1ad637SFrançois Tigeot switch (nid) {
4132a1ad637SFrançois Tigeot case 33:
4142a1ad637SFrançois Tigeot patch = "as=1 seq=15";
4152a1ad637SFrançois Tigeot break;
4162a1ad637SFrançois Tigeot }
4172a1ad637SFrançois Tigeot } else if (id == HDA_CODEC_ALC892 &&
4182a1ad637SFrançois Tigeot subid == INTEL_DH87RL_SUBVENDOR) {
4192a1ad637SFrançois Tigeot switch (nid) {
4202a1ad637SFrançois Tigeot case 27:
4212a1ad637SFrançois Tigeot patch = "as=1 seq=15";
4222a1ad637SFrançois Tigeot break;
4232a1ad637SFrançois Tigeot }
4242a1ad637SFrançois Tigeot }
4252a1ad637SFrançois Tigeot
4262a1ad637SFrançois Tigeot if (patch != NULL)
4272a1ad637SFrançois Tigeot config = hdaa_widget_pin_patch(config, patch);
4282a1ad637SFrançois Tigeot HDA_BOOTVERBOSE(
4292a1ad637SFrançois Tigeot if (config != orig)
4302a1ad637SFrançois Tigeot device_printf(w->devinfo->dev,
4312a1ad637SFrançois Tigeot "Patching pin config nid=%u 0x%08x -> 0x%08x\n",
4322a1ad637SFrançois Tigeot nid, orig, config);
4332a1ad637SFrançois Tigeot );
4342a1ad637SFrançois Tigeot w->wclass.pin.config = config;
4352a1ad637SFrançois Tigeot }
4362a1ad637SFrançois Tigeot
4372a1ad637SFrançois Tigeot static void
hdaa_widget_patch(struct hdaa_widget * w)4382a1ad637SFrançois Tigeot hdaa_widget_patch(struct hdaa_widget *w)
4392a1ad637SFrançois Tigeot {
4402a1ad637SFrançois Tigeot struct hdaa_devinfo *devinfo = w->devinfo;
4412a1ad637SFrançois Tigeot uint32_t orig;
4422a1ad637SFrançois Tigeot nid_t beeper = -1;
443536a8300SMatthew Dillon uint32_t id, subid;
444536a8300SMatthew Dillon
445536a8300SMatthew Dillon id = hdaa_codec_id(devinfo);
446536a8300SMatthew Dillon subid = hdaa_card_id(devinfo);
4472a1ad637SFrançois Tigeot
4482a1ad637SFrançois Tigeot orig = w->param.widget_cap;
4492a1ad637SFrançois Tigeot /* On some codecs beeper is an input pin, but it is not recordable
4502a1ad637SFrançois Tigeot alone. Also most of BIOSes does not declare beeper pin.
4512a1ad637SFrançois Tigeot Change beeper pin node type to beeper to help parser. */
4522a1ad637SFrançois Tigeot switch (hdaa_codec_id(devinfo)) {
4532a1ad637SFrançois Tigeot case HDA_CODEC_AD1882:
4542a1ad637SFrançois Tigeot case HDA_CODEC_AD1883:
4552a1ad637SFrançois Tigeot case HDA_CODEC_AD1984:
4562a1ad637SFrançois Tigeot case HDA_CODEC_AD1984A:
4572a1ad637SFrançois Tigeot case HDA_CODEC_AD1984B:
4582a1ad637SFrançois Tigeot case HDA_CODEC_AD1987:
4592a1ad637SFrançois Tigeot case HDA_CODEC_AD1988:
4602a1ad637SFrançois Tigeot case HDA_CODEC_AD1988B:
4612a1ad637SFrançois Tigeot case HDA_CODEC_AD1989B:
4622a1ad637SFrançois Tigeot beeper = 26;
4632a1ad637SFrançois Tigeot break;
4642a1ad637SFrançois Tigeot case HDA_CODEC_ALC260:
4652a1ad637SFrançois Tigeot beeper = 23;
4662a1ad637SFrançois Tigeot break;
4672a1ad637SFrançois Tigeot }
4682a1ad637SFrançois Tigeot if (hda_get_vendor_id(devinfo->dev) == REALTEK_VENDORID &&
4692a1ad637SFrançois Tigeot hdaa_codec_id(devinfo) != HDA_CODEC_ALC260)
4702a1ad637SFrançois Tigeot beeper = 29;
4712a1ad637SFrançois Tigeot if (w->nid == beeper) {
4722a1ad637SFrançois Tigeot w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_MASK;
4732a1ad637SFrançois Tigeot w->param.widget_cap |= HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_BEEP_WIDGET <<
4742a1ad637SFrançois Tigeot HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_SHIFT;
4752a1ad637SFrançois Tigeot w->waspin = 1;
4762a1ad637SFrançois Tigeot }
4772a1ad637SFrançois Tigeot /*
4782a1ad637SFrançois Tigeot * Clear "digital" flag from digital mic input, as its signal then goes
4792a1ad637SFrançois Tigeot * to "analog" mixer and this separation just limits functionaity.
4802a1ad637SFrançois Tigeot */
4812a1ad637SFrançois Tigeot if (hdaa_codec_id(devinfo) == HDA_CODEC_AD1984A &&
4822a1ad637SFrançois Tigeot w->nid == 23)
4832a1ad637SFrançois Tigeot w->param.widget_cap &= ~HDA_PARAM_AUDIO_WIDGET_CAP_DIGITAL_MASK;
4842a1ad637SFrançois Tigeot HDA_BOOTVERBOSE(
4852a1ad637SFrançois Tigeot if (w->param.widget_cap != orig) {
4862a1ad637SFrançois Tigeot device_printf(w->devinfo->dev,
4872a1ad637SFrançois Tigeot "Patching widget caps nid=%u 0x%08x -> 0x%08x\n",
4882a1ad637SFrançois Tigeot w->nid, orig, w->param.widget_cap);
4892a1ad637SFrançois Tigeot }
4902a1ad637SFrançois Tigeot );
4912a1ad637SFrançois Tigeot
492536a8300SMatthew Dillon #if 1
493536a8300SMatthew Dillon /*
494536a8300SMatthew Dillon * Redirect the headphone plug sense (NID 33 -> redir to 12).
495536a8300SMatthew Dillon *
496536a8300SMatthew Dillon * Disable the remixer (NID 11). There was a comment in the linux
497536a8300SMatthew Dillon * driver that disabling the remixer removes low level whitenoise.
498536a8300SMatthew Dillon * this makes sense since the mixer's unconnected inputs might have
499536a8300SMatthew Dillon * noise on them that leaks through.
500536a8300SMatthew Dillon */
501dad4f08aSMatthew Dillon if (id == HDA_CODEC_ALC283 && (subid == ACER_C720_SUBVENDOR ||
502dad4f08aSMatthew Dillon subid == ACER_C720_SUBVENDOR2)) {
503536a8300SMatthew Dillon if (w->nid == 33)
504536a8300SMatthew Dillon w->senseredir = 12;
505536a8300SMatthew Dillon if (w->nid == 11)
506536a8300SMatthew Dillon w->enable = 0;
507536a8300SMatthew Dillon }
508536a8300SMatthew Dillon #endif
509536a8300SMatthew Dillon
5102a1ad637SFrançois Tigeot if (w->type == HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX)
5112a1ad637SFrançois Tigeot hdac_pin_patch(w);
5122a1ad637SFrançois Tigeot }
5132a1ad637SFrançois Tigeot
5142a1ad637SFrançois Tigeot void
hdaa_patch(struct hdaa_devinfo * devinfo)5152a1ad637SFrançois Tigeot hdaa_patch(struct hdaa_devinfo *devinfo)
5162a1ad637SFrançois Tigeot {
5172a1ad637SFrançois Tigeot struct hdaa_widget *w;
5182a1ad637SFrançois Tigeot uint32_t id, subid, subsystemid;
519*8fa94593SMatthew Dillon uint32_t val;
5202a1ad637SFrançois Tigeot int i;
5212a1ad637SFrançois Tigeot
5222a1ad637SFrançois Tigeot id = hdaa_codec_id(devinfo);
5232a1ad637SFrançois Tigeot subid = hdaa_card_id(devinfo);
5242a1ad637SFrançois Tigeot subsystemid = hda_get_subsystem_id(devinfo->dev);
5252a1ad637SFrançois Tigeot
5262a1ad637SFrançois Tigeot /*
5272a1ad637SFrançois Tigeot * Quirks
5282a1ad637SFrançois Tigeot */
5292a1ad637SFrançois Tigeot for (i = 0; i < nitems(hdac_quirks); i++) {
5302a1ad637SFrançois Tigeot if (!(HDA_DEV_MATCH(hdac_quirks[i].model, subid) &&
5312a1ad637SFrançois Tigeot HDA_DEV_MATCH(hdac_quirks[i].id, id) &&
5322a1ad637SFrançois Tigeot HDA_DEV_MATCH(hdac_quirks[i].subsystemid, subsystemid)))
5332a1ad637SFrançois Tigeot continue;
5342a1ad637SFrançois Tigeot devinfo->quirks |= hdac_quirks[i].set;
5352a1ad637SFrançois Tigeot devinfo->quirks &= ~(hdac_quirks[i].unset);
5362a1ad637SFrançois Tigeot devinfo->gpio = hdac_quirks[i].gpio;
5372a1ad637SFrançois Tigeot }
5382a1ad637SFrançois Tigeot
5392a1ad637SFrançois Tigeot /* Apply per-widget patch. */
5402a1ad637SFrançois Tigeot for (i = devinfo->startnode; i < devinfo->endnode; i++) {
5412a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, i);
5422a1ad637SFrançois Tigeot if (w == NULL)
5432a1ad637SFrançois Tigeot continue;
5442a1ad637SFrançois Tigeot hdaa_widget_patch(w);
5452a1ad637SFrançois Tigeot }
5462a1ad637SFrançois Tigeot
5472a1ad637SFrançois Tigeot switch (id) {
5482a1ad637SFrançois Tigeot case HDA_CODEC_AD1983:
5492a1ad637SFrançois Tigeot /*
5502a1ad637SFrançois Tigeot * This CODEC has several possible usages, but none
5512a1ad637SFrançois Tigeot * fit the parser best. Help parser to choose better.
5522a1ad637SFrançois Tigeot */
5532a1ad637SFrançois Tigeot /* Disable direct unmixed playback to get pcm volume. */
5542a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 5);
5552a1ad637SFrançois Tigeot if (w != NULL)
5562a1ad637SFrançois Tigeot w->connsenable[0] = 0;
5572a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 6);
5582a1ad637SFrançois Tigeot if (w != NULL)
5592a1ad637SFrançois Tigeot w->connsenable[0] = 0;
5602a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 11);
5612a1ad637SFrançois Tigeot if (w != NULL)
5622a1ad637SFrançois Tigeot w->connsenable[0] = 0;
5632a1ad637SFrançois Tigeot /* Disable mic and line selectors. */
5642a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 12);
5652a1ad637SFrançois Tigeot if (w != NULL)
5662a1ad637SFrançois Tigeot w->connsenable[1] = 0;
5672a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 13);
5682a1ad637SFrançois Tigeot if (w != NULL)
5692a1ad637SFrançois Tigeot w->connsenable[1] = 0;
5702a1ad637SFrançois Tigeot /* Disable recording from mono playback mix. */
5712a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 20);
5722a1ad637SFrançois Tigeot if (w != NULL)
5732a1ad637SFrançois Tigeot w->connsenable[3] = 0;
5742a1ad637SFrançois Tigeot break;
5752a1ad637SFrançois Tigeot case HDA_CODEC_AD1986A:
5762a1ad637SFrançois Tigeot /*
5772a1ad637SFrançois Tigeot * This CODEC has overcomplicated input mixing.
5782a1ad637SFrançois Tigeot * Make some cleaning there.
5792a1ad637SFrançois Tigeot */
5802a1ad637SFrançois Tigeot /* Disable input mono mixer. Not needed and not supported. */
5812a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 43);
5822a1ad637SFrançois Tigeot if (w != NULL)
5832a1ad637SFrançois Tigeot w->enable = 0;
5842a1ad637SFrançois Tigeot /* Disable any with any input mixing mesh. Use separately. */
5852a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 39);
5862a1ad637SFrançois Tigeot if (w != NULL)
5872a1ad637SFrançois Tigeot w->enable = 0;
5882a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 40);
5892a1ad637SFrançois Tigeot if (w != NULL)
5902a1ad637SFrançois Tigeot w->enable = 0;
5912a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 41);
5922a1ad637SFrançois Tigeot if (w != NULL)
5932a1ad637SFrançois Tigeot w->enable = 0;
5942a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 42);
5952a1ad637SFrançois Tigeot if (w != NULL)
5962a1ad637SFrançois Tigeot w->enable = 0;
5972a1ad637SFrançois Tigeot /* Disable duplicate mixer node connector. */
5982a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 15);
5992a1ad637SFrançois Tigeot if (w != NULL)
6002a1ad637SFrançois Tigeot w->connsenable[3] = 0;
6012a1ad637SFrançois Tigeot /* There is only one mic preamplifier, use it effectively. */
6022a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 31);
6032a1ad637SFrançois Tigeot if (w != NULL) {
6042a1ad637SFrançois Tigeot if ((w->wclass.pin.config &
6052a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
6062a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
6072a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 16);
6082a1ad637SFrançois Tigeot if (w != NULL)
6092a1ad637SFrançois Tigeot w->connsenable[2] = 0;
6102a1ad637SFrançois Tigeot } else {
6112a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 15);
6122a1ad637SFrançois Tigeot if (w != NULL)
6132a1ad637SFrançois Tigeot w->connsenable[0] = 0;
6142a1ad637SFrançois Tigeot }
6152a1ad637SFrançois Tigeot }
6162a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 32);
6172a1ad637SFrançois Tigeot if (w != NULL) {
6182a1ad637SFrançois Tigeot if ((w->wclass.pin.config &
6192a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_DEVICE_MASK) ==
6202a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_DEVICE_MIC_IN) {
6212a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 16);
6222a1ad637SFrançois Tigeot if (w != NULL)
6232a1ad637SFrançois Tigeot w->connsenable[0] = 0;
6242a1ad637SFrançois Tigeot } else {
6252a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 15);
6262a1ad637SFrançois Tigeot if (w != NULL)
6272a1ad637SFrançois Tigeot w->connsenable[1] = 0;
6282a1ad637SFrançois Tigeot }
6292a1ad637SFrançois Tigeot }
6302a1ad637SFrançois Tigeot
6312a1ad637SFrançois Tigeot if (subid == ASUS_A8X_SUBVENDOR) {
6322a1ad637SFrançois Tigeot /*
6332a1ad637SFrançois Tigeot * This is just plain ridiculous.. There
6342a1ad637SFrançois Tigeot * are several A8 series that share the same
6352a1ad637SFrançois Tigeot * pci id but works differently (EAPD).
6362a1ad637SFrançois Tigeot */
6372a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 26);
6382a1ad637SFrançois Tigeot if (w != NULL && w->type ==
6392a1ad637SFrançois Tigeot HDA_PARAM_AUDIO_WIDGET_CAP_TYPE_PIN_COMPLEX &&
6402a1ad637SFrançois Tigeot (w->wclass.pin.config &
6412a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_MASK) !=
6422a1ad637SFrançois Tigeot HDA_CONFIG_DEFAULTCONF_CONNECTIVITY_NONE)
6432a1ad637SFrançois Tigeot devinfo->quirks &=
6442a1ad637SFrançois Tigeot ~HDAA_QUIRK_EAPDINV;
6452a1ad637SFrançois Tigeot }
6462a1ad637SFrançois Tigeot break;
6472a1ad637SFrançois Tigeot case HDA_CODEC_AD1981HD:
6482a1ad637SFrançois Tigeot /*
6492a1ad637SFrançois Tigeot * This CODEC has very unusual design with several
6502a1ad637SFrançois Tigeot * points inappropriate for the present parser.
6512a1ad637SFrançois Tigeot */
6522a1ad637SFrançois Tigeot /* Disable recording from mono playback mix. */
6532a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 21);
6542a1ad637SFrançois Tigeot if (w != NULL)
6552a1ad637SFrançois Tigeot w->connsenable[3] = 0;
6562a1ad637SFrançois Tigeot /* Disable rear to front mic mixer, use separately. */
6572a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 31);
6582a1ad637SFrançois Tigeot if (w != NULL)
6592a1ad637SFrançois Tigeot w->enable = 0;
6602a1ad637SFrançois Tigeot /* Disable direct playback, use mixer. */
6612a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 5);
6622a1ad637SFrançois Tigeot if (w != NULL)
6632a1ad637SFrançois Tigeot w->connsenable[0] = 0;
6642a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 6);
6652a1ad637SFrançois Tigeot if (w != NULL)
6662a1ad637SFrançois Tigeot w->connsenable[0] = 0;
6672a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 9);
6682a1ad637SFrançois Tigeot if (w != NULL)
6692a1ad637SFrançois Tigeot w->connsenable[0] = 0;
6702a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 24);
6712a1ad637SFrançois Tigeot if (w != NULL)
6722a1ad637SFrançois Tigeot w->connsenable[0] = 0;
6732a1ad637SFrançois Tigeot break;
674*8fa94593SMatthew Dillon case HDA_CODEC_ALC256:
675*8fa94593SMatthew Dillon val = hda_read_coef_idx(devinfo->dev, 0x20, 0x46);
676*8fa94593SMatthew Dillon hda_write_coef_idx(devinfo->dev, 0x20, 0x46, val|0x3000);
677*8fa94593SMatthew Dillon break;
6782a1ad637SFrançois Tigeot case HDA_CODEC_ALC269:
6792a1ad637SFrançois Tigeot /*
6802a1ad637SFrançois Tigeot * ASUS EeePC 1001px has strange variant of ALC269 CODEC,
6812a1ad637SFrançois Tigeot * that mutes speaker if unused mixer at NID 15 is muted.
6822a1ad637SFrançois Tigeot * Probably CODEC incorrectly reports internal connections.
6832a1ad637SFrançois Tigeot * Hide that muter from the driver. There are several CODECs
6842a1ad637SFrançois Tigeot * sharing this ID and I have not enough information about
6852a1ad637SFrançois Tigeot * them to implement more universal solution.
6862a1ad637SFrançois Tigeot */
6872a1ad637SFrançois Tigeot if (subid == 0x84371043) {
6882a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 15);
6892a1ad637SFrançois Tigeot if (w != NULL)
6902a1ad637SFrançois Tigeot w->param.inamp_cap = 0;
6912a1ad637SFrançois Tigeot }
6922a1ad637SFrançois Tigeot break;
6932a1ad637SFrançois Tigeot case HDA_CODEC_CX20582:
6942a1ad637SFrançois Tigeot case HDA_CODEC_CX20583:
6952a1ad637SFrançois Tigeot case HDA_CODEC_CX20584:
6962a1ad637SFrançois Tigeot case HDA_CODEC_CX20585:
6972a1ad637SFrançois Tigeot case HDA_CODEC_CX20590:
6982a1ad637SFrançois Tigeot /*
6992a1ad637SFrançois Tigeot * These codecs have extra connectivity on record side
7002a1ad637SFrançois Tigeot * too reach for the present parser.
7012a1ad637SFrançois Tigeot */
7022a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 20);
7032a1ad637SFrançois Tigeot if (w != NULL)
7042a1ad637SFrançois Tigeot w->connsenable[1] = 0;
7052a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 21);
7062a1ad637SFrançois Tigeot if (w != NULL)
7072a1ad637SFrançois Tigeot w->connsenable[1] = 0;
7082a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 22);
7092a1ad637SFrançois Tigeot if (w != NULL)
7102a1ad637SFrançois Tigeot w->connsenable[0] = 0;
7112a1ad637SFrançois Tigeot break;
7122a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_0:
7132a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_1:
7142a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_2:
7152a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_3:
7162a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_4:
7172a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_5:
7182a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_6:
7192a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_7:
7202a1ad637SFrançois Tigeot /*
7212a1ad637SFrançois Tigeot * These codecs have hidden mic boost controls.
7222a1ad637SFrançois Tigeot */
7232a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 26);
7242a1ad637SFrançois Tigeot if (w != NULL)
7252a1ad637SFrançois Tigeot w->param.inamp_cap =
7262a1ad637SFrançois Tigeot (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
7272a1ad637SFrançois Tigeot (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
7282a1ad637SFrançois Tigeot (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
7292a1ad637SFrançois Tigeot w = hdaa_widget_get(devinfo, 30);
7302a1ad637SFrançois Tigeot if (w != NULL)
7312a1ad637SFrançois Tigeot w->param.inamp_cap =
7322a1ad637SFrançois Tigeot (40 << HDA_PARAM_OUTPUT_AMP_CAP_STEPSIZE_SHIFT) |
7332a1ad637SFrançois Tigeot (3 << HDA_PARAM_OUTPUT_AMP_CAP_NUMSTEPS_SHIFT) |
7342a1ad637SFrançois Tigeot (0 << HDA_PARAM_OUTPUT_AMP_CAP_OFFSET_SHIFT);
7352a1ad637SFrançois Tigeot break;
7362a1ad637SFrançois Tigeot }
7372a1ad637SFrançois Tigeot }
7382a1ad637SFrançois Tigeot
7392a1ad637SFrançois Tigeot void
hdaa_patch_direct(struct hdaa_devinfo * devinfo)7402a1ad637SFrançois Tigeot hdaa_patch_direct(struct hdaa_devinfo *devinfo)
7412a1ad637SFrançois Tigeot {
7422a1ad637SFrançois Tigeot device_t dev = devinfo->dev;
7432a1ad637SFrançois Tigeot uint32_t id, subid, val;
7442a1ad637SFrançois Tigeot
7452a1ad637SFrançois Tigeot id = hdaa_codec_id(devinfo);
7462a1ad637SFrançois Tigeot subid = hdaa_card_id(devinfo);
7472a1ad637SFrançois Tigeot
7482a1ad637SFrançois Tigeot switch (id) {
7492a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_0:
7502a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_1:
7512a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_2:
7522a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_3:
7532a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_4:
7542a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_5:
7552a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_6:
7562a1ad637SFrançois Tigeot case HDA_CODEC_VT1708S_7:
7572a1ad637SFrançois Tigeot /* Enable Mic Boost Volume controls. */
7582a1ad637SFrançois Tigeot hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
7592a1ad637SFrançois Tigeot 0xf98, 0x01));
7602a1ad637SFrançois Tigeot /* Fall though */
7612a1ad637SFrançois Tigeot case HDA_CODEC_VT1818S:
7622a1ad637SFrançois Tigeot /* Don't bypass mixer. */
7632a1ad637SFrançois Tigeot hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
7642a1ad637SFrançois Tigeot 0xf88, 0xc0));
7652a1ad637SFrançois Tigeot break;
7662a1ad637SFrançois Tigeot }
7672a1ad637SFrançois Tigeot if (subid == APPLE_INTEL_MAC)
7682a1ad637SFrançois Tigeot hda_command(dev, HDA_CMD_12BIT(0, devinfo->nid,
7692a1ad637SFrançois Tigeot 0x7e7, 0));
7702a1ad637SFrançois Tigeot if (id == HDA_CODEC_ALC269) {
7712a1ad637SFrançois Tigeot if (subid == 0x16e31043 || subid == 0x831a1043 ||
7722a1ad637SFrançois Tigeot subid == 0x834a1043 || subid == 0x83981043 ||
7732a1ad637SFrançois Tigeot subid == 0x83ce1043) {
7742a1ad637SFrançois Tigeot /*
7752a1ad637SFrançois Tigeot * The ditital mics on some Asus laptops produce
7762a1ad637SFrançois Tigeot * differential signals instead of expected stereo.
7772a1ad637SFrançois Tigeot * That results in silence if downmix it to mono.
7782a1ad637SFrançois Tigeot * To workaround, make codec to handle signal as mono.
7792a1ad637SFrançois Tigeot */
7802a1ad637SFrançois Tigeot hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
7812a1ad637SFrançois Tigeot val = hda_command(dev, HDA_CMD_GET_PROCESSING_COEFF(0, 0x20));
7822a1ad637SFrançois Tigeot hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, 0x20, 0x07));
7832a1ad637SFrançois Tigeot hda_command(dev, HDA_CMD_SET_PROCESSING_COEFF(0, 0x20, val|0x80));
7842a1ad637SFrançois Tigeot }
7852a1ad637SFrançois Tigeot }
786536a8300SMatthew Dillon if (id == HDA_CODEC_ALC283) {
787dad4f08aSMatthew Dillon if (subid == ACER_C720_SUBVENDOR ||
788dad4f08aSMatthew Dillon subid == ACER_C720_SUBVENDOR2)
789536a8300SMatthew Dillon hdaa_patch_direct_acer_c720(devinfo);
790536a8300SMatthew Dillon }
791536a8300SMatthew Dillon }
792536a8300SMatthew Dillon
793536a8300SMatthew Dillon /* XXX move me to a better place */
794536a8300SMatthew Dillon uint32_t
hda_read_coef_idx(device_t dev,nid_t nid,unsigned int coef_idx)795536a8300SMatthew Dillon hda_read_coef_idx(device_t dev, nid_t nid, unsigned int coef_idx)
796536a8300SMatthew Dillon {
797536a8300SMatthew Dillon uint32_t val;
798536a8300SMatthew Dillon
799536a8300SMatthew Dillon hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, nid, coef_idx));
800536a8300SMatthew Dillon val = hda_command(dev, HDA_CMD_GET_PROCESSING_COEFF(0, nid));
801536a8300SMatthew Dillon return val;
802536a8300SMatthew Dillon }
803536a8300SMatthew Dillon
804536a8300SMatthew Dillon void
hda_write_coef_idx(device_t dev,nid_t nid,unsigned int coef_idx,unsigned coef_val)805536a8300SMatthew Dillon hda_write_coef_idx(device_t dev, nid_t nid, unsigned int coef_idx,
806536a8300SMatthew Dillon unsigned coef_val)
807536a8300SMatthew Dillon {
808536a8300SMatthew Dillon hda_command(dev, HDA_CMD_SET_COEFF_INDEX(0, nid, coef_idx));
809536a8300SMatthew Dillon hda_command(dev, HDA_CMD_SET_PROCESSING_COEFF(0, nid, coef_val));
8102a1ad637SFrançois Tigeot }
811