ALSA: hda: Move codec drivers into sound/hda/codecs directory
authorTakashi Iwai <tiwai@suse.de>
Wed, 9 Jul 2025 16:04:09 +0000 (18:04 +0200)
committerTakashi Iwai <tiwai@suse.de>
Fri, 11 Jul 2025 07:55:37 +0000 (09:55 +0200)
Now move the all remaining codec drivers from sound/pci/hda to
sound/hda/codecs subdirectory.  Some drivers are put under the further
vendor subdirectory, and the vendor helper code (*_helper.c) are put
under helpers subdirectory.  Also the sub-codec drivers are moved under
a different subdirectory, sound/hda/codecs/sub-codecs, for
distinguishing from the main HD-audio codec drivers.

The prefix patch_ and hda_ as well as the suffix _helper are dropped
from file names as they are mostly superfluous.

No functional changes but just file path shuffling.

Reviewed-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20250709160434.1859-7-tiwai@suse.de
97 files changed:
sound/hda/Kconfig
sound/hda/Makefile
sound/hda/codecs/Kconfig [new file with mode: 0644]
sound/hda/codecs/Makefile [new file with mode: 0644]
sound/hda/codecs/analog.c [new file with mode: 0644]
sound/hda/codecs/ca0110.c [new file with mode: 0644]
sound/hda/codecs/ca0132.c [new file with mode: 0644]
sound/hda/codecs/ca0132_regs.h [new file with mode: 0644]
sound/hda/codecs/cirrus/Kconfig [new file with mode: 0644]
sound/hda/codecs/cirrus/Makefile [new file with mode: 0644]
sound/hda/codecs/cirrus/cirrus.c [new file with mode: 0644]
sound/hda/codecs/cirrus/cs8409-tables.c [new file with mode: 0644]
sound/hda/codecs/cirrus/cs8409.c [new file with mode: 0644]
sound/hda/codecs/cirrus/cs8409.h [new file with mode: 0644]
sound/hda/codecs/cmedia.c [new file with mode: 0644]
sound/hda/codecs/conexant.c [new file with mode: 0644]
sound/hda/codecs/generic.c [new file with mode: 0644]
sound/hda/codecs/generic.h [new file with mode: 0644]
sound/hda/codecs/hdmi/Makefile [new file with mode: 0644]
sound/hda/codecs/hdmi/eld.c [new file with mode: 0644]
sound/hda/codecs/hdmi/hdmi.c [new file with mode: 0644]
sound/hda/codecs/helpers/hp_x360.c [new file with mode: 0644]
sound/hda/codecs/helpers/ideapad_hotkey_led.c [new file with mode: 0644]
sound/hda/codecs/helpers/ideapad_s740.c [new file with mode: 0644]
sound/hda/codecs/helpers/thinkpad.c [new file with mode: 0644]
sound/hda/codecs/realtek.c [new file with mode: 0644]
sound/hda/codecs/senarytech.c [new file with mode: 0644]
sound/hda/codecs/si3054.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/Kconfig [new file with mode: 0644]
sound/hda/codecs/side-codecs/Makefile [new file with mode: 0644]
sound/hda/codecs/side-codecs/cirrus_scodec.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/cirrus_scodec.h [new file with mode: 0644]
sound/hda/codecs/side-codecs/cirrus_scodec_test.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l41_hda.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l41_hda.h [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l41_hda_property.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l41_hda_property.h [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l41_hda_spi.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l56_hda.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l56_hda.h [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/cs35l56_hda_spi.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/hda_component.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/hda_component.h [new file with mode: 0644]
sound/hda/codecs/side-codecs/tas2781_hda.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/tas2781_hda.h [new file with mode: 0644]
sound/hda/codecs/side-codecs/tas2781_hda_i2c.c [new file with mode: 0644]
sound/hda/codecs/side-codecs/tas2781_hda_spi.c [new file with mode: 0644]
sound/hda/codecs/sigmatel.c [new file with mode: 0644]
sound/hda/codecs/via.c [new file with mode: 0644]
sound/pci/Kconfig
sound/pci/Makefile
sound/pci/hda/Kconfig [deleted file]
sound/pci/hda/Makefile [deleted file]
sound/pci/hda/ca0132_regs.h [deleted file]
sound/pci/hda/cirrus_scodec.c [deleted file]
sound/pci/hda/cirrus_scodec.h [deleted file]
sound/pci/hda/cirrus_scodec_test.c [deleted file]
sound/pci/hda/cs35l41_hda.c [deleted file]
sound/pci/hda/cs35l41_hda.h [deleted file]
sound/pci/hda/cs35l41_hda_i2c.c [deleted file]
sound/pci/hda/cs35l41_hda_property.c [deleted file]
sound/pci/hda/cs35l41_hda_property.h [deleted file]
sound/pci/hda/cs35l41_hda_spi.c [deleted file]
sound/pci/hda/cs35l56_hda.c [deleted file]
sound/pci/hda/cs35l56_hda.h [deleted file]
sound/pci/hda/cs35l56_hda_i2c.c [deleted file]
sound/pci/hda/cs35l56_hda_spi.c [deleted file]
sound/pci/hda/hda_component.c [deleted file]
sound/pci/hda/hda_component.h [deleted file]
sound/pci/hda/hda_eld.c [deleted file]
sound/pci/hda/hda_generic.c [deleted file]
sound/pci/hda/hda_generic.h [deleted file]
sound/pci/hda/hp_x360_helper.c [deleted file]
sound/pci/hda/ideapad_hotkey_led_helper.c [deleted file]
sound/pci/hda/ideapad_s740_helper.c [deleted file]
sound/pci/hda/patch_analog.c [deleted file]
sound/pci/hda/patch_ca0110.c [deleted file]
sound/pci/hda/patch_ca0132.c [deleted file]
sound/pci/hda/patch_cirrus.c [deleted file]
sound/pci/hda/patch_cmedia.c [deleted file]
sound/pci/hda/patch_conexant.c [deleted file]
sound/pci/hda/patch_cs8409-tables.c [deleted file]
sound/pci/hda/patch_cs8409.c [deleted file]
sound/pci/hda/patch_cs8409.h [deleted file]
sound/pci/hda/patch_hdmi.c [deleted file]
sound/pci/hda/patch_realtek.c [deleted file]
sound/pci/hda/patch_senarytech.c [deleted file]
sound/pci/hda/patch_si3054.c [deleted file]
sound/pci/hda/patch_sigmatel.c [deleted file]
sound/pci/hda/patch_via.c [deleted file]
sound/pci/hda/tas2781_hda.c [deleted file]
sound/pci/hda/tas2781_hda.h [deleted file]
sound/pci/hda/tas2781_hda_i2c.c [deleted file]
sound/pci/hda/tas2781_hda_spi.c [deleted file]
sound/pci/hda/thinkpad_helper.c [deleted file]

index d360c884bd6d09cc939a075743e727b041e4282a..7797f44b3d0c497d57dd3e4dfc182e632431cfd0 100644 (file)
@@ -3,6 +3,7 @@ menu "HD-Audio"
 
 source "sound/hda/common/Kconfig"
 source "sound/hda/controllers/Kconfig"
+source "sound/hda/codecs/Kconfig"
 source "sound/hda/core/Kconfig"
 
 endmenu
index fc76086a1f5ede7dd863f7e8377c806afa72e18e..31b9fbedaa77ee275ba6ab25d85e58b43eed0f07 100644 (file)
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-y += core/
 obj-$(CONFIG_SND_HDA) += common/
+obj-$(CONFIG_SND_HDA) += codecs/
 # this must be the last entry after codec drivers;
 # otherwise the codec patches won't be hooked before the PCI probe
 # when built in kernel
diff --git a/sound/hda/codecs/Kconfig b/sound/hda/codecs/Kconfig
new file mode 100644 (file)
index 0000000..bac19a6
--- /dev/null
@@ -0,0 +1,168 @@
+# SPDX-License-Identifier: GPL-2.0-only
+if SND_HDA
+
+config SND_HDA_GENERIC_LEDS
+       bool
+
+config SND_HDA_CODEC_REALTEK
+       tristate "Build Realtek HD-audio codec support"
+       depends on INPUT
+       select SND_HDA_GENERIC
+       select SND_HDA_GENERIC_LEDS
+       select SND_HDA_SCODEC_COMPONENT
+       help
+         Say Y or M here to include Realtek HD-audio codec support in
+         snd-hda-intel driver, such as ALC880.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m
+
+config SND_HDA_CODEC_ANALOG
+       tristate "Build Analog Devices HD-audio codec support"
+       select SND_HDA_GENERIC
+       help
+         Say Y or M here to include Analog Devices HD-audio codec support in
+         snd-hda-intel driver, such as AD1986A.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_ANALOG=m
+
+config SND_HDA_CODEC_SIGMATEL
+       tristate "Build IDT/Sigmatel HD-audio codec support"
+       select SND_HDA_GENERIC
+       select SND_HDA_GENERIC_LEDS
+       help
+         Say Y or M here to include IDT (Sigmatel) HD-audio codec support in
+         snd-hda-intel driver, such as STAC9200.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_SIGMATEL=m
+
+config SND_HDA_CODEC_VIA
+       tristate "Build VIA HD-audio codec support"
+       select SND_HDA_GENERIC
+       help
+         Say Y or M here to include VIA HD-audio codec support in
+         snd-hda-intel driver, such as VT1708.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_VIA=m
+
+config SND_HDA_CODEC_HDMI
+       tristate "Build HDMI/DisplayPort HD-audio codec support"
+       select SND_DYNAMIC_MINORS
+       select SND_PCM_ELD
+       help
+         Say Y or M here to include HDMI and DisplayPort HD-audio codec
+         support in snd-hda-intel driver.  This includes all AMD/ATI,
+         Intel and Nvidia HDMI/DisplayPort codecs.
+
+         Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS
+         to assure the multiple streams for DP-MST support.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m
+
+config SND_HDA_CODEC_CONEXANT
+       tristate "Build Conexant HD-audio codec support"
+       select SND_HDA_GENERIC
+       select SND_HDA_GENERIC_LEDS
+       help
+         Say Y or M here to include Conexant HD-audio codec support in
+         snd-hda-intel driver, such as CX20549.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m
+
+config SND_HDA_CODEC_SENARYTECH
+       tristate "Build Senarytech HD-audio codec support"
+       select SND_HDA_GENERIC
+       select SND_HDA_GENERIC_LEDS
+       help
+         Say Y or M here to include Senarytech HD-audio codec support in
+         snd-hda-intel driver, such as SN6186.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_SENARYTECH=m
+
+config SND_HDA_CODEC_CA0110
+       tristate "Build Creative CA0110-IBG codec support"
+       select SND_HDA_GENERIC
+       help
+         Say Y or M here to include Creative CA0110-IBG codec support in
+         snd-hda-intel driver, found on some Creative X-Fi cards.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_CA0110=m
+
+config SND_HDA_CODEC_CA0132
+       tristate "Build Creative CA0132 codec support"
+       help
+         Say Y or M here to include Creative CA0132 codec support in
+         snd-hda-intel driver.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_CA0132=m
+
+config SND_HDA_CODEC_CA0132_DSP
+       bool "Support new DSP code for CA0132 codec"
+       depends on SND_HDA_CODEC_CA0132
+       default y
+       select SND_HDA_DSP_LOADER
+       select FW_LOADER
+       help
+         Say Y here to enable the DSP for Creative CA0132 for extended
+         features like equalizer or echo cancellation.
+
+         Note that this option requires the external firmware file
+         (ctefx.bin).
+
+config SND_HDA_CODEC_CMEDIA
+       tristate "Build C-Media HD-audio codec support"
+       select SND_HDA_GENERIC
+       help
+         Say Y or M here to include C-Media HD-audio codec support in
+         snd-hda-intel driver, such as CMI9880.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m
+
+config SND_HDA_CODEC_SI3054
+       tristate "Build Silicon Labs 3054 HD-modem codec support"
+       help
+         Say Y or M here to include Silicon Labs 3054 HD-modem codec
+         (and compatibles) support in snd-hda-intel driver.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_SI3054=m
+
+config SND_HDA_GENERIC
+       tristate "Enable generic HD-audio codec parser"
+       select SND_CTL_LED if SND_HDA_GENERIC_LEDS
+       select LEDS_CLASS if SND_HDA_GENERIC_LEDS
+       help
+         Say Y or M here to enable the generic HD-audio codec parser
+         in snd-hda-intel driver.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_GENERIC=m
+
+config SND_HDA_INTEL_HDMI_SILENT_STREAM
+       bool "Enable Silent Stream always for HDMI"
+       depends on SND_HDA_INTEL
+       help
+         Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream
+         for HDMI on hardware that supports the feature.
+
+         When enabled, the HDMI/DisplayPort codec will continue to provide
+         a continuous clock and a valid but silent data stream to
+         any connected external receiver. This allows to avoid gaps
+         at start of playback. Many receivers require multiple seconds
+         to start playing audio after the clock has been stopped.
+         This feature can impact power consumption as resources
+         are kept reserved both at transmitter and receiver.
+
+source "sound/hda/codecs/cirrus/Kconfig"
+source "sound/hda/codecs/side-codecs/Kconfig"
+
+endif # SND_HDA
diff --git a/sound/hda/codecs/Makefile b/sound/hda/codecs/Makefile
new file mode 100644 (file)
index 0000000..205cd13
--- /dev/null
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../common
+
+snd-hda-codec-generic-y :=     generic.o
+snd-hda-codec-analog-y :=      analog.o
+snd-hda-codec-ca0110-y :=      ca0110.o
+snd-hda-codec-ca0132-y :=      ca0132.o
+snd-hda-codec-cmedia-y :=      cmedia.o
+snd-hda-codec-conexant-y :=    conexant.o
+snd-hda-codec-idt-y :=         sigmatel.o
+snd-hda-codec-realtek-y :=     realtek.o
+snd-hda-codec-senarytech-y :=  senarytech.o
+snd-hda-codec-si3054-y :=      si3054.o
+snd-hda-codec-via-y :=         via.o
+
+obj-y += cirrus/
+obj-y += hdmi/
+obj-y += side-codecs/
+
+# codec drivers
+obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
+obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
+obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
+obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
+obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
+obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
+obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
+obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
+obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
+obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
+obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
diff --git a/sound/hda/codecs/analog.c b/sound/hda/codecs/analog.c
new file mode 100644 (file)
index 0000000..3557e06
--- /dev/null
@@ -0,0 +1,1176 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
+ *   AD1986A, AD1988
+ *
+ * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+
+struct ad198x_spec {
+       struct hda_gen_spec gen;
+
+       /* for auto parser */
+       int smux_paths[4];
+       unsigned int cur_smux;
+       hda_nid_t eapd_nid;
+
+       unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
+       int num_smux_conns;
+};
+
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; the actual parameters are overwritten at build */
+static const struct snd_kcontrol_new ad_beep_mixer[] = {
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
+       { } /* end */
+};
+
+#define set_beep_amp(spec, nid, idx, dir) \
+       ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
+#else
+#define set_beep_amp(spec, nid, idx, dir) /* NOP */
+#endif
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+static int create_beep_ctls(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec = codec->spec;
+       const struct snd_kcontrol_new *knew;
+
+       if (!spec->beep_amp)
+               return 0;
+
+       for (knew = ad_beep_mixer ; knew->name; knew++) {
+               int err;
+               struct snd_kcontrol *kctl;
+               kctl = snd_ctl_new1(knew, codec);
+               if (!kctl)
+                       return -ENOMEM;
+               kctl->private_value = spec->beep_amp;
+               err = snd_hda_ctl_add(codec, 0, kctl);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+#else
+#define create_beep_ctls(codec)                0
+#endif
+
+static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
+                               hda_nid_t hp)
+{
+       if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                           !codec->inv_eapd ? 0x00 : 0x02);
+       if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                           !codec->inv_eapd ? 0x00 : 0x02);
+}
+
+static void ad198x_power_eapd(struct hda_codec *codec)
+{
+       /* We currently only handle front, HP */
+       switch (codec->core.vendor_id) {
+       case 0x11d41882:
+       case 0x11d4882a:
+       case 0x11d41884:
+       case 0x11d41984:
+       case 0x11d41883:
+       case 0x11d4184a:
+       case 0x11d4194a:
+       case 0x11d4194b:
+       case 0x11d41988:
+       case 0x11d4198b:
+       case 0x11d4989a:
+       case 0x11d4989b:
+               ad198x_power_eapd_write(codec, 0x12, 0x11);
+               break;
+       case 0x11d41981:
+       case 0x11d41983:
+               ad198x_power_eapd_write(codec, 0x05, 0x06);
+               break;
+       case 0x11d41986:
+               ad198x_power_eapd_write(codec, 0x1b, 0x1a);
+               break;
+       }
+}
+
+static int ad198x_suspend(struct hda_codec *codec)
+{
+       snd_hda_shutup_pins(codec);
+       ad198x_power_eapd(codec);
+       return 0;
+}
+
+/* follow EAPD via vmaster hook */
+static void ad_vmaster_eapd_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct ad198x_spec *spec = codec->spec;
+
+       if (!spec->eapd_nid)
+               return;
+       if (codec->inv_eapd)
+               enabled = !enabled;
+       snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,
+                                  AC_VERB_SET_EAPD_BTLENABLE,
+                                  enabled ? 0x02 : 0x00);
+}
+
+/*
+ * Automatic parse of I/O pins from the BIOS configuration
+ */
+
+static int ad198x_auto_build_controls(struct hda_codec *codec)
+{
+       int err;
+
+       err = snd_hda_gen_build_controls(codec);
+       if (err < 0)
+               return err;
+       err = create_beep_ctls(codec);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+static const struct hda_codec_ops ad198x_auto_patch_ops = {
+       .build_controls = ad198x_auto_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = snd_hda_gen_init,
+       .free = snd_hda_gen_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .check_power_status = snd_hda_gen_check_power_status,
+       .suspend = ad198x_suspend,
+};
+
+
+static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
+{
+       struct ad198x_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+       int err;
+
+       codec->spdif_status_reset = 1;
+       codec->no_trigger_sense = 1;
+       codec->no_sticky_stream = 1;
+
+       spec->gen.indep_hp = indep_hp;
+       if (!spec->gen.add_stereo_mix_input)
+               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
+
+       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+       if (err < 0)
+               return err;
+       err = snd_hda_gen_parse_auto_config(codec, cfg);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+/*
+ * AD1986A specific
+ */
+
+static int alloc_ad_spec(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+       snd_hda_gen_spec_init(&spec->gen);
+       codec->patch_ops = ad198x_auto_patch_ops;
+       return 0;
+}
+
+/*
+ * AD1986A fixup codes
+ */
+
+/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
+static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct ad198x_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               codec->inv_jack_detect = 1;
+               spec->gen.keep_eapd_on = 1;
+               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+               spec->eapd_nid = 0x1b;
+       }
+}
+
+/* Toshiba Satellite L40 implements EAPD in a standard way unlike others */
+static void ad1986a_fixup_eapd(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       struct ad198x_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               codec->inv_eapd = 0;
+               spec->gen.keep_eapd_on = 1;
+               spec->eapd_nid = 0x1b;
+       }
+}
+
+/* enable stereo-mix input for avoiding regression on KDE (bko#88251) */
+static void ad1986a_fixup_eapd_mix_in(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       struct ad198x_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               ad1986a_fixup_eapd(codec, fix, action);
+               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_ENABLE;
+       }
+}
+
+enum {
+       AD1986A_FIXUP_INV_JACK_DETECT,
+       AD1986A_FIXUP_ULTRA,
+       AD1986A_FIXUP_SAMSUNG,
+       AD1986A_FIXUP_3STACK,
+       AD1986A_FIXUP_LAPTOP,
+       AD1986A_FIXUP_LAPTOP_IMIC,
+       AD1986A_FIXUP_EAPD,
+       AD1986A_FIXUP_EAPD_MIX_IN,
+       AD1986A_FIXUP_EASYNOTE,
+};
+
+static const struct hda_fixup ad1986a_fixups[] = {
+       [AD1986A_FIXUP_INV_JACK_DETECT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad_fixup_inv_jack_detect,
+       },
+       [AD1986A_FIXUP_ULTRA] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       {}
+               },
+       },
+       [AD1986A_FIXUP_SAMSUNG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       { 0x20, 0x411111f0 }, /* N/A */
+                       { 0x24, 0x411111f0 }, /* N/A */
+                       {}
+               },
+       },
+       [AD1986A_FIXUP_3STACK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02214021 }, /* headphone */
+                       { 0x1b, 0x01014011 }, /* front */
+                       { 0x1c, 0x01813030 }, /* line-in */
+                       { 0x1d, 0x01a19020 }, /* rear mic */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { 0x1f, 0x02a190f0 }, /* mic */
+                       { 0x20, 0x411111f0 }, /* N/A */
+                       {}
+               },
+       },
+       [AD1986A_FIXUP_LAPTOP] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02214021 }, /* headphone */
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { 0x1f, 0x02a191f0 }, /* mic */
+                       { 0x20, 0x411111f0 }, /* N/A */
+                       {}
+               },
+       },
+       [AD1986A_FIXUP_LAPTOP_IMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1d, 0x90a7013e }, /* int mic */
+                       {}
+               },
+               .chained_before = 1,
+               .chain_id = AD1986A_FIXUP_LAPTOP,
+       },
+       [AD1986A_FIXUP_EAPD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad1986a_fixup_eapd,
+       },
+       [AD1986A_FIXUP_EAPD_MIX_IN] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad1986a_fixup_eapd_mix_in,
+       },
+       [AD1986A_FIXUP_EASYNOTE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x0421402f }, /* headphone */
+                       { 0x1b, 0x90170110 }, /* speaker */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x90a70130 }, /* int mic */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { 0x1f, 0x04a19040 }, /* mic */
+                       { 0x20, 0x411111f0 }, /* N/A */
+                       { 0x21, 0x411111f0 }, /* N/A */
+                       { 0x22, 0x411111f0 }, /* N/A */
+                       { 0x23, 0x411111f0 }, /* N/A */
+                       { 0x24, 0x411111f0 }, /* N/A */
+                       { 0x25, 0x411111f0 }, /* N/A */
+                       {}
+               },
+               .chained = true,
+               .chain_id = AD1986A_FIXUP_EAPD_MIX_IN,
+       },
+};
+
+static const struct hda_quirk ad1986a_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
+       SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC),
+       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
+       SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
+       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
+       SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
+       SND_PCI_QUIRK(0x1631, 0xc022, "PackardBell EasyNote MX65", AD1986A_FIXUP_EASYNOTE),
+       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
+       SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
+       SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
+       {}
+};
+
+static const struct hda_model_fixup ad1986a_fixup_models[] = {
+       { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
+       { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
+       { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
+       { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
+       { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
+       {}
+};
+
+/*
+ */
+static int patch_ad1986a(struct hda_codec *codec)
+{
+       int err;
+       struct ad198x_spec *spec;
+       static const hda_nid_t preferred_pairs[] = {
+               0x1a, 0x03,
+               0x1b, 0x03,
+               0x1c, 0x04,
+               0x1d, 0x05,
+               0x1e, 0x03,
+               0
+       };
+
+       err = alloc_ad_spec(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+
+       /* AD1986A has the inverted EAPD implementation */
+       codec->inv_eapd = 1;
+
+       spec->gen.mixer_nid = 0x07;
+       spec->gen.beep_nid = 0x19;
+       set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
+
+       /* AD1986A has a hardware problem that it can't share a stream
+        * with multiple output pins.  The copy of front to surrounds
+        * causes noisy or silent outputs at a certain timing, e.g.
+        * changing the volume.
+        * So, let's disable the shared stream.
+        */
+       spec->gen.multiout.no_share_stream = 1;
+       /* give fixed DAC/pin pairs */
+       spec->gen.preferred_dacs = preferred_pairs;
+
+       /* AD1986A can't manage the dynamic pin on/off smoothly */
+       spec->gen.auto_mute_via_amp = 1;
+
+       snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
+                          ad1986a_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = ad198x_parse_auto_config(codec, false);
+       if (err < 0) {
+               snd_hda_gen_free(codec);
+               return err;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+
+/*
+ * AD1983 specific
+ */
+
+/*
+ * SPDIF mux control for AD1983 auto-parser
+ */
+static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ad198x_spec *spec = codec->spec;
+       static const char * const texts2[] = { "PCM", "ADC" };
+       static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
+       int num_conns = spec->num_smux_conns;
+
+       if (num_conns == 2)
+               return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
+       else if (num_conns == 3)
+               return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
+       else
+               return -EINVAL;
+}
+
+static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ad198x_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->cur_smux;
+       return 0;
+}
+
+static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ad198x_spec *spec = codec->spec;
+       unsigned int val = ucontrol->value.enumerated.item[0];
+       hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
+       int num_conns = spec->num_smux_conns;
+
+       if (val >= num_conns)
+               return -EINVAL;
+       if (spec->cur_smux == val)
+               return 0;
+       spec->cur_smux = val;
+       snd_hda_codec_write_cache(codec, dig_out, 0,
+                                 AC_VERB_SET_CONNECT_SEL, val);
+       return 1;
+}
+
+static const struct snd_kcontrol_new ad1983_auto_smux_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Playback Source",
+       .info = ad1983_auto_smux_enum_info,
+       .get = ad1983_auto_smux_enum_get,
+       .put = ad1983_auto_smux_enum_put,
+};
+
+static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec = codec->spec;
+       hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
+       int num_conns;
+
+       if (!dig_out)
+               return 0;
+       num_conns = snd_hda_get_num_conns(codec, dig_out);
+       if (num_conns != 2 && num_conns != 3)
+               return 0;
+       spec->num_smux_conns = num_conns;
+       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
+               return -ENOMEM;
+       return 0;
+}
+
+static int patch_ad1983(struct hda_codec *codec)
+{
+       static const hda_nid_t conn_0c[] = { 0x08 };
+       static const hda_nid_t conn_0d[] = { 0x09 };
+       struct ad198x_spec *spec;
+       int err;
+
+       err = alloc_ad_spec(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+
+       spec->gen.mixer_nid = 0x0e;
+       spec->gen.beep_nid = 0x10;
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
+       /* limit the loopback routes not to confuse the parser */
+       snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);
+       snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);
+
+       err = ad198x_parse_auto_config(codec, false);
+       if (err < 0)
+               goto error;
+       err = ad1983_add_spdif_mux_ctl(codec);
+       if (err < 0)
+               goto error;
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+
+/*
+ * AD1981 HD specific
+ */
+
+static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       struct ad198x_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+               spec->eapd_nid = 0x05;
+       }
+}
+
+/* set the upper-limit for mixer amp to 0dB for avoiding the possible
+ * damage by overloading
+ */
+static void ad1981_fixup_amp_override(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
+                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                         (1 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+enum {
+       AD1981_FIXUP_AMP_OVERRIDE,
+       AD1981_FIXUP_HP_EAPD,
+};
+
+static const struct hda_fixup ad1981_fixups[] = {
+       [AD1981_FIXUP_AMP_OVERRIDE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad1981_fixup_amp_override,
+       },
+       [AD1981_FIXUP_HP_EAPD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad1981_fixup_hp_eapd,
+               .chained = true,
+               .chain_id = AD1981_FIXUP_AMP_OVERRIDE,
+       },
+};
+
+static const struct hda_quirk ad1981_fixup_tbl[] = {
+       SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
+       /* HP nx6320 (reversed SSID, H/W bug) */
+       SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
+       {}
+};
+
+static int patch_ad1981(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+       int err;
+
+       err = alloc_ad_spec(codec);
+       if (err < 0)
+               return -ENOMEM;
+       spec = codec->spec;
+
+       spec->gen.mixer_nid = 0x0e;
+       spec->gen.beep_nid = 0x10;
+       set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
+
+       snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = ad198x_parse_auto_config(codec, false);
+       if (err < 0)
+               goto error;
+       err = ad1983_add_spdif_mux_ctl(codec);
+       if (err < 0)
+               goto error;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+
+/*
+ * AD1988
+ *
+ * Output pins and routes
+ *
+ *        Pin               Mix     Sel     DAC (*)
+ * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
+ * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
+ * port-C 0x15 (mute)    <- 0x2c <- 0x31 <- 05/0a
+ * port-D 0x12 (mute/hp) <- 0x29         <- 04
+ * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
+ * port-F 0x16 (mute)    <- 0x2a         <- 06
+ * port-G 0x24 (mute)    <- 0x27         <- 05
+ * port-H 0x25 (mute)    <- 0x28         <- 0a
+ * mono   0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
+ *
+ * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
+ * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
+ *
+ * Input pins and routes
+ *
+ *        pin     boost   mix input # / adc input #
+ * port-A 0x11 -> 0x38 -> mix 2, ADC 0
+ * port-B 0x14 -> 0x39 -> mix 0, ADC 1
+ * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
+ * port-D 0x12 -> 0x3d -> mix 3, ADC 8
+ * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
+ * port-F 0x16 -> 0x3b -> mix 5, ADC 3
+ * port-G 0x24 -> N/A  -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
+ * port-H 0x25 -> N/A  -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
+ *
+ *
+ * DAC assignment
+ *   6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
+ *   3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
+ *
+ * Inputs of Analog Mix (0x20)
+ *   0:Port-B (front mic)
+ *   1:Port-C/G/H (line-in)
+ *   2:Port-A
+ *   3:Port-D (line-in/2)
+ *   4:Port-E/G/H (mic-in)
+ *   5:Port-F (mic2-in)
+ *   6:CD
+ *   7:Beep
+ *
+ * ADC selection
+ *   0:Port-A
+ *   1:Port-B (front mic-in)
+ *   2:Port-C (line-in)
+ *   3:Port-F (mic2-in)
+ *   4:Port-E (mic-in)
+ *   5:CD
+ *   6:Port-G
+ *   7:Port-H
+ *   8:Port-D (line-in/2)
+ *   9:Mix
+ *
+ * Proposed pin assignments by the datasheet
+ *
+ * 6-stack
+ * Port-A front headphone
+ *      B front mic-in
+ *      C rear line-in
+ *      D rear front-out
+ *      E rear mic-in
+ *      F rear surround
+ *      G rear CLFE
+ *      H rear side
+ *
+ * 3-stack
+ * Port-A front headphone
+ *      B front mic
+ *      C rear line-in/surround
+ *      D rear front-out
+ *      E rear mic-in/CLFE
+ *
+ * laptop
+ * Port-A headphone
+ *      B mic-in
+ *      C docking station
+ *      D internal speaker (with EAPD)
+ *      E/F quad mic array
+ */
+
+static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
+                                     struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ad198x_spec *spec = codec->spec;
+       static const char * const texts[] = {
+               "PCM", "ADC1", "ADC2", "ADC3",
+       };
+       int num_conns = spec->num_smux_conns;
+
+       if (num_conns > 4)
+               num_conns = 4;
+       return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
+}
+
+static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ad198x_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->cur_smux;
+       return 0;
+}
+
+static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ad198x_spec *spec = codec->spec;
+       unsigned int val = ucontrol->value.enumerated.item[0];
+       struct nid_path *path;
+       int num_conns = spec->num_smux_conns;
+
+       if (val >= num_conns)
+               return -EINVAL;
+       if (spec->cur_smux == val)
+               return 0;
+
+       mutex_lock(&codec->control_mutex);
+       path = snd_hda_get_path_from_idx(codec,
+                                        spec->smux_paths[spec->cur_smux]);
+       if (path)
+               snd_hda_activate_path(codec, path, false, true);
+       path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
+       if (path)
+               snd_hda_activate_path(codec, path, true, true);
+       spec->cur_smux = val;
+       mutex_unlock(&codec->control_mutex);
+       return 1;
+}
+
+static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Playback Source",
+       .info = ad1988_auto_smux_enum_info,
+       .get = ad1988_auto_smux_enum_get,
+       .put = ad1988_auto_smux_enum_put,
+};
+
+static int ad1988_auto_init(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec = codec->spec;
+       int i, err;
+
+       err = snd_hda_gen_init(codec);
+       if (err < 0)
+               return err;
+       if (!spec->gen.autocfg.dig_outs)
+               return 0;
+
+       for (i = 0; i < 4; i++) {
+               struct nid_path *path;
+               path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
+               if (path)
+                       snd_hda_activate_path(codec, path, path->active, false);
+       }
+
+       return 0;
+}
+
+static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec = codec->spec;
+       int i, num_conns;
+       /* we create four static faked paths, since AD codecs have odd
+        * widget connections regarding the SPDIF out source
+        */
+       static const struct nid_path fake_paths[4] = {
+               {
+                       .depth = 3,
+                       .path = { 0x02, 0x1d, 0x1b },
+                       .idx = { 0, 0, 0 },
+                       .multi = { 0, 0, 0 },
+               },
+               {
+                       .depth = 4,
+                       .path = { 0x08, 0x0b, 0x1d, 0x1b },
+                       .idx = { 0, 0, 1, 0 },
+                       .multi = { 0, 1, 0, 0 },
+               },
+               {
+                       .depth = 4,
+                       .path = { 0x09, 0x0b, 0x1d, 0x1b },
+                       .idx = { 0, 1, 1, 0 },
+                       .multi = { 0, 1, 0, 0 },
+               },
+               {
+                       .depth = 4,
+                       .path = { 0x0f, 0x0b, 0x1d, 0x1b },
+                       .idx = { 0, 2, 1, 0 },
+                       .multi = { 0, 1, 0, 0 },
+               },
+       };
+
+       /* SPDIF source mux appears to be present only on AD1988A */
+       if (!spec->gen.autocfg.dig_outs ||
+           get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
+               return 0;
+
+       num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
+       if (num_conns != 3 && num_conns != 4)
+               return 0;
+       spec->num_smux_conns = num_conns;
+
+       for (i = 0; i < num_conns; i++) {
+               struct nid_path *path = snd_array_new(&spec->gen.paths);
+               if (!path)
+                       return -ENOMEM;
+               *path = fake_paths[i];
+               if (!i)
+                       path->active = 1;
+               spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
+       }
+
+       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
+               return -ENOMEM;
+
+       codec->patch_ops.init = ad1988_auto_init;
+
+       return 0;
+}
+
+/*
+ */
+
+enum {
+       AD1988_FIXUP_6STACK_DIG,
+};
+
+static const struct hda_fixup ad1988_fixups[] = {
+       [AD1988_FIXUP_6STACK_DIG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x11, 0x02214130 }, /* front-hp */
+                       { 0x12, 0x01014010 }, /* line-out */
+                       { 0x14, 0x02a19122 }, /* front-mic */
+                       { 0x15, 0x01813021 }, /* line-in */
+                       { 0x16, 0x01011012 }, /* line-out */
+                       { 0x17, 0x01a19020 }, /* mic */
+                       { 0x1b, 0x0145f1f0 }, /* SPDIF */
+                       { 0x24, 0x01016011 }, /* line-out */
+                       { 0x25, 0x01012013 }, /* line-out */
+                       { }
+               }
+       },
+};
+
+static const struct hda_model_fixup ad1988_fixup_models[] = {
+       { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
+       {}
+};
+
+static int patch_ad1988(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+       int err;
+
+       err = alloc_ad_spec(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+
+       spec->gen.mixer_nid = 0x20;
+       spec->gen.mixer_merge_nid = 0x21;
+       spec->gen.beep_nid = 0x10;
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
+       snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = ad198x_parse_auto_config(codec, true);
+       if (err < 0)
+               goto error;
+       err = ad1988_add_spdif_mux_ctl(codec);
+       if (err < 0)
+               goto error;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+
+/*
+ * AD1884 / AD1984
+ *
+ * port-B - front line/mic-in
+ * port-E - aux in/out
+ * port-F - aux in/out
+ * port-C - rear line/mic-in
+ * port-D - rear line/hp-out
+ * port-A - front line/hp-out
+ *
+ * AD1984 = AD1884 + two digital mic-ins
+ *
+ * AD1883 / AD1884A / AD1984A / AD1984B
+ *
+ * port-B (0x14) - front mic-in
+ * port-E (0x1c) - rear mic-in
+ * port-F (0x16) - CD / ext out
+ * port-C (0x15) - rear line-in
+ * port-D (0x12) - rear line-out
+ * port-A (0x11) - front hp-out
+ *
+ * AD1984A = AD1884A + digital-mic
+ * AD1883 = equivalent with AD1984A
+ * AD1984B = AD1984A + extra SPDIF-out
+ */
+
+/* set the upper-limit for mixer amp to 0dB for avoiding the possible
+ * damage by overloading
+ */
+static void ad1884_fixup_amp_override(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
+                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                         (1 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+/* toggle GPIO1 according to the mute state */
+static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct ad198x_spec *spec = codec->spec;
+
+       if (spec->eapd_nid)
+               ad_vmaster_eapd_hook(private_data, enabled);
+       snd_hda_codec_write_cache(codec, 0x01, 0,
+                                  AC_VERB_SET_GPIO_DATA,
+                                  enabled ? 0x00 : 0x02);
+}
+
+static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       struct ad198x_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
+               spec->gen.own_eapd_ctl = 1;
+               snd_hda_codec_write_cache(codec, 0x01, 0,
+                                         AC_VERB_SET_GPIO_MASK, 0x02);
+               snd_hda_codec_write_cache(codec, 0x01, 0,
+                                         AC_VERB_SET_GPIO_DIRECTION, 0x02);
+               snd_hda_codec_write_cache(codec, 0x01, 0,
+                                         AC_VERB_SET_GPIO_DATA, 0x02);
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+                       spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
+               else
+                       spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
+               break;
+       }
+}
+
+static void ad1884_fixup_thinkpad(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       struct ad198x_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.keep_eapd_on = 1;
+               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
+               spec->eapd_nid = 0x12;
+               /* Analog PC Beeper - allow firmware/ACPI beeps */
+               spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
+               spec->gen.beep_nid = 0; /* no digital beep */
+       }
+}
+
+/* set magic COEFs for dmic */
+static const struct hda_verb ad1884_dmic_init_verbs[] = {
+       {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
+       {0x01, AC_VERB_SET_PROC_COEF, 0x08},
+       {}
+};
+
+enum {
+       AD1884_FIXUP_AMP_OVERRIDE,
+       AD1884_FIXUP_HP_EAPD,
+       AD1884_FIXUP_DMIC_COEF,
+       AD1884_FIXUP_THINKPAD,
+       AD1884_FIXUP_HP_TOUCHSMART,
+};
+
+static const struct hda_fixup ad1884_fixups[] = {
+       [AD1884_FIXUP_AMP_OVERRIDE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad1884_fixup_amp_override,
+       },
+       [AD1884_FIXUP_HP_EAPD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad1884_fixup_hp_eapd,
+               .chained = true,
+               .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
+       },
+       [AD1884_FIXUP_DMIC_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = ad1884_dmic_init_verbs,
+       },
+       [AD1884_FIXUP_THINKPAD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = ad1884_fixup_thinkpad,
+               .chained = true,
+               .chain_id = AD1884_FIXUP_DMIC_COEF,
+       },
+       [AD1884_FIXUP_HP_TOUCHSMART] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = ad1884_dmic_init_verbs,
+               .chained = true,
+               .chain_id = AD1884_FIXUP_HP_EAPD,
+       },
+};
+
+static const struct hda_quirk ad1884_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
+       {}
+};
+
+
+static int patch_ad1884(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+       int err;
+
+       err = alloc_ad_spec(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+
+       spec->gen.mixer_nid = 0x20;
+       spec->gen.mixer_merge_nid = 0x21;
+       spec->gen.beep_nid = 0x10;
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+
+       snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = ad198x_parse_auto_config(codec, true);
+       if (err < 0)
+               goto error;
+       err = ad1983_add_spdif_mux_ctl(codec);
+       if (err < 0)
+               goto error;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+/*
+ * AD1882 / AD1882A
+ *
+ * port-A - front hp-out
+ * port-B - front mic-in
+ * port-C - rear line-in, shared surr-out (3stack)
+ * port-D - rear line-out
+ * port-E - rear mic-in, shared clfe-out (3stack)
+ * port-F - rear surr-out (6stack)
+ * port-G - rear clfe-out (6stack)
+ */
+
+static int patch_ad1882(struct hda_codec *codec)
+{
+       struct ad198x_spec *spec;
+       int err;
+
+       err = alloc_ad_spec(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+
+       spec->gen.mixer_nid = 0x20;
+       spec->gen.mixer_merge_nid = 0x21;
+       spec->gen.beep_nid = 0x10;
+       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
+       err = ad198x_parse_auto_config(codec, true);
+       if (err < 0)
+               goto error;
+       err = ad1988_add_spdif_mux_ctl(codec);
+       if (err < 0)
+               goto error;
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_analog[] = {
+       HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
+       HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
+       HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
+       HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
+       HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
+       HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
+       HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
+       HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
+       HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
+       HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Analog Devices HD-audio codec");
+
+static struct hda_codec_driver analog_driver = {
+       .id = snd_hda_id_analog,
+};
+
+module_hda_codec_driver(analog_driver);
diff --git a/sound/hda/codecs/ca0110.c b/sound/hda/codecs/ca0110.c
new file mode 100644 (file)
index 0000000..0353544
--- /dev/null
@@ -0,0 +1,88 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio interface patch for Creative X-Fi CA0110-IBG chip
+ *
+ * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+
+static const struct hda_codec_ops ca0110_patch_ops = {
+       .build_controls = snd_hda_gen_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = snd_hda_gen_init,
+       .free = snd_hda_gen_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+};
+
+static int ca0110_parse_auto_config(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
+       if (err < 0)
+               return err;
+       err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+
+static int patch_ca0110(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       snd_hda_gen_spec_init(spec);
+       codec->spec = spec;
+       codec->patch_ops = ca0110_patch_ops;
+
+       spec->multi_cap_vol = 1;
+       codec->bus->core.needs_damn_long_delay = 1;
+
+       err = ca0110_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_ca0110[] = {
+       HDA_CODEC_ENTRY(0x1102000a, "CA0110-IBG", patch_ca0110),
+       HDA_CODEC_ENTRY(0x1102000b, "CA0110-IBG", patch_ca0110),
+       HDA_CODEC_ENTRY(0x1102000d, "SB0880 X-Fi", patch_ca0110),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0110);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
+
+static struct hda_codec_driver ca0110_driver = {
+       .id = snd_hda_id_ca0110,
+};
+
+module_hda_codec_driver(ca0110_driver);
diff --git a/sound/hda/codecs/ca0132.c b/sound/hda/codecs/ca0132.c
new file mode 100644 (file)
index 0000000..35a9794
--- /dev/null
@@ -0,0 +1,10123 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio interface patch for Creative CA0132 chip
+ *
+ * Copyright (c) 2011, Creative Technology Ltd.
+ *
+ * Based on ca0110.c
+ * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/io.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+
+#include "ca0132_regs.h"
+
+/* Enable this to see controls for tuning purpose. */
+#define ENABLE_TUNING_CONTROLS
+
+#ifdef ENABLE_TUNING_CONTROLS
+#include <sound/tlv.h>
+#endif
+
+#define FLOAT_ZERO     0x00000000
+#define FLOAT_ONE      0x3f800000
+#define FLOAT_TWO      0x40000000
+#define FLOAT_THREE     0x40400000
+#define FLOAT_FIVE     0x40a00000
+#define FLOAT_SIX       0x40c00000
+#define FLOAT_EIGHT     0x41000000
+#define FLOAT_MINUS_5  0xc0a00000
+
+#define UNSOL_TAG_DSP  0x16
+
+#define DSP_DMA_WRITE_BUFLEN_INIT (1UL<<18)
+#define DSP_DMA_WRITE_BUFLEN_OVLY (1UL<<15)
+
+#define DMA_TRANSFER_FRAME_SIZE_NWORDS         8
+#define DMA_TRANSFER_MAX_FRAME_SIZE_NWORDS     32
+#define DMA_OVERLAY_FRAME_SIZE_NWORDS          2
+
+#define MASTERCONTROL                          0x80
+#define MASTERCONTROL_ALLOC_DMA_CHAN           10
+#define MASTERCONTROL_QUERY_SPEAKER_EQ_ADDRESS 60
+
+#define WIDGET_CHIP_CTRL      0x15
+#define WIDGET_DSP_CTRL       0x16
+
+#define MEM_CONNID_MICIN1     3
+#define MEM_CONNID_MICIN2     5
+#define MEM_CONNID_MICOUT1    12
+#define MEM_CONNID_MICOUT2    14
+#define MEM_CONNID_WUH        10
+#define MEM_CONNID_DSP        16
+#define MEM_CONNID_DMIC       100
+
+#define SCP_SET    0
+#define SCP_GET    1
+
+#define EFX_FILE   "ctefx.bin"
+#define DESKTOP_EFX_FILE   "ctefx-desktop.bin"
+#define R3DI_EFX_FILE  "ctefx-r3di.bin"
+
+#ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP
+MODULE_FIRMWARE(EFX_FILE);
+MODULE_FIRMWARE(DESKTOP_EFX_FILE);
+MODULE_FIRMWARE(R3DI_EFX_FILE);
+#endif
+
+static const char *const dirstr[2] = { "Playback", "Capture" };
+
+#define NUM_OF_OUTPUTS 2
+static const char *const out_type_str[2] = { "Speakers", "Headphone" };
+enum {
+       SPEAKER_OUT,
+       HEADPHONE_OUT,
+};
+
+enum {
+       DIGITAL_MIC,
+       LINE_MIC_IN
+};
+
+/* Strings for Input Source Enum Control */
+static const char *const in_src_str[3] = { "Microphone", "Line In", "Front Microphone" };
+#define IN_SRC_NUM_OF_INPUTS 3
+enum {
+       REAR_MIC,
+       REAR_LINE_IN,
+       FRONT_MIC,
+};
+
+enum {
+#define VNODE_START_NID    0x80
+       VNID_SPK = VNODE_START_NID,                     /* Speaker vnid */
+       VNID_MIC,
+       VNID_HP_SEL,
+       VNID_AMIC1_SEL,
+       VNID_HP_ASEL,
+       VNID_AMIC1_ASEL,
+       VNODE_END_NID,
+#define VNODES_COUNT  (VNODE_END_NID - VNODE_START_NID)
+
+#define EFFECT_START_NID    0x90
+#define OUT_EFFECT_START_NID    EFFECT_START_NID
+       SURROUND = OUT_EFFECT_START_NID,
+       CRYSTALIZER,
+       DIALOG_PLUS,
+       SMART_VOLUME,
+       X_BASS,
+       EQUALIZER,
+       OUT_EFFECT_END_NID,
+#define OUT_EFFECTS_COUNT  (OUT_EFFECT_END_NID - OUT_EFFECT_START_NID)
+
+#define IN_EFFECT_START_NID  OUT_EFFECT_END_NID
+       ECHO_CANCELLATION = IN_EFFECT_START_NID,
+       VOICE_FOCUS,
+       MIC_SVM,
+       NOISE_REDUCTION,
+       IN_EFFECT_END_NID,
+#define IN_EFFECTS_COUNT  (IN_EFFECT_END_NID - IN_EFFECT_START_NID)
+
+       VOICEFX = IN_EFFECT_END_NID,
+       PLAY_ENHANCEMENT,
+       CRYSTAL_VOICE,
+       EFFECT_END_NID,
+       OUTPUT_SOURCE_ENUM,
+       INPUT_SOURCE_ENUM,
+       XBASS_XOVER,
+       EQ_PRESET_ENUM,
+       SMART_VOLUME_ENUM,
+       MIC_BOOST_ENUM,
+       AE5_HEADPHONE_GAIN_ENUM,
+       AE5_SOUND_FILTER_ENUM,
+       ZXR_HEADPHONE_GAIN,
+       SPEAKER_CHANNEL_CFG_ENUM,
+       SPEAKER_FULL_RANGE_FRONT,
+       SPEAKER_FULL_RANGE_REAR,
+       BASS_REDIRECTION,
+       BASS_REDIRECTION_XOVER,
+#define EFFECTS_COUNT  (EFFECT_END_NID - EFFECT_START_NID)
+};
+
+/* Effects values size*/
+#define EFFECT_VALS_MAX_COUNT 12
+
+/*
+ * Default values for the effect slider controls, they are in order of their
+ * effect NID's. Surround, Crystalizer, Dialog Plus, Smart Volume, and then
+ * X-bass.
+ */
+static const unsigned int effect_slider_defaults[] = {67, 65, 50, 74, 50};
+/* Amount of effect level sliders for ca0132_alt controls. */
+#define EFFECT_LEVEL_SLIDERS 5
+
+/* Latency introduced by DSP blocks in milliseconds. */
+#define DSP_CAPTURE_INIT_LATENCY        0
+#define DSP_CRYSTAL_VOICE_LATENCY       124
+#define DSP_PLAYBACK_INIT_LATENCY       13
+#define DSP_PLAY_ENHANCEMENT_LATENCY    30
+#define DSP_SPEAKER_OUT_LATENCY         7
+
+struct ct_effect {
+       const char *name;
+       hda_nid_t nid;
+       int mid; /*effect module ID*/
+       int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/
+       int direct; /* 0:output; 1:input*/
+       int params; /* number of default non-on/off params */
+       /*effect default values, 1st is on/off. */
+       unsigned int def_vals[EFFECT_VALS_MAX_COUNT];
+};
+
+#define EFX_DIR_OUT 0
+#define EFX_DIR_IN  1
+
+static const struct ct_effect ca0132_effects[EFFECTS_COUNT] = {
+       { .name = "Surround",
+         .nid = SURROUND,
+         .mid = 0x96,
+         .reqs = {0, 1},
+         .direct = EFX_DIR_OUT,
+         .params = 1,
+         .def_vals = {0x3F800000, 0x3F2B851F}
+       },
+       { .name = "Crystalizer",
+         .nid = CRYSTALIZER,
+         .mid = 0x96,
+         .reqs = {7, 8},
+         .direct = EFX_DIR_OUT,
+         .params = 1,
+         .def_vals = {0x3F800000, 0x3F266666}
+       },
+       { .name = "Dialog Plus",
+         .nid = DIALOG_PLUS,
+         .mid = 0x96,
+         .reqs = {2, 3},
+         .direct = EFX_DIR_OUT,
+         .params = 1,
+         .def_vals = {0x00000000, 0x3F000000}
+       },
+       { .name = "Smart Volume",
+         .nid = SMART_VOLUME,
+         .mid = 0x96,
+         .reqs = {4, 5, 6},
+         .direct = EFX_DIR_OUT,
+         .params = 2,
+         .def_vals = {0x3F800000, 0x3F3D70A4, 0x00000000}
+       },
+       { .name = "X-Bass",
+         .nid = X_BASS,
+         .mid = 0x96,
+         .reqs = {24, 23, 25},
+         .direct = EFX_DIR_OUT,
+         .params = 2,
+         .def_vals = {0x3F800000, 0x42A00000, 0x3F000000}
+       },
+       { .name = "Equalizer",
+         .nid = EQUALIZER,
+         .mid = 0x96,
+         .reqs = {9, 10, 11, 12, 13, 14,
+                       15, 16, 17, 18, 19, 20},
+         .direct = EFX_DIR_OUT,
+         .params = 11,
+         .def_vals = {0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000000,
+                      0x00000000, 0x00000000, 0x00000000, 0x00000000}
+       },
+       { .name = "Echo Cancellation",
+         .nid = ECHO_CANCELLATION,
+         .mid = 0x95,
+         .reqs = {0, 1, 2, 3},
+         .direct = EFX_DIR_IN,
+         .params = 3,
+         .def_vals = {0x00000000, 0x3F3A9692, 0x00000000, 0x00000000}
+       },
+       { .name = "Voice Focus",
+         .nid = VOICE_FOCUS,
+         .mid = 0x95,
+         .reqs = {6, 7, 8, 9},
+         .direct = EFX_DIR_IN,
+         .params = 3,
+         .def_vals = {0x3F800000, 0x3D7DF3B6, 0x41F00000, 0x41F00000}
+       },
+       { .name = "Mic SVM",
+         .nid = MIC_SVM,
+         .mid = 0x95,
+         .reqs = {44, 45},
+         .direct = EFX_DIR_IN,
+         .params = 1,
+         .def_vals = {0x00000000, 0x3F3D70A4}
+       },
+       { .name = "Noise Reduction",
+         .nid = NOISE_REDUCTION,
+         .mid = 0x95,
+         .reqs = {4, 5},
+         .direct = EFX_DIR_IN,
+         .params = 1,
+         .def_vals = {0x3F800000, 0x3F000000}
+       },
+       { .name = "VoiceFX",
+         .nid = VOICEFX,
+         .mid = 0x95,
+         .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18},
+         .direct = EFX_DIR_IN,
+         .params = 8,
+         .def_vals = {0x00000000, 0x43C80000, 0x44AF0000, 0x44FA0000,
+                      0x3F800000, 0x3F800000, 0x3F800000, 0x00000000,
+                      0x00000000}
+       }
+};
+
+/* Tuning controls */
+#ifdef ENABLE_TUNING_CONTROLS
+
+enum {
+#define TUNING_CTL_START_NID  0xC0
+       WEDGE_ANGLE = TUNING_CTL_START_NID,
+       SVM_LEVEL,
+       EQUALIZER_BAND_0,
+       EQUALIZER_BAND_1,
+       EQUALIZER_BAND_2,
+       EQUALIZER_BAND_3,
+       EQUALIZER_BAND_4,
+       EQUALIZER_BAND_5,
+       EQUALIZER_BAND_6,
+       EQUALIZER_BAND_7,
+       EQUALIZER_BAND_8,
+       EQUALIZER_BAND_9,
+       TUNING_CTL_END_NID
+#define TUNING_CTLS_COUNT  (TUNING_CTL_END_NID - TUNING_CTL_START_NID)
+};
+
+struct ct_tuning_ctl {
+       const char *name;
+       hda_nid_t parent_nid;
+       hda_nid_t nid;
+       int mid; /*effect module ID*/
+       int req; /*effect module request*/
+       int direct; /* 0:output; 1:input*/
+       unsigned int def_val;/*effect default values*/
+};
+
+static const struct ct_tuning_ctl ca0132_tuning_ctls[] = {
+       { .name = "Wedge Angle",
+         .parent_nid = VOICE_FOCUS,
+         .nid = WEDGE_ANGLE,
+         .mid = 0x95,
+         .req = 8,
+         .direct = EFX_DIR_IN,
+         .def_val = 0x41F00000
+       },
+       { .name = "SVM Level",
+         .parent_nid = MIC_SVM,
+         .nid = SVM_LEVEL,
+         .mid = 0x95,
+         .req = 45,
+         .direct = EFX_DIR_IN,
+         .def_val = 0x3F3D70A4
+       },
+       { .name = "EQ Band0",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_0,
+         .mid = 0x96,
+         .req = 11,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band1",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_1,
+         .mid = 0x96,
+         .req = 12,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band2",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_2,
+         .mid = 0x96,
+         .req = 13,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band3",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_3,
+         .mid = 0x96,
+         .req = 14,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band4",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_4,
+         .mid = 0x96,
+         .req = 15,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band5",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_5,
+         .mid = 0x96,
+         .req = 16,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band6",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_6,
+         .mid = 0x96,
+         .req = 17,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band7",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_7,
+         .mid = 0x96,
+         .req = 18,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band8",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_8,
+         .mid = 0x96,
+         .req = 19,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       },
+       { .name = "EQ Band9",
+         .parent_nid = EQUALIZER,
+         .nid = EQUALIZER_BAND_9,
+         .mid = 0x96,
+         .req = 20,
+         .direct = EFX_DIR_OUT,
+         .def_val = 0x00000000
+       }
+};
+#endif
+
+/* Voice FX Presets */
+#define VOICEFX_MAX_PARAM_COUNT 9
+
+struct ct_voicefx {
+       const char *name;
+       hda_nid_t nid;
+       int mid;
+       int reqs[VOICEFX_MAX_PARAM_COUNT]; /*effect module request*/
+};
+
+struct ct_voicefx_preset {
+       const char *name; /*preset name*/
+       unsigned int vals[VOICEFX_MAX_PARAM_COUNT];
+};
+
+static const struct ct_voicefx ca0132_voicefx = {
+       .name = "VoiceFX Capture Switch",
+       .nid = VOICEFX,
+       .mid = 0x95,
+       .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18}
+};
+
+static const struct ct_voicefx_preset ca0132_voicefx_presets[] = {
+       { .name = "Neutral",
+         .vals = { 0x00000000, 0x43C80000, 0x44AF0000,
+                   0x44FA0000, 0x3F800000, 0x3F800000,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       },
+       { .name = "Female2Male",
+         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
+                   0x44FA0000, 0x3F19999A, 0x3F866666,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       },
+       { .name = "Male2Female",
+         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
+                   0x450AC000, 0x4017AE14, 0x3F6B851F,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       },
+       { .name = "ScrappyKid",
+         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
+                   0x44FA0000, 0x40400000, 0x3F28F5C3,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       },
+       { .name = "Elderly",
+         .vals = { 0x3F800000, 0x44324000, 0x44BB8000,
+                   0x44E10000, 0x3FB33333, 0x3FB9999A,
+                   0x3F800000, 0x3E3A2E43, 0x00000000 }
+       },
+       { .name = "Orc",
+         .vals = { 0x3F800000, 0x43EA0000, 0x44A52000,
+                   0x45098000, 0x3F266666, 0x3FC00000,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       },
+       { .name = "Elf",
+         .vals = { 0x3F800000, 0x43C70000, 0x44AE6000,
+                   0x45193000, 0x3F8E147B, 0x3F75C28F,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       },
+       { .name = "Dwarf",
+         .vals = { 0x3F800000, 0x43930000, 0x44BEE000,
+                   0x45007000, 0x3F451EB8, 0x3F7851EC,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       },
+       { .name = "AlienBrute",
+         .vals = { 0x3F800000, 0x43BFC5AC, 0x44B28FDF,
+                   0x451F6000, 0x3F266666, 0x3FA7D945,
+                   0x3F800000, 0x3CF5C28F, 0x00000000 }
+       },
+       { .name = "Robot",
+         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
+                   0x44FA0000, 0x3FB2718B, 0x3F800000,
+                   0xBC07010E, 0x00000000, 0x00000000 }
+       },
+       { .name = "Marine",
+         .vals = { 0x3F800000, 0x43C20000, 0x44906000,
+                   0x44E70000, 0x3F4CCCCD, 0x3F8A3D71,
+                   0x3F0A3D71, 0x00000000, 0x00000000 }
+       },
+       { .name = "Emo",
+         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
+                   0x44FA0000, 0x3F800000, 0x3F800000,
+                   0x3E4CCCCD, 0x00000000, 0x00000000 }
+       },
+       { .name = "DeepVoice",
+         .vals = { 0x3F800000, 0x43A9C5AC, 0x44AA4FDF,
+                   0x44FFC000, 0x3EDBB56F, 0x3F99C4CA,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       },
+       { .name = "Munchkin",
+         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
+                   0x44FA0000, 0x3F800000, 0x3F1A043C,
+                   0x3F800000, 0x00000000, 0x00000000 }
+       }
+};
+
+/* ca0132 EQ presets, taken from Windows Sound Blaster Z Driver */
+
+#define EQ_PRESET_MAX_PARAM_COUNT 11
+
+struct ct_eq {
+       const char *name;
+       hda_nid_t nid;
+       int mid;
+       int reqs[EQ_PRESET_MAX_PARAM_COUNT]; /*effect module request*/
+};
+
+struct ct_eq_preset {
+       const char *name; /*preset name*/
+       unsigned int vals[EQ_PRESET_MAX_PARAM_COUNT];
+};
+
+static const struct ct_eq ca0132_alt_eq_enum = {
+       .name = "FX: Equalizer Preset Switch",
+       .nid = EQ_PRESET_ENUM,
+       .mid = 0x96,
+       .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
+};
+
+
+static const struct ct_eq_preset ca0132_alt_eq_presets[] = {
+       { .name = "Flat",
+        .vals = { 0x00000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x00000000            }
+       },
+       { .name = "Acoustic",
+        .vals = { 0x00000000, 0x00000000, 0x3F8CCCCD,
+                  0x40000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x00000000, 0x40000000,
+                  0x40000000, 0x40000000            }
+       },
+       { .name = "Classical",
+        .vals = { 0x00000000, 0x00000000, 0x40C00000,
+                  0x40C00000, 0x40466666, 0x00000000,
+                  0x00000000, 0x00000000, 0x00000000,
+                  0x40466666, 0x40466666            }
+       },
+       { .name = "Country",
+        .vals = { 0x00000000, 0xBF99999A, 0x00000000,
+                  0x3FA66666, 0x3FA66666, 0x3F8CCCCD,
+                  0x00000000, 0x00000000, 0x40000000,
+                  0x40466666, 0x40800000            }
+       },
+       { .name = "Dance",
+        .vals = { 0x00000000, 0xBF99999A, 0x40000000,
+                  0x40466666, 0x40866666, 0xBF99999A,
+                  0xBF99999A, 0x00000000, 0x00000000,
+                  0x40800000, 0x40800000            }
+       },
+       { .name = "Jazz",
+        .vals = { 0x00000000, 0x00000000, 0x00000000,
+                  0x3F8CCCCD, 0x40800000, 0x40800000,
+                  0x40800000, 0x00000000, 0x3F8CCCCD,
+                  0x40466666, 0x40466666            }
+       },
+       { .name = "New Age",
+        .vals = { 0x00000000, 0x00000000, 0x40000000,
+                  0x40000000, 0x00000000, 0x00000000,
+                  0x00000000, 0x3F8CCCCD, 0x40000000,
+                  0x40000000, 0x40000000            }
+       },
+       { .name = "Pop",
+        .vals = { 0x00000000, 0xBFCCCCCD, 0x00000000,
+                  0x40000000, 0x40000000, 0x00000000,
+                  0xBF99999A, 0xBF99999A, 0x00000000,
+                  0x40466666, 0x40C00000            }
+       },
+       { .name = "Rock",
+        .vals = { 0x00000000, 0xBF99999A, 0xBF99999A,
+                  0x3F8CCCCD, 0x40000000, 0xBF99999A,
+                  0xBF99999A, 0x00000000, 0x00000000,
+                  0x40800000, 0x40800000            }
+       },
+       { .name = "Vocal",
+        .vals = { 0x00000000, 0xC0000000, 0xBF99999A,
+                  0xBF99999A, 0x00000000, 0x40466666,
+                  0x40800000, 0x40466666, 0x00000000,
+                  0x00000000, 0x3F8CCCCD            }
+       }
+};
+
+/*
+ * DSP reqs for handling full-range speakers/bass redirection. If a speaker is
+ * set as not being full range, and bass redirection is enabled, all
+ * frequencies below the crossover frequency are redirected to the LFE
+ * channel. If the surround configuration has no LFE channel, this can't be
+ * enabled. X-Bass must be disabled when using these.
+ */
+enum speaker_range_reqs {
+       SPEAKER_BASS_REDIRECT            = 0x15,
+       SPEAKER_BASS_REDIRECT_XOVER_FREQ = 0x16,
+       /* Between 0x16-0x1a are the X-Bass reqs. */
+       SPEAKER_FULL_RANGE_FRONT_L_R     = 0x1a,
+       SPEAKER_FULL_RANGE_CENTER_LFE    = 0x1b,
+       SPEAKER_FULL_RANGE_REAR_L_R      = 0x1c,
+       SPEAKER_FULL_RANGE_SURROUND_L_R  = 0x1d,
+       SPEAKER_BASS_REDIRECT_SUB_GAIN   = 0x1e,
+};
+
+/*
+ * Definitions for the DSP req's to handle speaker tuning. These all belong to
+ * module ID 0x96, the output effects module.
+ */
+enum speaker_tuning_reqs {
+       /*
+        * Currently, this value is always set to 0.0f. However, on Windows,
+        * when selecting certain headphone profiles on the new Sound Blaster
+        * connect software, the QUERY_SPEAKER_EQ_ADDRESS req on mid 0x80 is
+        * sent. This gets the speaker EQ address area, which is then used to
+        * send over (presumably) an equalizer profile for the specific
+        * headphone setup. It is sent using the same method the DSP
+        * firmware is uploaded with, which I believe is why the 'ctspeq.bin'
+        * file exists in linux firmware tree but goes unused. It would also
+        * explain why the QUERY_SPEAKER_EQ_ADDRESS req is defined but unused.
+        * Once this profile is sent over, SPEAKER_TUNING_USE_SPEAKER_EQ is
+        * set to 1.0f.
+        */
+       SPEAKER_TUNING_USE_SPEAKER_EQ           = 0x1f,
+       SPEAKER_TUNING_ENABLE_CENTER_EQ         = 0x20,
+       SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL     = 0x21,
+       SPEAKER_TUNING_FRONT_RIGHT_VOL_LEVEL    = 0x22,
+       SPEAKER_TUNING_CENTER_VOL_LEVEL         = 0x23,
+       SPEAKER_TUNING_LFE_VOL_LEVEL            = 0x24,
+       SPEAKER_TUNING_REAR_LEFT_VOL_LEVEL      = 0x25,
+       SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL     = 0x26,
+       SPEAKER_TUNING_SURROUND_LEFT_VOL_LEVEL  = 0x27,
+       SPEAKER_TUNING_SURROUND_RIGHT_VOL_LEVEL = 0x28,
+       /*
+        * Inversion is used when setting headphone virtualization to line
+        * out. Not sure why this is, but it's the only place it's ever used.
+        */
+       SPEAKER_TUNING_FRONT_LEFT_INVERT        = 0x29,
+       SPEAKER_TUNING_FRONT_RIGHT_INVERT       = 0x2a,
+       SPEAKER_TUNING_CENTER_INVERT            = 0x2b,
+       SPEAKER_TUNING_LFE_INVERT               = 0x2c,
+       SPEAKER_TUNING_REAR_LEFT_INVERT         = 0x2d,
+       SPEAKER_TUNING_REAR_RIGHT_INVERT        = 0x2e,
+       SPEAKER_TUNING_SURROUND_LEFT_INVERT     = 0x2f,
+       SPEAKER_TUNING_SURROUND_RIGHT_INVERT    = 0x30,
+       /* Delay is used when setting surround speaker distance in Windows. */
+       SPEAKER_TUNING_FRONT_LEFT_DELAY         = 0x31,
+       SPEAKER_TUNING_FRONT_RIGHT_DELAY        = 0x32,
+       SPEAKER_TUNING_CENTER_DELAY             = 0x33,
+       SPEAKER_TUNING_LFE_DELAY                = 0x34,
+       SPEAKER_TUNING_REAR_LEFT_DELAY          = 0x35,
+       SPEAKER_TUNING_REAR_RIGHT_DELAY         = 0x36,
+       SPEAKER_TUNING_SURROUND_LEFT_DELAY      = 0x37,
+       SPEAKER_TUNING_SURROUND_RIGHT_DELAY     = 0x38,
+       /* Of these two, only mute seems to ever be used. */
+       SPEAKER_TUNING_MAIN_VOLUME              = 0x39,
+       SPEAKER_TUNING_MUTE                     = 0x3a,
+};
+
+/* Surround output channel count configuration structures. */
+#define SPEAKER_CHANNEL_CFG_COUNT 5
+enum {
+       SPEAKER_CHANNELS_2_0,
+       SPEAKER_CHANNELS_2_1,
+       SPEAKER_CHANNELS_4_0,
+       SPEAKER_CHANNELS_4_1,
+       SPEAKER_CHANNELS_5_1,
+};
+
+struct ca0132_alt_speaker_channel_cfg {
+       const char *name;
+       unsigned int val;
+};
+
+static const struct ca0132_alt_speaker_channel_cfg speaker_channel_cfgs[] = {
+       { .name = "2.0",
+         .val = FLOAT_ONE
+       },
+       { .name = "2.1",
+         .val = FLOAT_TWO
+       },
+       { .name = "4.0",
+         .val = FLOAT_FIVE
+       },
+       { .name = "4.1",
+         .val = FLOAT_SIX
+       },
+       { .name = "5.1",
+         .val = FLOAT_EIGHT
+       }
+};
+
+/*
+ * DSP volume setting structs. Req 1 is left volume, req 2 is right volume,
+ * and I don't know what the third req is, but it's always zero. I assume it's
+ * some sort of update or set command to tell the DSP there's new volume info.
+ */
+#define DSP_VOL_OUT 0
+#define DSP_VOL_IN  1
+
+struct ct_dsp_volume_ctl {
+       hda_nid_t vnid;
+       int mid; /* module ID*/
+       unsigned int reqs[3]; /* scp req ID */
+};
+
+static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = {
+       { .vnid = VNID_SPK,
+         .mid = 0x32,
+         .reqs = {3, 4, 2}
+       },
+       { .vnid = VNID_MIC,
+         .mid = 0x37,
+         .reqs = {2, 3, 1}
+       }
+};
+
+/* Values for ca0113_mmio_command_set for selecting output. */
+#define AE_CA0113_OUT_SET_COMMANDS 6
+struct ae_ca0113_output_set {
+       unsigned int group[AE_CA0113_OUT_SET_COMMANDS];
+       unsigned int target[AE_CA0113_OUT_SET_COMMANDS];
+       unsigned int vals[NUM_OF_OUTPUTS][AE_CA0113_OUT_SET_COMMANDS];
+};
+
+static const struct ae_ca0113_output_set ae5_ca0113_output_presets = {
+       .group =  { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+       .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+                   /* Speakers. */
+       .vals =   { { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f },
+                   /* Headphones. */
+                   { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 } },
+};
+
+static const struct ae_ca0113_output_set ae7_ca0113_output_presets = {
+       .group  = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
+       .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
+                   /* Speakers. */
+       .vals   = { { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f },
+                   /* Headphones. */
+                   { 0x3f, 0x3f, 0x00, 0x00, 0x02, 0x00 } },
+};
+
+/* ae5 ca0113 command sequences to set headphone gain levels. */
+#define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4
+struct ae5_headphone_gain_set {
+       const char *name;
+       unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS];
+};
+
+static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = {
+       { .name = "Low (16-31",
+         .vals = { 0xff, 0x2c, 0xf5, 0x32 }
+       },
+       { .name = "Medium (32-149",
+         .vals = { 0x38, 0xa8, 0x3e, 0x4c }
+       },
+       { .name = "High (150-600",
+         .vals = { 0xff, 0xff, 0xff, 0x7f }
+       }
+};
+
+struct ae5_filter_set {
+       const char *name;
+       unsigned int val;
+};
+
+static const struct ae5_filter_set ae5_filter_presets[] = {
+       { .name = "Slow Roll Off",
+         .val = 0xa0
+       },
+       { .name = "Minimum Phase",
+         .val = 0xc0
+       },
+       { .name = "Fast Roll Off",
+         .val = 0x80
+       }
+};
+
+/*
+ * Data structures for storing audio router remapping data. These are used to
+ * remap a currently active streams ports.
+ */
+struct chipio_stream_remap_data {
+       unsigned int stream_id;
+       unsigned int count;
+
+       unsigned int offset[16];
+       unsigned int value[16];
+};
+
+static const struct chipio_stream_remap_data stream_remap_data[] = {
+       { .stream_id = 0x14,
+         .count     = 0x04,
+         .offset    = { 0x00, 0x04, 0x08, 0x0c },
+         .value     = { 0x0001f8c0, 0x0001f9c1, 0x0001fac6, 0x0001fbc7 },
+       },
+       { .stream_id = 0x0c,
+         .count     = 0x0c,
+         .offset    = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
+                        0x20, 0x24, 0x28, 0x2c },
+         .value     = { 0x0001e0c0, 0x0001e1c1, 0x0001e4c2, 0x0001e5c3,
+                        0x0001e2c4, 0x0001e3c5, 0x0001e8c6, 0x0001e9c7,
+                        0x0001ecc8, 0x0001edc9, 0x0001eaca, 0x0001ebcb },
+       },
+       { .stream_id = 0x0c,
+         .count     = 0x08,
+         .offset    = { 0x08, 0x0c, 0x10, 0x14, 0x20, 0x24, 0x28, 0x2c },
+         .value     = { 0x000140c2, 0x000141c3, 0x000150c4, 0x000151c5,
+                        0x000142c8, 0x000143c9, 0x000152ca, 0x000153cb },
+       }
+};
+
+enum hda_cmd_vendor_io {
+       /* for DspIO node */
+       VENDOR_DSPIO_SCP_WRITE_DATA_LOW      = 0x000,
+       VENDOR_DSPIO_SCP_WRITE_DATA_HIGH     = 0x100,
+
+       VENDOR_DSPIO_STATUS                  = 0xF01,
+       VENDOR_DSPIO_SCP_POST_READ_DATA      = 0x702,
+       VENDOR_DSPIO_SCP_READ_DATA           = 0xF02,
+       VENDOR_DSPIO_DSP_INIT                = 0x703,
+       VENDOR_DSPIO_SCP_POST_COUNT_QUERY    = 0x704,
+       VENDOR_DSPIO_SCP_READ_COUNT          = 0xF04,
+
+       /* for ChipIO node */
+       VENDOR_CHIPIO_ADDRESS_LOW            = 0x000,
+       VENDOR_CHIPIO_ADDRESS_HIGH           = 0x100,
+       VENDOR_CHIPIO_STREAM_FORMAT          = 0x200,
+       VENDOR_CHIPIO_DATA_LOW               = 0x300,
+       VENDOR_CHIPIO_DATA_HIGH              = 0x400,
+
+       VENDOR_CHIPIO_8051_WRITE_DIRECT      = 0x500,
+       VENDOR_CHIPIO_8051_READ_DIRECT       = 0xD00,
+
+       VENDOR_CHIPIO_GET_PARAMETER          = 0xF00,
+       VENDOR_CHIPIO_STATUS                 = 0xF01,
+       VENDOR_CHIPIO_HIC_POST_READ          = 0x702,
+       VENDOR_CHIPIO_HIC_READ_DATA          = 0xF03,
+
+       VENDOR_CHIPIO_8051_DATA_WRITE        = 0x707,
+       VENDOR_CHIPIO_8051_DATA_READ         = 0xF07,
+       VENDOR_CHIPIO_8051_PMEM_READ         = 0xF08,
+       VENDOR_CHIPIO_8051_IRAM_WRITE        = 0x709,
+       VENDOR_CHIPIO_8051_IRAM_READ         = 0xF09,
+
+       VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE   = 0x70A,
+       VENDOR_CHIPIO_CT_EXTENSIONS_GET      = 0xF0A,
+
+       VENDOR_CHIPIO_PLL_PMU_WRITE          = 0x70C,
+       VENDOR_CHIPIO_PLL_PMU_READ           = 0xF0C,
+       VENDOR_CHIPIO_8051_ADDRESS_LOW       = 0x70D,
+       VENDOR_CHIPIO_8051_ADDRESS_HIGH      = 0x70E,
+       VENDOR_CHIPIO_FLAG_SET               = 0x70F,
+       VENDOR_CHIPIO_FLAGS_GET              = 0xF0F,
+       VENDOR_CHIPIO_PARAM_SET              = 0x710,
+       VENDOR_CHIPIO_PARAM_GET              = 0xF10,
+
+       VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET  = 0x711,
+       VENDOR_CHIPIO_PORT_ALLOC_SET         = 0x712,
+       VENDOR_CHIPIO_PORT_ALLOC_GET         = 0xF12,
+       VENDOR_CHIPIO_PORT_FREE_SET          = 0x713,
+
+       VENDOR_CHIPIO_PARAM_EX_ID_GET        = 0xF17,
+       VENDOR_CHIPIO_PARAM_EX_ID_SET        = 0x717,
+       VENDOR_CHIPIO_PARAM_EX_VALUE_GET     = 0xF18,
+       VENDOR_CHIPIO_PARAM_EX_VALUE_SET     = 0x718,
+
+       VENDOR_CHIPIO_DMIC_CTL_SET           = 0x788,
+       VENDOR_CHIPIO_DMIC_CTL_GET           = 0xF88,
+       VENDOR_CHIPIO_DMIC_PIN_SET           = 0x789,
+       VENDOR_CHIPIO_DMIC_PIN_GET           = 0xF89,
+       VENDOR_CHIPIO_DMIC_MCLK_SET          = 0x78A,
+       VENDOR_CHIPIO_DMIC_MCLK_GET          = 0xF8A,
+
+       VENDOR_CHIPIO_EAPD_SEL_SET           = 0x78D
+};
+
+/*
+ *  Control flag IDs
+ */
+enum control_flag_id {
+       /* Connection manager stream setup is bypassed/enabled */
+       CONTROL_FLAG_C_MGR                  = 0,
+       /* DSP DMA is bypassed/enabled */
+       CONTROL_FLAG_DMA                    = 1,
+       /* 8051 'idle' mode is disabled/enabled */
+       CONTROL_FLAG_IDLE_ENABLE            = 2,
+       /* Tracker for the SPDIF-in path is bypassed/enabled */
+       CONTROL_FLAG_TRACKER                = 3,
+       /* DigitalOut to Spdif2Out connection is disabled/enabled */
+       CONTROL_FLAG_SPDIF2OUT              = 4,
+       /* Digital Microphone is disabled/enabled */
+       CONTROL_FLAG_DMIC                   = 5,
+       /* ADC_B rate is 48 kHz/96 kHz */
+       CONTROL_FLAG_ADC_B_96KHZ            = 6,
+       /* ADC_C rate is 48 kHz/96 kHz */
+       CONTROL_FLAG_ADC_C_96KHZ            = 7,
+       /* DAC rate is 48 kHz/96 kHz (affects all DACs) */
+       CONTROL_FLAG_DAC_96KHZ              = 8,
+       /* DSP rate is 48 kHz/96 kHz */
+       CONTROL_FLAG_DSP_96KHZ              = 9,
+       /* SRC clock is 98 MHz/196 MHz (196 MHz forces rate to 96 KHz) */
+       CONTROL_FLAG_SRC_CLOCK_196MHZ       = 10,
+       /* SRC rate is 48 kHz/96 kHz (48 kHz disabled when clock is 196 MHz) */
+       CONTROL_FLAG_SRC_RATE_96KHZ         = 11,
+       /* Decode Loop (DSP->SRC->DSP) is disabled/enabled */
+       CONTROL_FLAG_DECODE_LOOP            = 12,
+       /* De-emphasis filter on DAC-1 disabled/enabled */
+       CONTROL_FLAG_DAC1_DEEMPHASIS        = 13,
+       /* De-emphasis filter on DAC-2 disabled/enabled */
+       CONTROL_FLAG_DAC2_DEEMPHASIS        = 14,
+       /* De-emphasis filter on DAC-3 disabled/enabled */
+       CONTROL_FLAG_DAC3_DEEMPHASIS        = 15,
+       /* High-pass filter on ADC_B disabled/enabled */
+       CONTROL_FLAG_ADC_B_HIGH_PASS        = 16,
+       /* High-pass filter on ADC_C disabled/enabled */
+       CONTROL_FLAG_ADC_C_HIGH_PASS        = 17,
+       /* Common mode on Port_A disabled/enabled */
+       CONTROL_FLAG_PORT_A_COMMON_MODE     = 18,
+       /* Common mode on Port_D disabled/enabled */
+       CONTROL_FLAG_PORT_D_COMMON_MODE     = 19,
+       /* Impedance for ramp generator on Port_A 16 Ohm/10K Ohm */
+       CONTROL_FLAG_PORT_A_10KOHM_LOAD     = 20,
+       /* Impedance for ramp generator on Port_D, 16 Ohm/10K Ohm */
+       CONTROL_FLAG_PORT_D_10KOHM_LOAD     = 21,
+       /* ASI rate is 48kHz/96kHz */
+       CONTROL_FLAG_ASI_96KHZ              = 22,
+       /* DAC power settings able to control attached ports no/yes */
+       CONTROL_FLAG_DACS_CONTROL_PORTS     = 23,
+       /* Clock Stop OK reporting is disabled/enabled */
+       CONTROL_FLAG_CONTROL_STOP_OK_ENABLE = 24,
+       /* Number of control flags */
+       CONTROL_FLAGS_MAX = (CONTROL_FLAG_CONTROL_STOP_OK_ENABLE+1)
+};
+
+/*
+ * Control parameter IDs
+ */
+enum control_param_id {
+       /* 0: None, 1: Mic1In*/
+       CONTROL_PARAM_VIP_SOURCE               = 1,
+       /* 0: force HDA, 1: allow DSP if HDA Spdif1Out stream is idle */
+       CONTROL_PARAM_SPDIF1_SOURCE            = 2,
+       /* Port A output stage gain setting to use when 16 Ohm output
+        * impedance is selected*/
+       CONTROL_PARAM_PORTA_160OHM_GAIN        = 8,
+       /* Port D output stage gain setting to use when 16 Ohm output
+        * impedance is selected*/
+       CONTROL_PARAM_PORTD_160OHM_GAIN        = 10,
+
+       /*
+        * This control param name was found in the 8051 memory, and makes
+        * sense given the fact the AE-5 uses it and has the ASI flag set.
+        */
+       CONTROL_PARAM_ASI                      = 23,
+
+       /* Stream Control */
+
+       /* Select stream with the given ID */
+       CONTROL_PARAM_STREAM_ID                = 24,
+       /* Source connection point for the selected stream */
+       CONTROL_PARAM_STREAM_SOURCE_CONN_POINT = 25,
+       /* Destination connection point for the selected stream */
+       CONTROL_PARAM_STREAM_DEST_CONN_POINT   = 26,
+       /* Number of audio channels in the selected stream */
+       CONTROL_PARAM_STREAMS_CHANNELS         = 27,
+       /*Enable control for the selected stream */
+       CONTROL_PARAM_STREAM_CONTROL           = 28,
+
+       /* Connection Point Control */
+
+       /* Select connection point with the given ID */
+       CONTROL_PARAM_CONN_POINT_ID            = 29,
+       /* Connection point sample rate */
+       CONTROL_PARAM_CONN_POINT_SAMPLE_RATE   = 30,
+
+       /* Node Control */
+
+       /* Select HDA node with the given ID */
+       CONTROL_PARAM_NODE_ID                  = 31
+};
+
+/*
+ *  Dsp Io Status codes
+ */
+enum hda_vendor_status_dspio {
+       /* Success */
+       VENDOR_STATUS_DSPIO_OK                       = 0x00,
+       /* Busy, unable to accept new command, the host must retry */
+       VENDOR_STATUS_DSPIO_BUSY                     = 0x01,
+       /* SCP command queue is full */
+       VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL   = 0x02,
+       /* SCP response queue is empty */
+       VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY = 0x03
+};
+
+/*
+ *  Chip Io Status codes
+ */
+enum hda_vendor_status_chipio {
+       /* Success */
+       VENDOR_STATUS_CHIPIO_OK   = 0x00,
+       /* Busy, unable to accept new command, the host must retry */
+       VENDOR_STATUS_CHIPIO_BUSY = 0x01
+};
+
+/*
+ *  CA0132 sample rate
+ */
+enum ca0132_sample_rate {
+       SR_6_000        = 0x00,
+       SR_8_000        = 0x01,
+       SR_9_600        = 0x02,
+       SR_11_025       = 0x03,
+       SR_16_000       = 0x04,
+       SR_22_050       = 0x05,
+       SR_24_000       = 0x06,
+       SR_32_000       = 0x07,
+       SR_44_100       = 0x08,
+       SR_48_000       = 0x09,
+       SR_88_200       = 0x0A,
+       SR_96_000       = 0x0B,
+       SR_144_000      = 0x0C,
+       SR_176_400      = 0x0D,
+       SR_192_000      = 0x0E,
+       SR_384_000      = 0x0F,
+
+       SR_COUNT        = 0x10,
+
+       SR_RATE_UNKNOWN = 0x1F
+};
+
+enum dsp_download_state {
+       DSP_DOWNLOAD_FAILED = -1,
+       DSP_DOWNLOAD_INIT   = 0,
+       DSP_DOWNLOADING     = 1,
+       DSP_DOWNLOADED      = 2
+};
+
+/* retrieve parameters from hda format */
+#define get_hdafmt_chs(fmt)    (fmt & 0xf)
+#define get_hdafmt_bits(fmt)   ((fmt >> 4) & 0x7)
+#define get_hdafmt_rate(fmt)   ((fmt >> 8) & 0x7f)
+#define get_hdafmt_type(fmt)   ((fmt >> 15) & 0x1)
+
+/*
+ * CA0132 specific
+ */
+
+struct ca0132_spec {
+       const struct snd_kcontrol_new *mixers[5];
+       unsigned int num_mixers;
+       const struct hda_verb *base_init_verbs;
+       const struct hda_verb *base_exit_verbs;
+       const struct hda_verb *chip_init_verbs;
+       const struct hda_verb *desktop_init_verbs;
+       struct hda_verb *spec_init_verbs;
+       struct auto_pin_cfg autocfg;
+
+       /* Nodes configurations */
+       struct hda_multi_out multiout;
+       hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
+       hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
+       unsigned int num_outputs;
+       hda_nid_t input_pins[AUTO_PIN_LAST];
+       hda_nid_t adcs[AUTO_PIN_LAST];
+       hda_nid_t dig_out;
+       hda_nid_t dig_in;
+       unsigned int num_inputs;
+       hda_nid_t shared_mic_nid;
+       hda_nid_t shared_out_nid;
+       hda_nid_t unsol_tag_hp;
+       hda_nid_t unsol_tag_front_hp; /* for desktop ca0132 codecs */
+       hda_nid_t unsol_tag_amic1;
+
+       /* chip access */
+       struct mutex chipio_mutex; /* chip access mutex */
+       u32 curr_chip_addx;
+
+       /* DSP download related */
+       enum dsp_download_state dsp_state;
+       unsigned int dsp_stream_id;
+       unsigned int wait_scp;
+       unsigned int wait_scp_header;
+       unsigned int wait_num_data;
+       unsigned int scp_resp_header;
+       unsigned int scp_resp_data[4];
+       unsigned int scp_resp_count;
+       bool startup_check_entered;
+       bool dsp_reload;
+
+       /* mixer and effects related */
+       unsigned char dmic_ctl;
+       int cur_out_type;
+       int cur_mic_type;
+       long vnode_lvol[VNODES_COUNT];
+       long vnode_rvol[VNODES_COUNT];
+       long vnode_lswitch[VNODES_COUNT];
+       long vnode_rswitch[VNODES_COUNT];
+       long effects_switch[EFFECTS_COUNT];
+       long voicefx_val;
+       long cur_mic_boost;
+       /* ca0132_alt control related values */
+       unsigned char in_enum_val;
+       unsigned char out_enum_val;
+       unsigned char channel_cfg_val;
+       unsigned char speaker_range_val[2];
+       unsigned char mic_boost_enum_val;
+       unsigned char smart_volume_setting;
+       unsigned char bass_redirection_val;
+       long bass_redirect_xover_freq;
+       long fx_ctl_val[EFFECT_LEVEL_SLIDERS];
+       long xbass_xover_freq;
+       long eq_preset_val;
+       unsigned int tlv[4];
+       struct hda_vmaster_mute_hook vmaster_mute;
+       /* AE-5 Control values */
+       unsigned char ae5_headphone_gain_val;
+       unsigned char ae5_filter_val;
+       /* ZxR Control Values */
+       unsigned char zxr_gain_set;
+
+       struct hda_codec *codec;
+       struct delayed_work unsol_hp_work;
+
+#ifdef ENABLE_TUNING_CONTROLS
+       long cur_ctl_vals[TUNING_CTLS_COUNT];
+#endif
+       /*
+        * The Recon3D, Sound Blaster Z, Sound Blaster ZxR, and Sound Blaster
+        * AE-5 all use PCI region 2 to toggle GPIO and other currently unknown
+        * things.
+        */
+       bool use_pci_mmio;
+       void __iomem *mem_base;
+
+       /*
+        * Whether or not to use the alt functions like alt_select_out,
+        * alt_select_in, etc. Only used on desktop codecs for now, because of
+        * surround sound support.
+        */
+       bool use_alt_functions;
+
+       /*
+        * Whether or not to use alt controls:  volume effect sliders, EQ
+        * presets, smart volume presets, and new control names with FX prefix.
+        * Renames PlayEnhancement and CrystalVoice too.
+        */
+       bool use_alt_controls;
+};
+
+/*
+ * CA0132 quirks table
+ */
+enum {
+       QUIRK_ALIENWARE,
+       QUIRK_ALIENWARE_M17XR4,
+       QUIRK_SBZ,
+       QUIRK_ZXR,
+       QUIRK_ZXR_DBPRO,
+       QUIRK_R3DI,
+       QUIRK_R3D,
+       QUIRK_AE5,
+       QUIRK_AE7,
+       QUIRK_NONE = HDA_FIXUP_ID_NOT_SET,
+};
+
+#ifdef CONFIG_PCI
+#define ca0132_quirk(spec)             ((spec)->codec->fixup_id)
+#define ca0132_use_pci_mmio(spec)      ((spec)->use_pci_mmio)
+#define ca0132_use_alt_functions(spec) ((spec)->use_alt_functions)
+#define ca0132_use_alt_controls(spec)  ((spec)->use_alt_controls)
+#else
+#define ca0132_quirk(spec)             ({ (void)(spec); QUIRK_NONE; })
+#define ca0132_use_alt_functions(spec) ({ (void)(spec); false; })
+#define ca0132_use_pci_mmio(spec)      ({ (void)(spec); false; })
+#define ca0132_use_alt_controls(spec)  ({ (void)(spec); false; })
+#endif
+
+static const struct hda_pintbl alienware_pincfgs[] = {
+       { 0x0b, 0x90170110 }, /* Builtin Speaker */
+       { 0x0c, 0x411111f0 }, /* N/A */
+       { 0x0d, 0x411111f0 }, /* N/A */
+       { 0x0e, 0x411111f0 }, /* N/A */
+       { 0x0f, 0x0321101f }, /* HP */
+       { 0x10, 0x411111f0 }, /* Headset?  disabled for now */
+       { 0x11, 0x03a11021 }, /* Mic */
+       { 0x12, 0xd5a30140 }, /* Builtin Mic */
+       { 0x13, 0x411111f0 }, /* N/A */
+       { 0x18, 0x411111f0 }, /* N/A */
+       {}
+};
+
+/* Sound Blaster Z pin configs taken from Windows Driver */
+static const struct hda_pintbl sbz_pincfgs[] = {
+       { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
+       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
+       { 0x0d, 0x014510f0 }, /* Digital Out */
+       { 0x0e, 0x01c510f0 }, /* SPDIF In */
+       { 0x0f, 0x0221701f }, /* Port A -- BackPanel HP */
+       { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
+       { 0x11, 0x01017014 }, /* Port B -- LineMicIn2 / Rear L/R */
+       { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
+       { 0x13, 0x908700f0 }, /* What U Hear In*/
+       { 0x18, 0x50d000f0 }, /* N/A */
+       {}
+};
+
+/* Sound Blaster ZxR pin configs taken from Windows Driver */
+static const struct hda_pintbl zxr_pincfgs[] = {
+       { 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */
+       { 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/
+       { 0x0d, 0x014510f0 }, /* Digital Out */
+       { 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/
+       { 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */
+       { 0x10, 0x01017111 }, /* Port D -- Center/LFE */
+       { 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */
+       { 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */
+       { 0x13, 0x908700f0 }, /* What U Hear In*/
+       { 0x18, 0x50d000f0 }, /* N/A */
+       {}
+};
+
+/* Recon3D pin configs taken from Windows Driver */
+static const struct hda_pintbl r3d_pincfgs[] = {
+       { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
+       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
+       { 0x0d, 0x014510f0 }, /* Digital Out */
+       { 0x0e, 0x01c520f0 }, /* SPDIF In */
+       { 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
+       { 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
+       { 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
+       { 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
+       { 0x13, 0x908700f0 }, /* What U Hear In*/
+       { 0x18, 0x50d000f0 }, /* N/A */
+       {}
+};
+
+/* Sound Blaster AE-5 pin configs taken from Windows Driver */
+static const struct hda_pintbl ae5_pincfgs[] = {
+       { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
+       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
+       { 0x0d, 0x014510f0 }, /* Digital Out */
+       { 0x0e, 0x01c510f0 }, /* SPDIF In */
+       { 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */
+       { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
+       { 0x11, 0x012170ff }, /* Port B -- LineMicIn2 / Rear Headphone */
+       { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
+       { 0x13, 0x908700f0 }, /* What U Hear In*/
+       { 0x18, 0x50d000f0 }, /* N/A */
+       {}
+};
+
+/* Recon3D integrated pin configs taken from Windows Driver */
+static const struct hda_pintbl r3di_pincfgs[] = {
+       { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
+       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
+       { 0x0d, 0x014510f0 }, /* Digital Out */
+       { 0x0e, 0x41c520f0 }, /* SPDIF In */
+       { 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
+       { 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
+       { 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
+       { 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
+       { 0x13, 0x908700f0 }, /* What U Hear In*/
+       { 0x18, 0x500000f0 }, /* N/A */
+       {}
+};
+
+static const struct hda_pintbl ae7_pincfgs[] = {
+       { 0x0b, 0x01017010 },
+       { 0x0c, 0x014510f0 },
+       { 0x0d, 0x414510f0 },
+       { 0x0e, 0x01c520f0 },
+       { 0x0f, 0x01017114 },
+       { 0x10, 0x01017011 },
+       { 0x11, 0x018170ff },
+       { 0x12, 0x01a170f0 },
+       { 0x13, 0x908700f0 },
+       { 0x18, 0x500000f0 },
+       {}
+};
+
+static const struct hda_quirk ca0132_quirks[] = {
+       SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4),
+       SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE),
+       SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE),
+       SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE),
+       SND_PCI_QUIRK(0x1102, 0x0010, "Sound Blaster Z", QUIRK_SBZ),
+       SND_PCI_QUIRK(0x1102, 0x0023, "Sound Blaster Z", QUIRK_SBZ),
+       SND_PCI_QUIRK(0x1102, 0x0027, "Sound Blaster Z", QUIRK_SBZ),
+       SND_PCI_QUIRK(0x1102, 0x0033, "Sound Blaster ZxR", QUIRK_SBZ),
+       SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI),
+       SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
+       SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
+       SND_PCI_QUIRK(0x3842, 0x1038, "EVGA X99 Classified", QUIRK_R3DI),
+       SND_PCI_QUIRK(0x3842, 0x104b, "EVGA X299 Dark", QUIRK_R3DI),
+       SND_PCI_QUIRK(0x3842, 0x1055, "EVGA Z390 DARK", QUIRK_R3DI),
+       SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
+       SND_PCI_QUIRK(0x1102, 0x0018, "Recon3D", QUIRK_R3D),
+       SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
+       SND_PCI_QUIRK(0x1102, 0x0191, "Sound Blaster AE-5 Plus", QUIRK_AE5),
+       SND_PCI_QUIRK(0x1102, 0x0081, "Sound Blaster AE-7", QUIRK_AE7),
+       {}
+};
+
+static const struct hda_model_fixup ca0132_quirk_models[] = {
+       { .id = QUIRK_ALIENWARE, .name = "alienware" },
+       { .id = QUIRK_ALIENWARE_M17XR4, .name = "alienware-m17xr4" },
+       { .id = QUIRK_SBZ, .name = "sbz" },
+       { .id = QUIRK_ZXR, .name = "zxr" },
+       { .id = QUIRK_ZXR_DBPRO, .name = "zxr-dbpro" },
+       { .id = QUIRK_R3DI, .name = "r3di" },
+       { .id = QUIRK_R3D, .name = "r3d" },
+       { .id = QUIRK_AE5, .name = "ae5" },
+       { .id = QUIRK_AE7, .name = "ae7" },
+       {}
+};
+
+/* Output selection quirk info structures. */
+#define MAX_QUIRK_MMIO_GPIO_SET_VALS 3
+#define MAX_QUIRK_SCP_SET_VALS 2
+struct ca0132_alt_out_set_info {
+       unsigned int dac2port; /* ParamID 0x0d value. */
+
+       bool has_hda_gpio;
+       char hda_gpio_pin;
+       char hda_gpio_set;
+
+       unsigned int mmio_gpio_count;
+       char mmio_gpio_pin[MAX_QUIRK_MMIO_GPIO_SET_VALS];
+       char mmio_gpio_set[MAX_QUIRK_MMIO_GPIO_SET_VALS];
+
+       unsigned int scp_cmds_count;
+       unsigned int scp_cmd_mid[MAX_QUIRK_SCP_SET_VALS];
+       unsigned int scp_cmd_req[MAX_QUIRK_SCP_SET_VALS];
+       unsigned int scp_cmd_val[MAX_QUIRK_SCP_SET_VALS];
+
+       bool has_chipio_write;
+       unsigned int chipio_write_addr;
+       unsigned int chipio_write_data;
+};
+
+struct ca0132_alt_out_set_quirk_data {
+       int quirk_id;
+
+       bool has_headphone_gain;
+       bool is_ae_series;
+
+       struct ca0132_alt_out_set_info out_set_info[NUM_OF_OUTPUTS];
+};
+
+static const struct ca0132_alt_out_set_quirk_data quirk_out_set_data[] = {
+       { .quirk_id = QUIRK_R3DI,
+         .has_headphone_gain = false,
+         .is_ae_series       = false,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port         = 0x24,
+                 .has_hda_gpio     = true,
+                 .hda_gpio_pin     = 2,
+                 .hda_gpio_set     = 1,
+                 .mmio_gpio_count  = 0,
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               },
+               /* Headphones. */
+               { .dac2port         = 0x21,
+                 .has_hda_gpio     = true,
+                 .hda_gpio_pin     = 2,
+                 .hda_gpio_set     = 0,
+                 .mmio_gpio_count  = 0,
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               } },
+       },
+       { .quirk_id = QUIRK_R3D,
+         .has_headphone_gain = false,
+         .is_ae_series       = false,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port         = 0x24,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 1,
+                 .mmio_gpio_pin    = { 1 },
+                 .mmio_gpio_set    = { 1 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               },
+               /* Headphones. */
+               { .dac2port         = 0x21,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 1,
+                 .mmio_gpio_pin    = { 1 },
+                 .mmio_gpio_set    = { 0 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               } },
+       },
+       { .quirk_id = QUIRK_SBZ,
+         .has_headphone_gain = false,
+         .is_ae_series       = false,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port         = 0x18,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 3,
+                 .mmio_gpio_pin    = { 7, 4, 1 },
+                 .mmio_gpio_set    = { 0, 1, 1 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false, },
+               /* Headphones. */
+               { .dac2port         = 0x12,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 3,
+                 .mmio_gpio_pin    = { 7, 4, 1 },
+                 .mmio_gpio_set    = { 1, 1, 0 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               } },
+       },
+       { .quirk_id = QUIRK_ZXR,
+         .has_headphone_gain = true,
+         .is_ae_series       = false,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port         = 0x24,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 3,
+                 .mmio_gpio_pin    = { 2, 3, 5 },
+                 .mmio_gpio_set    = { 1, 1, 0 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               },
+               /* Headphones. */
+               { .dac2port         = 0x21,
+                 .has_hda_gpio     = false,
+                 .mmio_gpio_count  = 3,
+                 .mmio_gpio_pin    = { 2, 3, 5 },
+                 .mmio_gpio_set    = { 0, 1, 1 },
+                 .scp_cmds_count   = 0,
+                 .has_chipio_write = false,
+               } },
+       },
+       { .quirk_id = QUIRK_AE5,
+         .has_headphone_gain = true,
+         .is_ae_series       = true,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port          = 0xa4,
+                 .has_hda_gpio      = false,
+                 .mmio_gpio_count   = 0,
+                 .scp_cmds_count    = 2,
+                 .scp_cmd_mid       = { 0x96, 0x96 },
+                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
+                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
+                 .scp_cmd_val       = { FLOAT_ZERO, FLOAT_ZERO },
+                 .has_chipio_write  = true,
+                 .chipio_write_addr = 0x0018b03c,
+                 .chipio_write_data = 0x00000012
+               },
+               /* Headphones. */
+               { .dac2port          = 0xa1,
+                 .has_hda_gpio      = false,
+                 .mmio_gpio_count   = 0,
+                 .scp_cmds_count    = 2,
+                 .scp_cmd_mid       = { 0x96, 0x96 },
+                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
+                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
+                 .scp_cmd_val       = { FLOAT_ONE, FLOAT_ONE },
+                 .has_chipio_write  = true,
+                 .chipio_write_addr = 0x0018b03c,
+                 .chipio_write_data = 0x00000012
+               } },
+       },
+       { .quirk_id = QUIRK_AE7,
+         .has_headphone_gain = true,
+         .is_ae_series       = true,
+         .out_set_info = {
+               /* Speakers. */
+               { .dac2port          = 0x58,
+                 .has_hda_gpio      = false,
+                 .mmio_gpio_count   = 1,
+                 .mmio_gpio_pin     = { 0 },
+                 .mmio_gpio_set     = { 1 },
+                 .scp_cmds_count    = 2,
+                 .scp_cmd_mid       = { 0x96, 0x96 },
+                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
+                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
+                 .scp_cmd_val       = { FLOAT_ZERO, FLOAT_ZERO },
+                 .has_chipio_write  = true,
+                 .chipio_write_addr = 0x0018b03c,
+                 .chipio_write_data = 0x00000000
+               },
+               /* Headphones. */
+               { .dac2port          = 0x58,
+                 .has_hda_gpio      = false,
+                 .mmio_gpio_count   = 1,
+                 .mmio_gpio_pin     = { 0 },
+                 .mmio_gpio_set     = { 1 },
+                 .scp_cmds_count    = 2,
+                 .scp_cmd_mid       = { 0x96, 0x96 },
+                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
+                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
+                 .scp_cmd_val       = { FLOAT_ONE, FLOAT_ONE },
+                 .has_chipio_write  = true,
+                 .chipio_write_addr = 0x0018b03c,
+                 .chipio_write_data = 0x00000010
+               } },
+       }
+};
+
+/*
+ * CA0132 codec access
+ */
+static unsigned int codec_send_command(struct hda_codec *codec, hda_nid_t nid,
+               unsigned int verb, unsigned int parm, unsigned int *res)
+{
+       unsigned int response;
+       response = snd_hda_codec_read(codec, nid, 0, verb, parm);
+       *res = response;
+
+       return ((response == -1) ? -1 : 0);
+}
+
+static int codec_set_converter_format(struct hda_codec *codec, hda_nid_t nid,
+               unsigned short converter_format, unsigned int *res)
+{
+       return codec_send_command(codec, nid, VENDOR_CHIPIO_STREAM_FORMAT,
+                               converter_format & 0xffff, res);
+}
+
+static int codec_set_converter_stream_channel(struct hda_codec *codec,
+                               hda_nid_t nid, unsigned char stream,
+                               unsigned char channel, unsigned int *res)
+{
+       unsigned char converter_stream_channel = 0;
+
+       converter_stream_channel = (stream << 4) | (channel & 0x0f);
+       return codec_send_command(codec, nid, AC_VERB_SET_CHANNEL_STREAMID,
+                               converter_stream_channel, res);
+}
+
+/* Chip access helper function */
+static int chipio_send(struct hda_codec *codec,
+                      unsigned int reg,
+                      unsigned int data)
+{
+       unsigned int res;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       /* send bits of data specified by reg */
+       do {
+               res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
+                                        reg, data);
+               if (res == VENDOR_STATUS_CHIPIO_OK)
+                       return 0;
+               msleep(20);
+       } while (time_before(jiffies, timeout));
+
+       return -EIO;
+}
+
+/*
+ * Write chip address through the vendor widget -- NOT protected by the Mutex!
+ */
+static int chipio_write_address(struct hda_codec *codec,
+                               unsigned int chip_addx)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int res;
+
+       if (spec->curr_chip_addx == chip_addx)
+                       return 0;
+
+       /* send low 16 bits of the address */
+       res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW,
+                         chip_addx & 0xffff);
+
+       if (res != -EIO) {
+               /* send high 16 bits of the address */
+               res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_HIGH,
+                                 chip_addx >> 16);
+       }
+
+       spec->curr_chip_addx = (res < 0) ? ~0U : chip_addx;
+
+       return res;
+}
+
+/*
+ * Write data through the vendor widget -- NOT protected by the Mutex!
+ */
+static int chipio_write_data(struct hda_codec *codec, unsigned int data)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int res;
+
+       /* send low 16 bits of the data */
+       res = chipio_send(codec, VENDOR_CHIPIO_DATA_LOW, data & 0xffff);
+
+       if (res != -EIO) {
+               /* send high 16 bits of the data */
+               res = chipio_send(codec, VENDOR_CHIPIO_DATA_HIGH,
+                                 data >> 16);
+       }
+
+       /*If no error encountered, automatically increment the address
+       as per chip behaviour*/
+       spec->curr_chip_addx = (res != -EIO) ?
+                                       (spec->curr_chip_addx + 4) : ~0U;
+       return res;
+}
+
+/*
+ * Write multiple data through the vendor widget -- NOT protected by the Mutex!
+ */
+static int chipio_write_data_multiple(struct hda_codec *codec,
+                                     const u32 *data,
+                                     unsigned int count)
+{
+       int status = 0;
+
+       if (data == NULL) {
+               codec_dbg(codec, "chipio_write_data null ptr\n");
+               return -EINVAL;
+       }
+
+       while ((count-- != 0) && (status == 0))
+               status = chipio_write_data(codec, *data++);
+
+       return status;
+}
+
+
+/*
+ * Read data through the vendor widget -- NOT protected by the Mutex!
+ */
+static int chipio_read_data(struct hda_codec *codec, unsigned int *data)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int res;
+
+       /* post read */
+       res = chipio_send(codec, VENDOR_CHIPIO_HIC_POST_READ, 0);
+
+       if (res != -EIO) {
+               /* read status */
+               res = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
+       }
+
+       if (res != -EIO) {
+               /* read data */
+               *data = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
+                                          VENDOR_CHIPIO_HIC_READ_DATA,
+                                          0);
+       }
+
+       /*If no error encountered, automatically increment the address
+       as per chip behaviour*/
+       spec->curr_chip_addx = (res != -EIO) ?
+                                       (spec->curr_chip_addx + 4) : ~0U;
+       return res;
+}
+
+/*
+ * Write given value to the given address through the chip I/O widget.
+ * protected by the Mutex
+ */
+static int chipio_write(struct hda_codec *codec,
+               unsigned int chip_addx, const unsigned int data)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int err;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       /* write the address, and if successful proceed to write data */
+       err = chipio_write_address(codec, chip_addx);
+       if (err < 0)
+               goto exit;
+
+       err = chipio_write_data(codec, data);
+       if (err < 0)
+               goto exit;
+
+exit:
+       mutex_unlock(&spec->chipio_mutex);
+       return err;
+}
+
+/*
+ * Write given value to the given address through the chip I/O widget.
+ * not protected by the Mutex
+ */
+static int chipio_write_no_mutex(struct hda_codec *codec,
+               unsigned int chip_addx, const unsigned int data)
+{
+       int err;
+
+
+       /* write the address, and if successful proceed to write data */
+       err = chipio_write_address(codec, chip_addx);
+       if (err < 0)
+               goto exit;
+
+       err = chipio_write_data(codec, data);
+       if (err < 0)
+               goto exit;
+
+exit:
+       return err;
+}
+
+/*
+ * Write multiple values to the given address through the chip I/O widget.
+ * protected by the Mutex
+ */
+static int chipio_write_multiple(struct hda_codec *codec,
+                                u32 chip_addx,
+                                const u32 *data,
+                                unsigned int count)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int status;
+
+       mutex_lock(&spec->chipio_mutex);
+       status = chipio_write_address(codec, chip_addx);
+       if (status < 0)
+               goto error;
+
+       status = chipio_write_data_multiple(codec, data, count);
+error:
+       mutex_unlock(&spec->chipio_mutex);
+
+       return status;
+}
+
+/*
+ * Read the given address through the chip I/O widget
+ * protected by the Mutex
+ */
+static int chipio_read(struct hda_codec *codec,
+               unsigned int chip_addx, unsigned int *data)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int err;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       /* write the address, and if successful proceed to write data */
+       err = chipio_write_address(codec, chip_addx);
+       if (err < 0)
+               goto exit;
+
+       err = chipio_read_data(codec, data);
+       if (err < 0)
+               goto exit;
+
+exit:
+       mutex_unlock(&spec->chipio_mutex);
+       return err;
+}
+
+/*
+ * Set chip control flags through the chip I/O widget.
+ */
+static void chipio_set_control_flag(struct hda_codec *codec,
+                                   enum control_flag_id flag_id,
+                                   bool flag_state)
+{
+       unsigned int val;
+       unsigned int flag_bit;
+
+       flag_bit = (flag_state ? 1 : 0);
+       val = (flag_bit << 7) | (flag_id);
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_FLAG_SET, val);
+}
+
+/*
+ * Set chip parameters through the chip I/O widget.
+ */
+static void chipio_set_control_param(struct hda_codec *codec,
+               enum control_param_id param_id, int param_val)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int val;
+
+       if ((param_id < 32) && (param_val < 8)) {
+               val = (param_val << 5) | (param_id);
+               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                                   VENDOR_CHIPIO_PARAM_SET, val);
+       } else {
+               mutex_lock(&spec->chipio_mutex);
+               if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) {
+                       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                                           VENDOR_CHIPIO_PARAM_EX_ID_SET,
+                                           param_id);
+                       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                                           VENDOR_CHIPIO_PARAM_EX_VALUE_SET,
+                                           param_val);
+               }
+               mutex_unlock(&spec->chipio_mutex);
+       }
+}
+
+/*
+ * Set chip parameters through the chip I/O widget. NO MUTEX.
+ */
+static void chipio_set_control_param_no_mutex(struct hda_codec *codec,
+               enum control_param_id param_id, int param_val)
+{
+       int val;
+
+       if ((param_id < 32) && (param_val < 8)) {
+               val = (param_val << 5) | (param_id);
+               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                                   VENDOR_CHIPIO_PARAM_SET, val);
+       } else {
+               if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) {
+                       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                                           VENDOR_CHIPIO_PARAM_EX_ID_SET,
+                                           param_id);
+                       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                                           VENDOR_CHIPIO_PARAM_EX_VALUE_SET,
+                                           param_val);
+               }
+       }
+}
+/*
+ * Connect stream to a source point, and then connect
+ * that source point to a destination point.
+ */
+static void chipio_set_stream_source_dest(struct hda_codec *codec,
+                               int streamid, int source_point, int dest_point)
+{
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_STREAM_ID, streamid);
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_STREAM_SOURCE_CONN_POINT, source_point);
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_STREAM_DEST_CONN_POINT, dest_point);
+}
+
+/*
+ * Set number of channels in the selected stream.
+ */
+static void chipio_set_stream_channels(struct hda_codec *codec,
+                               int streamid, unsigned int channels)
+{
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_STREAM_ID, streamid);
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_STREAMS_CHANNELS, channels);
+}
+
+/*
+ * Enable/Disable audio stream.
+ */
+static void chipio_set_stream_control(struct hda_codec *codec,
+                               int streamid, int enable)
+{
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_STREAM_ID, streamid);
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_STREAM_CONTROL, enable);
+}
+
+/*
+ * Get ChipIO audio stream's status.
+ */
+static void chipio_get_stream_control(struct hda_codec *codec,
+                               int streamid, unsigned int *enable)
+{
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_STREAM_ID, streamid);
+       *enable = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
+                          VENDOR_CHIPIO_PARAM_GET,
+                          CONTROL_PARAM_STREAM_CONTROL);
+}
+
+/*
+ * Set sampling rate of the connection point. NO MUTEX.
+ */
+static void chipio_set_conn_rate_no_mutex(struct hda_codec *codec,
+                               int connid, enum ca0132_sample_rate rate)
+{
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_CONN_POINT_ID, connid);
+       chipio_set_control_param_no_mutex(codec,
+                       CONTROL_PARAM_CONN_POINT_SAMPLE_RATE, rate);
+}
+
+/*
+ * Set sampling rate of the connection point.
+ */
+static void chipio_set_conn_rate(struct hda_codec *codec,
+                               int connid, enum ca0132_sample_rate rate)
+{
+       chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_ID, connid);
+       chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_SAMPLE_RATE,
+                                rate);
+}
+
+/*
+ * Writes to the 8051's internal address space directly instead of indirectly,
+ * giving access to the special function registers located at addresses
+ * 0x80-0xFF.
+ */
+static void chipio_8051_write_direct(struct hda_codec *codec,
+               unsigned int addr, unsigned int data)
+{
+       unsigned int verb;
+
+       verb = VENDOR_CHIPIO_8051_WRITE_DIRECT | data;
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, verb, addr);
+}
+
+/*
+ * Writes to the 8051's exram, which has 16-bits of address space.
+ * Data at addresses 0x2000-0x7fff is mirrored to 0x8000-0xdfff.
+ * Data at 0x8000-0xdfff can also be used as program memory for the 8051 by
+ * setting the pmem bank selection SFR.
+ * 0xe000-0xffff is always mapped as program memory, with only 0xf000-0xffff
+ * being writable.
+ */
+static void chipio_8051_set_address(struct hda_codec *codec, unsigned int addr)
+{
+       unsigned int tmp;
+
+       /* Lower 8-bits. */
+       tmp = addr & 0xff;
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_LOW, tmp);
+
+       /* Upper 8-bits. */
+       tmp = (addr >> 8) & 0xff;
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_ADDRESS_HIGH, tmp);
+}
+
+static void chipio_8051_set_data(struct hda_codec *codec, unsigned int data)
+{
+       /* 8-bits of data. */
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_8051_DATA_WRITE, data & 0xff);
+}
+
+static unsigned int chipio_8051_get_data(struct hda_codec *codec)
+{
+       return snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
+                                  VENDOR_CHIPIO_8051_DATA_READ, 0);
+}
+
+/* PLL_PMU writes share the lower address register of the 8051 exram writes. */
+static void chipio_8051_set_data_pll(struct hda_codec *codec, unsigned int data)
+{
+       /* 8-bits of data. */
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PLL_PMU_WRITE, data & 0xff);
+}
+
+static void chipio_8051_write_exram(struct hda_codec *codec,
+               unsigned int addr, unsigned int data)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       chipio_8051_set_address(codec, addr);
+       chipio_8051_set_data(codec, data);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void chipio_8051_write_exram_no_mutex(struct hda_codec *codec,
+               unsigned int addr, unsigned int data)
+{
+       chipio_8051_set_address(codec, addr);
+       chipio_8051_set_data(codec, data);
+}
+
+/* Readback data from the 8051's exram. No mutex. */
+static void chipio_8051_read_exram(struct hda_codec *codec,
+               unsigned int addr, unsigned int *data)
+{
+       chipio_8051_set_address(codec, addr);
+       *data = chipio_8051_get_data(codec);
+}
+
+static void chipio_8051_write_pll_pmu(struct hda_codec *codec,
+               unsigned int addr, unsigned int data)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       chipio_8051_set_address(codec, addr & 0xff);
+       chipio_8051_set_data_pll(codec, data);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void chipio_8051_write_pll_pmu_no_mutex(struct hda_codec *codec,
+               unsigned int addr, unsigned int data)
+{
+       chipio_8051_set_address(codec, addr & 0xff);
+       chipio_8051_set_data_pll(codec, data);
+}
+
+/*
+ * Enable clocks.
+ */
+static void chipio_enable_clocks(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       chipio_8051_write_pll_pmu_no_mutex(codec, 0x00, 0xff);
+       chipio_8051_write_pll_pmu_no_mutex(codec, 0x05, 0x0b);
+       chipio_8051_write_pll_pmu_no_mutex(codec, 0x06, 0xff);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+/*
+ * CA0132 DSP IO stuffs
+ */
+static int dspio_send(struct hda_codec *codec, unsigned int reg,
+                     unsigned int data)
+{
+       int res;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       /* send bits of data specified by reg to dsp */
+       do {
+               res = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, reg, data);
+               if ((res >= 0) && (res != VENDOR_STATUS_DSPIO_BUSY))
+                       return res;
+               msleep(20);
+       } while (time_before(jiffies, timeout));
+
+       return -EIO;
+}
+
+/*
+ * Wait for DSP to be ready for commands
+ */
+static void dspio_write_wait(struct hda_codec *codec)
+{
+       int status;
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+       do {
+               status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
+                                               VENDOR_DSPIO_STATUS, 0);
+               if ((status == VENDOR_STATUS_DSPIO_OK) ||
+                   (status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY))
+                       break;
+               msleep(1);
+       } while (time_before(jiffies, timeout));
+}
+
+/*
+ * Write SCP data to DSP
+ */
+static int dspio_write(struct hda_codec *codec, unsigned int scp_data)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int status;
+
+       dspio_write_wait(codec);
+
+       mutex_lock(&spec->chipio_mutex);
+       status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_LOW,
+                           scp_data & 0xffff);
+       if (status < 0)
+               goto error;
+
+       status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_HIGH,
+                                   scp_data >> 16);
+       if (status < 0)
+               goto error;
+
+       /* OK, now check if the write itself has executed*/
+       status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
+                                   VENDOR_DSPIO_STATUS, 0);
+error:
+       mutex_unlock(&spec->chipio_mutex);
+
+       return (status == VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL) ?
+                       -EIO : 0;
+}
+
+/*
+ * Write multiple SCP data to DSP
+ */
+static int dspio_write_multiple(struct hda_codec *codec,
+                               unsigned int *buffer, unsigned int size)
+{
+       int status = 0;
+       unsigned int count;
+
+       if (buffer == NULL)
+               return -EINVAL;
+
+       count = 0;
+       while (count < size) {
+               status = dspio_write(codec, *buffer++);
+               if (status != 0)
+                       break;
+               count++;
+       }
+
+       return status;
+}
+
+static int dspio_read(struct hda_codec *codec, unsigned int *data)
+{
+       int status;
+
+       status = dspio_send(codec, VENDOR_DSPIO_SCP_POST_READ_DATA, 0);
+       if (status == -EIO)
+               return status;
+
+       status = dspio_send(codec, VENDOR_DSPIO_STATUS, 0);
+       if (status == -EIO ||
+           status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY)
+               return -EIO;
+
+       *data = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
+                                  VENDOR_DSPIO_SCP_READ_DATA, 0);
+
+       return 0;
+}
+
+static int dspio_read_multiple(struct hda_codec *codec, unsigned int *buffer,
+                              unsigned int *buf_size, unsigned int size_count)
+{
+       int status = 0;
+       unsigned int size = *buf_size;
+       unsigned int count;
+       unsigned int skip_count;
+       unsigned int dummy;
+
+       if (buffer == NULL)
+               return -1;
+
+       count = 0;
+       while (count < size && count < size_count) {
+               status = dspio_read(codec, buffer++);
+               if (status != 0)
+                       break;
+               count++;
+       }
+
+       skip_count = count;
+       if (status == 0) {
+               while (skip_count < size) {
+                       status = dspio_read(codec, &dummy);
+                       if (status != 0)
+                               break;
+                       skip_count++;
+               }
+       }
+       *buf_size = count;
+
+       return status;
+}
+
+/*
+ * Construct the SCP header using corresponding fields
+ */
+static inline unsigned int
+make_scp_header(unsigned int target_id, unsigned int source_id,
+               unsigned int get_flag, unsigned int req,
+               unsigned int device_flag, unsigned int resp_flag,
+               unsigned int error_flag, unsigned int data_size)
+{
+       unsigned int header = 0;
+
+       header = (data_size & 0x1f) << 27;
+       header |= (error_flag & 0x01) << 26;
+       header |= (resp_flag & 0x01) << 25;
+       header |= (device_flag & 0x01) << 24;
+       header |= (req & 0x7f) << 17;
+       header |= (get_flag & 0x01) << 16;
+       header |= (source_id & 0xff) << 8;
+       header |= target_id & 0xff;
+
+       return header;
+}
+
+/*
+ * Extract corresponding fields from SCP header
+ */
+static inline void
+extract_scp_header(unsigned int header,
+                  unsigned int *target_id, unsigned int *source_id,
+                  unsigned int *get_flag, unsigned int *req,
+                  unsigned int *device_flag, unsigned int *resp_flag,
+                  unsigned int *error_flag, unsigned int *data_size)
+{
+       if (data_size)
+               *data_size = (header >> 27) & 0x1f;
+       if (error_flag)
+               *error_flag = (header >> 26) & 0x01;
+       if (resp_flag)
+               *resp_flag = (header >> 25) & 0x01;
+       if (device_flag)
+               *device_flag = (header >> 24) & 0x01;
+       if (req)
+               *req = (header >> 17) & 0x7f;
+       if (get_flag)
+               *get_flag = (header >> 16) & 0x01;
+       if (source_id)
+               *source_id = (header >> 8) & 0xff;
+       if (target_id)
+               *target_id = header & 0xff;
+}
+
+#define SCP_MAX_DATA_WORDS  (16)
+
+/* Structure to contain any SCP message */
+struct scp_msg {
+       unsigned int hdr;
+       unsigned int data[SCP_MAX_DATA_WORDS];
+};
+
+static void dspio_clear_response_queue(struct hda_codec *codec)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+       unsigned int dummy = 0;
+       int status;
+
+       /* clear all from the response queue */
+       do {
+               status = dspio_read(codec, &dummy);
+       } while (status == 0 && time_before(jiffies, timeout));
+}
+
+static int dspio_get_response_data(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int data = 0;
+       unsigned int count;
+
+       if (dspio_read(codec, &data) < 0)
+               return -EIO;
+
+       if ((data & 0x00ffffff) == spec->wait_scp_header) {
+               spec->scp_resp_header = data;
+               spec->scp_resp_count = data >> 27;
+               count = spec->wait_num_data;
+               dspio_read_multiple(codec, spec->scp_resp_data,
+                                   &spec->scp_resp_count, count);
+               return 0;
+       }
+
+       return -EIO;
+}
+
+/*
+ * Send SCP message to DSP
+ */
+static int dspio_send_scp_message(struct hda_codec *codec,
+                                 unsigned char *send_buf,
+                                 unsigned int send_buf_size,
+                                 unsigned char *return_buf,
+                                 unsigned int return_buf_size,
+                                 unsigned int *bytes_returned)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int status;
+       unsigned int scp_send_size = 0;
+       unsigned int total_size;
+       bool waiting_for_resp = false;
+       unsigned int header;
+       struct scp_msg *ret_msg;
+       unsigned int resp_src_id, resp_target_id;
+       unsigned int data_size, src_id, target_id, get_flag, device_flag;
+
+       if (bytes_returned)
+               *bytes_returned = 0;
+
+       /* get scp header from buffer */
+       header = *((unsigned int *)send_buf);
+       extract_scp_header(header, &target_id, &src_id, &get_flag, NULL,
+                          &device_flag, NULL, NULL, &data_size);
+       scp_send_size = data_size + 1;
+       total_size = (scp_send_size * 4);
+
+       if (send_buf_size < total_size)
+               return -EINVAL;
+
+       if (get_flag || device_flag) {
+               if (!return_buf || return_buf_size < 4 || !bytes_returned)
+                       return -EINVAL;
+
+               spec->wait_scp_header = *((unsigned int *)send_buf);
+
+               /* swap source id with target id */
+               resp_target_id = src_id;
+               resp_src_id = target_id;
+               spec->wait_scp_header &= 0xffff0000;
+               spec->wait_scp_header |= (resp_src_id << 8) | (resp_target_id);
+               spec->wait_num_data = return_buf_size/sizeof(unsigned int) - 1;
+               spec->wait_scp = 1;
+               waiting_for_resp = true;
+       }
+
+       status = dspio_write_multiple(codec, (unsigned int *)send_buf,
+                                     scp_send_size);
+       if (status < 0) {
+               spec->wait_scp = 0;
+               return status;
+       }
+
+       if (waiting_for_resp) {
+               unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+               memset(return_buf, 0, return_buf_size);
+               do {
+                       msleep(20);
+               } while (spec->wait_scp && time_before(jiffies, timeout));
+               waiting_for_resp = false;
+               if (!spec->wait_scp) {
+                       ret_msg = (struct scp_msg *)return_buf;
+                       memcpy(&ret_msg->hdr, &spec->scp_resp_header, 4);
+                       memcpy(&ret_msg->data, spec->scp_resp_data,
+                              spec->wait_num_data);
+                       *bytes_returned = (spec->scp_resp_count + 1) * 4;
+                       status = 0;
+               } else {
+                       status = -EIO;
+               }
+               spec->wait_scp = 0;
+       }
+
+       return status;
+}
+
+/**
+ * dspio_scp - Prepare and send the SCP message to DSP
+ * @codec: the HDA codec
+ * @mod_id: ID of the DSP module to send the command
+ * @src_id: ID of the source
+ * @req: ID of request to send to the DSP module
+ * @dir: SET or GET
+ * @data: pointer to the data to send with the request, request specific
+ * @len: length of the data, in bytes
+ * @reply: point to the buffer to hold data returned for a reply
+ * @reply_len: length of the reply buffer returned from GET
+ *
+ * Returns zero or a negative error code.
+ */
+static int dspio_scp(struct hda_codec *codec,
+               int mod_id, int src_id, int req, int dir, const void *data,
+               unsigned int len, void *reply, unsigned int *reply_len)
+{
+       int status = 0;
+       struct scp_msg scp_send, scp_reply;
+       unsigned int ret_bytes, send_size, ret_size;
+       unsigned int send_get_flag, reply_resp_flag, reply_error_flag;
+       unsigned int reply_data_size;
+
+       memset(&scp_send, 0, sizeof(scp_send));
+       memset(&scp_reply, 0, sizeof(scp_reply));
+
+       if ((len != 0 && data == NULL) || (len > SCP_MAX_DATA_WORDS))
+               return -EINVAL;
+
+       if (dir == SCP_GET && reply == NULL) {
+               codec_dbg(codec, "dspio_scp get but has no buffer\n");
+               return -EINVAL;
+       }
+
+       if (reply != NULL && (reply_len == NULL || (*reply_len == 0))) {
+               codec_dbg(codec, "dspio_scp bad resp buf len parms\n");
+               return -EINVAL;
+       }
+
+       scp_send.hdr = make_scp_header(mod_id, src_id, (dir == SCP_GET), req,
+                                      0, 0, 0, len/sizeof(unsigned int));
+       if (data != NULL && len > 0) {
+               len = min((unsigned int)(sizeof(scp_send.data)), len);
+               memcpy(scp_send.data, data, len);
+       }
+
+       ret_bytes = 0;
+       send_size = sizeof(unsigned int) + len;
+       status = dspio_send_scp_message(codec, (unsigned char *)&scp_send,
+                                       send_size, (unsigned char *)&scp_reply,
+                                       sizeof(scp_reply), &ret_bytes);
+
+       if (status < 0) {
+               codec_dbg(codec, "dspio_scp: send scp msg failed\n");
+               return status;
+       }
+
+       /* extract send and reply headers members */
+       extract_scp_header(scp_send.hdr, NULL, NULL, &send_get_flag,
+                          NULL, NULL, NULL, NULL, NULL);
+       extract_scp_header(scp_reply.hdr, NULL, NULL, NULL, NULL, NULL,
+                          &reply_resp_flag, &reply_error_flag,
+                          &reply_data_size);
+
+       if (!send_get_flag)
+               return 0;
+
+       if (reply_resp_flag && !reply_error_flag) {
+               ret_size = (ret_bytes - sizeof(scp_reply.hdr))
+                                       / sizeof(unsigned int);
+
+               if (*reply_len < ret_size*sizeof(unsigned int)) {
+                       codec_dbg(codec, "reply too long for buf\n");
+                       return -EINVAL;
+               } else if (ret_size != reply_data_size) {
+                       codec_dbg(codec, "RetLen and HdrLen .NE.\n");
+                       return -EINVAL;
+               } else if (!reply) {
+                       codec_dbg(codec, "NULL reply\n");
+                       return -EINVAL;
+               } else {
+                       *reply_len = ret_size*sizeof(unsigned int);
+                       memcpy(reply, scp_reply.data, *reply_len);
+               }
+       } else {
+               codec_dbg(codec, "reply ill-formed or errflag set\n");
+               return -EIO;
+       }
+
+       return status;
+}
+
+/*
+ * Set DSP parameters
+ */
+static int dspio_set_param(struct hda_codec *codec, int mod_id,
+                       int src_id, int req, const void *data, unsigned int len)
+{
+       return dspio_scp(codec, mod_id, src_id, req, SCP_SET, data, len, NULL,
+                       NULL);
+}
+
+static int dspio_set_uint_param(struct hda_codec *codec, int mod_id,
+                       int req, const unsigned int data)
+{
+       return dspio_set_param(codec, mod_id, 0x20, req, &data,
+                       sizeof(unsigned int));
+}
+
+/*
+ * Allocate a DSP DMA channel via an SCP message
+ */
+static int dspio_alloc_dma_chan(struct hda_codec *codec, unsigned int *dma_chan)
+{
+       int status = 0;
+       unsigned int size = sizeof(*dma_chan);
+
+       codec_dbg(codec, "     dspio_alloc_dma_chan() -- begin\n");
+       status = dspio_scp(codec, MASTERCONTROL, 0x20,
+                       MASTERCONTROL_ALLOC_DMA_CHAN, SCP_GET, NULL, 0,
+                       dma_chan, &size);
+
+       if (status < 0) {
+               codec_dbg(codec, "dspio_alloc_dma_chan: SCP Failed\n");
+               return status;
+       }
+
+       if ((*dma_chan + 1) == 0) {
+               codec_dbg(codec, "no free dma channels to allocate\n");
+               return -EBUSY;
+       }
+
+       codec_dbg(codec, "dspio_alloc_dma_chan: chan=%d\n", *dma_chan);
+       codec_dbg(codec, "     dspio_alloc_dma_chan() -- complete\n");
+
+       return status;
+}
+
+/*
+ * Free a DSP DMA via an SCP message
+ */
+static int dspio_free_dma_chan(struct hda_codec *codec, unsigned int dma_chan)
+{
+       int status = 0;
+       unsigned int dummy = 0;
+
+       codec_dbg(codec, "     dspio_free_dma_chan() -- begin\n");
+       codec_dbg(codec, "dspio_free_dma_chan: chan=%d\n", dma_chan);
+
+       status = dspio_scp(codec, MASTERCONTROL, 0x20,
+                       MASTERCONTROL_ALLOC_DMA_CHAN, SCP_SET, &dma_chan,
+                       sizeof(dma_chan), NULL, &dummy);
+
+       if (status < 0) {
+               codec_dbg(codec, "dspio_free_dma_chan: SCP Failed\n");
+               return status;
+       }
+
+       codec_dbg(codec, "     dspio_free_dma_chan() -- complete\n");
+
+       return status;
+}
+
+/*
+ * (Re)start the DSP
+ */
+static int dsp_set_run_state(struct hda_codec *codec)
+{
+       unsigned int dbg_ctrl_reg;
+       unsigned int halt_state;
+       int err;
+
+       err = chipio_read(codec, DSP_DBGCNTL_INST_OFFSET, &dbg_ctrl_reg);
+       if (err < 0)
+               return err;
+
+       halt_state = (dbg_ctrl_reg & DSP_DBGCNTL_STATE_MASK) >>
+                     DSP_DBGCNTL_STATE_LOBIT;
+
+       if (halt_state != 0) {
+               dbg_ctrl_reg &= ~((halt_state << DSP_DBGCNTL_SS_LOBIT) &
+                                 DSP_DBGCNTL_SS_MASK);
+               err = chipio_write(codec, DSP_DBGCNTL_INST_OFFSET,
+                                  dbg_ctrl_reg);
+               if (err < 0)
+                       return err;
+
+               dbg_ctrl_reg |= (halt_state << DSP_DBGCNTL_EXEC_LOBIT) &
+                               DSP_DBGCNTL_EXEC_MASK;
+               err = chipio_write(codec, DSP_DBGCNTL_INST_OFFSET,
+                                  dbg_ctrl_reg);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/*
+ * Reset the DSP
+ */
+static int dsp_reset(struct hda_codec *codec)
+{
+       unsigned int res;
+       int retry = 20;
+
+       codec_dbg(codec, "dsp_reset\n");
+       do {
+               res = dspio_send(codec, VENDOR_DSPIO_DSP_INIT, 0);
+               retry--;
+       } while (res == -EIO && retry);
+
+       if (!retry) {
+               codec_dbg(codec, "dsp_reset timeout\n");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+/*
+ * Convert chip address to DSP address
+ */
+static unsigned int dsp_chip_to_dsp_addx(unsigned int chip_addx,
+                                       bool *code, bool *yram)
+{
+       *code = *yram = false;
+
+       if (UC_RANGE(chip_addx, 1)) {
+               *code = true;
+               return UC_OFF(chip_addx);
+       } else if (X_RANGE_ALL(chip_addx, 1)) {
+               return X_OFF(chip_addx);
+       } else if (Y_RANGE_ALL(chip_addx, 1)) {
+               *yram = true;
+               return Y_OFF(chip_addx);
+       }
+
+       return INVALID_CHIP_ADDRESS;
+}
+
+/*
+ * Check if the DSP DMA is active
+ */
+static bool dsp_is_dma_active(struct hda_codec *codec, unsigned int dma_chan)
+{
+       unsigned int dma_chnlstart_reg;
+
+       chipio_read(codec, DSPDMAC_CHNLSTART_INST_OFFSET, &dma_chnlstart_reg);
+
+       return ((dma_chnlstart_reg & (1 <<
+                       (DSPDMAC_CHNLSTART_EN_LOBIT + dma_chan))) != 0);
+}
+
+static int dsp_dma_setup_common(struct hda_codec *codec,
+                               unsigned int chip_addx,
+                               unsigned int dma_chan,
+                               unsigned int port_map_mask,
+                               bool ovly)
+{
+       int status = 0;
+       unsigned int chnl_prop;
+       unsigned int dsp_addx;
+       unsigned int active;
+       bool code, yram;
+
+       codec_dbg(codec, "-- dsp_dma_setup_common() -- Begin ---------\n");
+
+       if (dma_chan >= DSPDMAC_DMA_CFG_CHANNEL_COUNT) {
+               codec_dbg(codec, "dma chan num invalid\n");
+               return -EINVAL;
+       }
+
+       if (dsp_is_dma_active(codec, dma_chan)) {
+               codec_dbg(codec, "dma already active\n");
+               return -EBUSY;
+       }
+
+       dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram);
+
+       if (dsp_addx == INVALID_CHIP_ADDRESS) {
+               codec_dbg(codec, "invalid chip addr\n");
+               return -ENXIO;
+       }
+
+       chnl_prop = DSPDMAC_CHNLPROP_AC_MASK;
+       active = 0;
+
+       codec_dbg(codec, "   dsp_dma_setup_common()    start reg pgm\n");
+
+       if (ovly) {
+               status = chipio_read(codec, DSPDMAC_CHNLPROP_INST_OFFSET,
+                                    &chnl_prop);
+
+               if (status < 0) {
+                       codec_dbg(codec, "read CHNLPROP Reg fail\n");
+                       return status;
+               }
+               codec_dbg(codec, "dsp_dma_setup_common() Read CHNLPROP\n");
+       }
+
+       if (!code)
+               chnl_prop &= ~(1 << (DSPDMAC_CHNLPROP_MSPCE_LOBIT + dma_chan));
+       else
+               chnl_prop |=  (1 << (DSPDMAC_CHNLPROP_MSPCE_LOBIT + dma_chan));
+
+       chnl_prop &= ~(1 << (DSPDMAC_CHNLPROP_DCON_LOBIT + dma_chan));
+
+       status = chipio_write(codec, DSPDMAC_CHNLPROP_INST_OFFSET, chnl_prop);
+       if (status < 0) {
+               codec_dbg(codec, "write CHNLPROP Reg fail\n");
+               return status;
+       }
+       codec_dbg(codec, "   dsp_dma_setup_common()    Write CHNLPROP\n");
+
+       if (ovly) {
+               status = chipio_read(codec, DSPDMAC_ACTIVE_INST_OFFSET,
+                                    &active);
+
+               if (status < 0) {
+                       codec_dbg(codec, "read ACTIVE Reg fail\n");
+                       return status;
+               }
+               codec_dbg(codec, "dsp_dma_setup_common() Read ACTIVE\n");
+       }
+
+       active &= (~(1 << (DSPDMAC_ACTIVE_AAR_LOBIT + dma_chan))) &
+               DSPDMAC_ACTIVE_AAR_MASK;
+
+       status = chipio_write(codec, DSPDMAC_ACTIVE_INST_OFFSET, active);
+       if (status < 0) {
+               codec_dbg(codec, "write ACTIVE Reg fail\n");
+               return status;
+       }
+
+       codec_dbg(codec, "   dsp_dma_setup_common()    Write ACTIVE\n");
+
+       status = chipio_write(codec, DSPDMAC_AUDCHSEL_INST_OFFSET(dma_chan),
+                             port_map_mask);
+       if (status < 0) {
+               codec_dbg(codec, "write AUDCHSEL Reg fail\n");
+               return status;
+       }
+       codec_dbg(codec, "   dsp_dma_setup_common()    Write AUDCHSEL\n");
+
+       status = chipio_write(codec, DSPDMAC_IRQCNT_INST_OFFSET(dma_chan),
+                       DSPDMAC_IRQCNT_BICNT_MASK | DSPDMAC_IRQCNT_CICNT_MASK);
+       if (status < 0) {
+               codec_dbg(codec, "write IRQCNT Reg fail\n");
+               return status;
+       }
+       codec_dbg(codec, "   dsp_dma_setup_common()    Write IRQCNT\n");
+
+       codec_dbg(codec,
+                  "ChipA=0x%x,DspA=0x%x,dmaCh=%u, "
+                  "CHSEL=0x%x,CHPROP=0x%x,Active=0x%x\n",
+                  chip_addx, dsp_addx, dma_chan,
+                  port_map_mask, chnl_prop, active);
+
+       codec_dbg(codec, "-- dsp_dma_setup_common() -- Complete ------\n");
+
+       return 0;
+}
+
+/*
+ * Setup the DSP DMA per-transfer-specific registers
+ */
+static int dsp_dma_setup(struct hda_codec *codec,
+                       unsigned int chip_addx,
+                       unsigned int count,
+                       unsigned int dma_chan)
+{
+       int status = 0;
+       bool code, yram;
+       unsigned int dsp_addx;
+       unsigned int addr_field;
+       unsigned int incr_field;
+       unsigned int base_cnt;
+       unsigned int cur_cnt;
+       unsigned int dma_cfg = 0;
+       unsigned int adr_ofs = 0;
+       unsigned int xfr_cnt = 0;
+       const unsigned int max_dma_count = 1 << (DSPDMAC_XFRCNT_BCNT_HIBIT -
+                                               DSPDMAC_XFRCNT_BCNT_LOBIT + 1);
+
+       codec_dbg(codec, "-- dsp_dma_setup() -- Begin ---------\n");
+
+       if (count > max_dma_count) {
+               codec_dbg(codec, "count too big\n");
+               return -EINVAL;
+       }
+
+       dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram);
+       if (dsp_addx == INVALID_CHIP_ADDRESS) {
+               codec_dbg(codec, "invalid chip addr\n");
+               return -ENXIO;
+       }
+
+       codec_dbg(codec, "   dsp_dma_setup()    start reg pgm\n");
+
+       addr_field = dsp_addx << DSPDMAC_DMACFG_DBADR_LOBIT;
+       incr_field   = 0;
+
+       if (!code) {
+               addr_field <<= 1;
+               if (yram)
+                       addr_field |= (1 << DSPDMAC_DMACFG_DBADR_LOBIT);
+
+               incr_field  = (1 << DSPDMAC_DMACFG_AINCR_LOBIT);
+       }
+
+       dma_cfg = addr_field + incr_field;
+       status = chipio_write(codec, DSPDMAC_DMACFG_INST_OFFSET(dma_chan),
+                               dma_cfg);
+       if (status < 0) {
+               codec_dbg(codec, "write DMACFG Reg fail\n");
+               return status;
+       }
+       codec_dbg(codec, "   dsp_dma_setup()    Write DMACFG\n");
+
+       adr_ofs = (count - 1) << (DSPDMAC_DSPADROFS_BOFS_LOBIT +
+                                                       (code ? 0 : 1));
+
+       status = chipio_write(codec, DSPDMAC_DSPADROFS_INST_OFFSET(dma_chan),
+                               adr_ofs);
+       if (status < 0) {
+               codec_dbg(codec, "write DSPADROFS Reg fail\n");
+               return status;
+       }
+       codec_dbg(codec, "   dsp_dma_setup()    Write DSPADROFS\n");
+
+       base_cnt = (count - 1) << DSPDMAC_XFRCNT_BCNT_LOBIT;
+
+       cur_cnt  = (count - 1) << DSPDMAC_XFRCNT_CCNT_LOBIT;
+
+       xfr_cnt = base_cnt | cur_cnt;
+
+       status = chipio_write(codec,
+                               DSPDMAC_XFRCNT_INST_OFFSET(dma_chan), xfr_cnt);
+       if (status < 0) {
+               codec_dbg(codec, "write XFRCNT Reg fail\n");
+               return status;
+       }
+       codec_dbg(codec, "   dsp_dma_setup()    Write XFRCNT\n");
+
+       codec_dbg(codec,
+                  "ChipA=0x%x, cnt=0x%x, DMACFG=0x%x, "
+                  "ADROFS=0x%x, XFRCNT=0x%x\n",
+                  chip_addx, count, dma_cfg, adr_ofs, xfr_cnt);
+
+       codec_dbg(codec, "-- dsp_dma_setup() -- Complete ---------\n");
+
+       return 0;
+}
+
+/*
+ * Start the DSP DMA
+ */
+static int dsp_dma_start(struct hda_codec *codec,
+                        unsigned int dma_chan, bool ovly)
+{
+       unsigned int reg = 0;
+       int status = 0;
+
+       codec_dbg(codec, "-- dsp_dma_start() -- Begin ---------\n");
+
+       if (ovly) {
+               status = chipio_read(codec,
+                                    DSPDMAC_CHNLSTART_INST_OFFSET, &reg);
+
+               if (status < 0) {
+                       codec_dbg(codec, "read CHNLSTART reg fail\n");
+                       return status;
+               }
+               codec_dbg(codec, "-- dsp_dma_start()    Read CHNLSTART\n");
+
+               reg &= ~(DSPDMAC_CHNLSTART_EN_MASK |
+                               DSPDMAC_CHNLSTART_DIS_MASK);
+       }
+
+       status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET,
+                       reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_EN_LOBIT)));
+       if (status < 0) {
+               codec_dbg(codec, "write CHNLSTART reg fail\n");
+               return status;
+       }
+       codec_dbg(codec, "-- dsp_dma_start() -- Complete ---------\n");
+
+       return status;
+}
+
+/*
+ * Stop the DSP DMA
+ */
+static int dsp_dma_stop(struct hda_codec *codec,
+                       unsigned int dma_chan, bool ovly)
+{
+       unsigned int reg = 0;
+       int status = 0;
+
+       codec_dbg(codec, "-- dsp_dma_stop() -- Begin ---------\n");
+
+       if (ovly) {
+               status = chipio_read(codec,
+                                    DSPDMAC_CHNLSTART_INST_OFFSET, &reg);
+
+               if (status < 0) {
+                       codec_dbg(codec, "read CHNLSTART reg fail\n");
+                       return status;
+               }
+               codec_dbg(codec, "-- dsp_dma_stop()    Read CHNLSTART\n");
+               reg &= ~(DSPDMAC_CHNLSTART_EN_MASK |
+                               DSPDMAC_CHNLSTART_DIS_MASK);
+       }
+
+       status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET,
+                       reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_DIS_LOBIT)));
+       if (status < 0) {
+               codec_dbg(codec, "write CHNLSTART reg fail\n");
+               return status;
+       }
+       codec_dbg(codec, "-- dsp_dma_stop() -- Complete ---------\n");
+
+       return status;
+}
+
+/**
+ * dsp_allocate_router_ports - Allocate router ports
+ *
+ * @codec: the HDA codec
+ * @num_chans: number of channels in the stream
+ * @ports_per_channel: number of ports per channel
+ * @start_device: start device
+ * @port_map: pointer to the port list to hold the allocated ports
+ *
+ * Returns zero or a negative error code.
+ */
+static int dsp_allocate_router_ports(struct hda_codec *codec,
+                                    unsigned int num_chans,
+                                    unsigned int ports_per_channel,
+                                    unsigned int start_device,
+                                    unsigned int *port_map)
+{
+       int status = 0;
+       int res;
+       u8 val;
+
+       status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
+       if (status < 0)
+               return status;
+
+       val = start_device << 6;
+       val |= (ports_per_channel - 1) << 4;
+       val |= num_chans - 1;
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET,
+                           val);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PORT_ALLOC_SET,
+                           MEM_CONNID_DSP);
+
+       status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
+       if (status < 0)
+               return status;
+
+       res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
+                               VENDOR_CHIPIO_PORT_ALLOC_GET, 0);
+
+       *port_map = res;
+
+       return (res < 0) ? res : 0;
+}
+
+/*
+ * Free router ports
+ */
+static int dsp_free_router_ports(struct hda_codec *codec)
+{
+       int status = 0;
+
+       status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
+       if (status < 0)
+               return status;
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PORT_FREE_SET,
+                           MEM_CONNID_DSP);
+
+       status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
+
+       return status;
+}
+
+/*
+ * Allocate DSP ports for the download stream
+ */
+static int dsp_allocate_ports(struct hda_codec *codec,
+                       unsigned int num_chans,
+                       unsigned int rate_multi, unsigned int *port_map)
+{
+       int status;
+
+       codec_dbg(codec, "     dsp_allocate_ports() -- begin\n");
+
+       if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) {
+               codec_dbg(codec, "bad rate multiple\n");
+               return -EINVAL;
+       }
+
+       status = dsp_allocate_router_ports(codec, num_chans,
+                                          rate_multi, 0, port_map);
+
+       codec_dbg(codec, "     dsp_allocate_ports() -- complete\n");
+
+       return status;
+}
+
+static int dsp_allocate_ports_format(struct hda_codec *codec,
+                       const unsigned short fmt,
+                       unsigned int *port_map)
+{
+       unsigned int num_chans;
+
+       unsigned int sample_rate_div = ((get_hdafmt_rate(fmt) >> 0) & 3) + 1;
+       unsigned int sample_rate_mul = ((get_hdafmt_rate(fmt) >> 3) & 3) + 1;
+       unsigned int rate_multi = sample_rate_mul / sample_rate_div;
+
+       if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) {
+               codec_dbg(codec, "bad rate multiple\n");
+               return -EINVAL;
+       }
+
+       num_chans = get_hdafmt_chs(fmt) + 1;
+
+       return dsp_allocate_ports(codec, num_chans, rate_multi, port_map);
+}
+
+/*
+ * free DSP ports
+ */
+static int dsp_free_ports(struct hda_codec *codec)
+{
+       int status;
+
+       codec_dbg(codec, "     dsp_free_ports() -- begin\n");
+
+       status = dsp_free_router_ports(codec);
+       if (status < 0) {
+               codec_dbg(codec, "free router ports fail\n");
+               return status;
+       }
+       codec_dbg(codec, "     dsp_free_ports() -- complete\n");
+
+       return status;
+}
+
+/*
+ *  HDA DMA engine stuffs for DSP code download
+ */
+struct dma_engine {
+       struct hda_codec *codec;
+       unsigned short m_converter_format;
+       struct snd_dma_buffer *dmab;
+       unsigned int buf_size;
+};
+
+
+enum dma_state {
+       DMA_STATE_STOP  = 0,
+       DMA_STATE_RUN   = 1
+};
+
+static int dma_convert_to_hda_format(struct hda_codec *codec,
+               unsigned int sample_rate,
+               unsigned short channels,
+               unsigned short *hda_format)
+{
+       unsigned int format_val;
+
+       format_val = snd_hdac_stream_format(channels, 32, sample_rate);
+
+       if (hda_format)
+               *hda_format = (unsigned short)format_val;
+
+       return 0;
+}
+
+/*
+ *  Reset DMA for DSP download
+ */
+static int dma_reset(struct dma_engine *dma)
+{
+       struct hda_codec *codec = dma->codec;
+       struct ca0132_spec *spec = codec->spec;
+       int status;
+
+       if (dma->dmab->area)
+               snd_hda_codec_load_dsp_cleanup(codec, dma->dmab);
+
+       status = snd_hda_codec_load_dsp_prepare(codec,
+                       dma->m_converter_format,
+                       dma->buf_size,
+                       dma->dmab);
+       if (status < 0)
+               return status;
+       spec->dsp_stream_id = status;
+       return 0;
+}
+
+static int dma_set_state(struct dma_engine *dma, enum dma_state state)
+{
+       bool cmd;
+
+       switch (state) {
+       case DMA_STATE_STOP:
+               cmd = false;
+               break;
+       case DMA_STATE_RUN:
+               cmd = true;
+               break;
+       default:
+               return 0;
+       }
+
+       snd_hda_codec_load_dsp_trigger(dma->codec, cmd);
+       return 0;
+}
+
+static unsigned int dma_get_buffer_size(struct dma_engine *dma)
+{
+       return dma->dmab->bytes;
+}
+
+static unsigned char *dma_get_buffer_addr(struct dma_engine *dma)
+{
+       return dma->dmab->area;
+}
+
+static int dma_xfer(struct dma_engine *dma,
+               const unsigned int *data,
+               unsigned int count)
+{
+       memcpy(dma->dmab->area, data, count);
+       return 0;
+}
+
+static void dma_get_converter_format(
+               struct dma_engine *dma,
+               unsigned short *format)
+{
+       if (format)
+               *format = dma->m_converter_format;
+}
+
+static unsigned int dma_get_stream_id(struct dma_engine *dma)
+{
+       struct ca0132_spec *spec = dma->codec->spec;
+
+       return spec->dsp_stream_id;
+}
+
+struct dsp_image_seg {
+       u32 magic;
+       u32 chip_addr;
+       u32 count;
+       u32 data[];
+};
+
+static const u32 g_magic_value = 0x4c46584d;
+static const u32 g_chip_addr_magic_value = 0xFFFFFF01;
+
+static bool is_valid(const struct dsp_image_seg *p)
+{
+       return p->magic == g_magic_value;
+}
+
+static bool is_hci_prog_list_seg(const struct dsp_image_seg *p)
+{
+       return g_chip_addr_magic_value == p->chip_addr;
+}
+
+static bool is_last(const struct dsp_image_seg *p)
+{
+       return p->count == 0;
+}
+
+static size_t dsp_sizeof(const struct dsp_image_seg *p)
+{
+       return struct_size(p, data, p->count);
+}
+
+static const struct dsp_image_seg *get_next_seg_ptr(
+                               const struct dsp_image_seg *p)
+{
+       return (struct dsp_image_seg *)((unsigned char *)(p) + dsp_sizeof(p));
+}
+
+/*
+ * CA0132 chip DSP transfer stuffs.  For DSP download.
+ */
+#define INVALID_DMA_CHANNEL (~0U)
+
+/*
+ * Program a list of address/data pairs via the ChipIO widget.
+ * The segment data is in the format of successive pairs of words.
+ * These are repeated as indicated by the segment's count field.
+ */
+static int dspxfr_hci_write(struct hda_codec *codec,
+                       const struct dsp_image_seg *fls)
+{
+       int status;
+       const u32 *data;
+       unsigned int count;
+
+       if (fls == NULL || fls->chip_addr != g_chip_addr_magic_value) {
+               codec_dbg(codec, "hci_write invalid params\n");
+               return -EINVAL;
+       }
+
+       count = fls->count;
+       data = (u32 *)(fls->data);
+       while (count >= 2) {
+               status = chipio_write(codec, data[0], data[1]);
+               if (status < 0) {
+                       codec_dbg(codec, "hci_write chipio failed\n");
+                       return status;
+               }
+               count -= 2;
+               data  += 2;
+       }
+       return 0;
+}
+
+/**
+ * dspxfr_one_seg - Write a block of data into DSP code or data RAM using pre-allocated DMA engine.
+ *
+ * @codec: the HDA codec
+ * @fls: pointer to a fast load image
+ * @reloc: Relocation address for loading single-segment overlays, or 0 for
+ *        no relocation
+ * @dma_engine: pointer to DMA engine to be used for DSP download
+ * @dma_chan: The number of DMA channels used for DSP download
+ * @port_map_mask: port mapping
+ * @ovly: TRUE if overlay format is required
+ *
+ * Returns zero or a negative error code.
+ */
+static int dspxfr_one_seg(struct hda_codec *codec,
+                       const struct dsp_image_seg *fls,
+                       unsigned int reloc,
+                       struct dma_engine *dma_engine,
+                       unsigned int dma_chan,
+                       unsigned int port_map_mask,
+                       bool ovly)
+{
+       int status = 0;
+       bool comm_dma_setup_done = false;
+       const unsigned int *data;
+       unsigned int chip_addx;
+       unsigned int words_to_write;
+       unsigned int buffer_size_words;
+       unsigned char *buffer_addx;
+       unsigned short hda_format;
+       unsigned int sample_rate_div;
+       unsigned int sample_rate_mul;
+       unsigned int num_chans;
+       unsigned int hda_frame_size_words;
+       unsigned int remainder_words;
+       const u32 *data_remainder;
+       u32 chip_addx_remainder;
+       unsigned int run_size_words;
+       const struct dsp_image_seg *hci_write = NULL;
+       unsigned long timeout;
+       bool dma_active;
+
+       if (fls == NULL)
+               return -EINVAL;
+       if (is_hci_prog_list_seg(fls)) {
+               hci_write = fls;
+               fls = get_next_seg_ptr(fls);
+       }
+
+       if (hci_write && (!fls || is_last(fls))) {
+               codec_dbg(codec, "hci_write\n");
+               return dspxfr_hci_write(codec, hci_write);
+       }
+
+       if (fls == NULL || dma_engine == NULL || port_map_mask == 0) {
+               codec_dbg(codec, "Invalid Params\n");
+               return -EINVAL;
+       }
+
+       data = fls->data;
+       chip_addx = fls->chip_addr;
+       words_to_write = fls->count;
+
+       if (!words_to_write)
+               return hci_write ? dspxfr_hci_write(codec, hci_write) : 0;
+       if (reloc)
+               chip_addx = (chip_addx & (0xFFFF0000 << 2)) + (reloc << 2);
+
+       if (!UC_RANGE(chip_addx, words_to_write) &&
+           !X_RANGE_ALL(chip_addx, words_to_write) &&
+           !Y_RANGE_ALL(chip_addx, words_to_write)) {
+               codec_dbg(codec, "Invalid chip_addx Params\n");
+               return -EINVAL;
+       }
+
+       buffer_size_words = (unsigned int)dma_get_buffer_size(dma_engine) /
+                                       sizeof(u32);
+
+       buffer_addx = dma_get_buffer_addr(dma_engine);
+
+       if (buffer_addx == NULL) {
+               codec_dbg(codec, "dma_engine buffer NULL\n");
+               return -EINVAL;
+       }
+
+       dma_get_converter_format(dma_engine, &hda_format);
+       sample_rate_div = ((get_hdafmt_rate(hda_format) >> 0) & 3) + 1;
+       sample_rate_mul = ((get_hdafmt_rate(hda_format) >> 3) & 3) + 1;
+       num_chans = get_hdafmt_chs(hda_format) + 1;
+
+       hda_frame_size_words = ((sample_rate_div == 0) ? 0 :
+                       (num_chans * sample_rate_mul / sample_rate_div));
+
+       if (hda_frame_size_words == 0) {
+               codec_dbg(codec, "frmsz zero\n");
+               return -EINVAL;
+       }
+
+       buffer_size_words = min(buffer_size_words,
+                               (unsigned int)(UC_RANGE(chip_addx, 1) ?
+                               65536 : 32768));
+       buffer_size_words -= buffer_size_words % hda_frame_size_words;
+       codec_dbg(codec,
+                  "chpadr=0x%08x frmsz=%u nchan=%u "
+                  "rate_mul=%u div=%u bufsz=%u\n",
+                  chip_addx, hda_frame_size_words, num_chans,
+                  sample_rate_mul, sample_rate_div, buffer_size_words);
+
+       if (buffer_size_words < hda_frame_size_words) {
+               codec_dbg(codec, "dspxfr_one_seg:failed\n");
+               return -EINVAL;
+       }
+
+       remainder_words = words_to_write % hda_frame_size_words;
+       data_remainder = data;
+       chip_addx_remainder = chip_addx;
+
+       data += remainder_words;
+       chip_addx += remainder_words*sizeof(u32);
+       words_to_write -= remainder_words;
+
+       while (words_to_write != 0) {
+               run_size_words = min(buffer_size_words, words_to_write);
+               codec_dbg(codec, "dspxfr (seg loop)cnt=%u rs=%u remainder=%u\n",
+                           words_to_write, run_size_words, remainder_words);
+               dma_xfer(dma_engine, data, run_size_words*sizeof(u32));
+               if (!comm_dma_setup_done) {
+                       status = dsp_dma_stop(codec, dma_chan, ovly);
+                       if (status < 0)
+                               return status;
+                       status = dsp_dma_setup_common(codec, chip_addx,
+                                               dma_chan, port_map_mask, ovly);
+                       if (status < 0)
+                               return status;
+                       comm_dma_setup_done = true;
+               }
+
+               status = dsp_dma_setup(codec, chip_addx,
+                                               run_size_words, dma_chan);
+               if (status < 0)
+                       return status;
+               status = dsp_dma_start(codec, dma_chan, ovly);
+               if (status < 0)
+                       return status;
+               if (!dsp_is_dma_active(codec, dma_chan)) {
+                       codec_dbg(codec, "dspxfr:DMA did not start\n");
+                       return -EIO;
+               }
+               status = dma_set_state(dma_engine, DMA_STATE_RUN);
+               if (status < 0)
+                       return status;
+               if (remainder_words != 0) {
+                       status = chipio_write_multiple(codec,
+                                               chip_addx_remainder,
+                                               data_remainder,
+                                               remainder_words);
+                       if (status < 0)
+                               return status;
+                       remainder_words = 0;
+               }
+               if (hci_write) {
+                       status = dspxfr_hci_write(codec, hci_write);
+                       if (status < 0)
+                               return status;
+                       hci_write = NULL;
+               }
+
+               timeout = jiffies + msecs_to_jiffies(2000);
+               do {
+                       dma_active = dsp_is_dma_active(codec, dma_chan);
+                       if (!dma_active)
+                               break;
+                       msleep(20);
+               } while (time_before(jiffies, timeout));
+               if (dma_active)
+                       break;
+
+               codec_dbg(codec, "+++++ DMA complete\n");
+               dma_set_state(dma_engine, DMA_STATE_STOP);
+               status = dma_reset(dma_engine);
+
+               if (status < 0)
+                       return status;
+
+               data += run_size_words;
+               chip_addx += run_size_words*sizeof(u32);
+               words_to_write -= run_size_words;
+       }
+
+       if (remainder_words != 0) {
+               status = chipio_write_multiple(codec, chip_addx_remainder,
+                                       data_remainder, remainder_words);
+       }
+
+       return status;
+}
+
+/**
+ * dspxfr_image - Write the entire DSP image of a DSP code/data overlay to DSP memories
+ *
+ * @codec: the HDA codec
+ * @fls_data: pointer to a fast load image
+ * @reloc: Relocation address for loading single-segment overlays, or 0 for
+ *        no relocation
+ * @sample_rate: sampling rate of the stream used for DSP download
+ * @channels: channels of the stream used for DSP download
+ * @ovly: TRUE if overlay format is required
+ *
+ * Returns zero or a negative error code.
+ */
+static int dspxfr_image(struct hda_codec *codec,
+                       const struct dsp_image_seg *fls_data,
+                       unsigned int reloc,
+                       unsigned int sample_rate,
+                       unsigned short channels,
+                       bool ovly)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int status;
+       unsigned short hda_format = 0;
+       unsigned int response;
+       unsigned char stream_id = 0;
+       struct dma_engine *dma_engine;
+       unsigned int dma_chan;
+       unsigned int port_map_mask;
+
+       if (fls_data == NULL)
+               return -EINVAL;
+
+       dma_engine = kzalloc(sizeof(*dma_engine), GFP_KERNEL);
+       if (!dma_engine)
+               return -ENOMEM;
+
+       dma_engine->dmab = kzalloc(sizeof(*dma_engine->dmab), GFP_KERNEL);
+       if (!dma_engine->dmab) {
+               kfree(dma_engine);
+               return -ENOMEM;
+       }
+
+       dma_engine->codec = codec;
+       dma_convert_to_hda_format(codec, sample_rate, channels, &hda_format);
+       dma_engine->m_converter_format = hda_format;
+       dma_engine->buf_size = (ovly ? DSP_DMA_WRITE_BUFLEN_OVLY :
+                       DSP_DMA_WRITE_BUFLEN_INIT) * 2;
+
+       dma_chan = ovly ? INVALID_DMA_CHANNEL : 0;
+
+       status = codec_set_converter_format(codec, WIDGET_CHIP_CTRL,
+                                       hda_format, &response);
+
+       if (status < 0) {
+               codec_dbg(codec, "set converter format fail\n");
+               goto exit;
+       }
+
+       status = snd_hda_codec_load_dsp_prepare(codec,
+                               dma_engine->m_converter_format,
+                               dma_engine->buf_size,
+                               dma_engine->dmab);
+       if (status < 0)
+               goto exit;
+       spec->dsp_stream_id = status;
+
+       if (ovly) {
+               status = dspio_alloc_dma_chan(codec, &dma_chan);
+               if (status < 0) {
+                       codec_dbg(codec, "alloc dmachan fail\n");
+                       dma_chan = INVALID_DMA_CHANNEL;
+                       goto exit;
+               }
+       }
+
+       port_map_mask = 0;
+       status = dsp_allocate_ports_format(codec, hda_format,
+                                       &port_map_mask);
+       if (status < 0) {
+               codec_dbg(codec, "alloc ports fail\n");
+               goto exit;
+       }
+
+       stream_id = dma_get_stream_id(dma_engine);
+       status = codec_set_converter_stream_channel(codec,
+                       WIDGET_CHIP_CTRL, stream_id, 0, &response);
+       if (status < 0) {
+               codec_dbg(codec, "set stream chan fail\n");
+               goto exit;
+       }
+
+       while ((fls_data != NULL) && !is_last(fls_data)) {
+               if (!is_valid(fls_data)) {
+                       codec_dbg(codec, "FLS check fail\n");
+                       status = -EINVAL;
+                       goto exit;
+               }
+               status = dspxfr_one_seg(codec, fls_data, reloc,
+                                       dma_engine, dma_chan,
+                                       port_map_mask, ovly);
+               if (status < 0)
+                       break;
+
+               if (is_hci_prog_list_seg(fls_data))
+                       fls_data = get_next_seg_ptr(fls_data);
+
+               if ((fls_data != NULL) && !is_last(fls_data))
+                       fls_data = get_next_seg_ptr(fls_data);
+       }
+
+       if (port_map_mask != 0)
+               status = dsp_free_ports(codec);
+
+       if (status < 0)
+               goto exit;
+
+       status = codec_set_converter_stream_channel(codec,
+                               WIDGET_CHIP_CTRL, 0, 0, &response);
+
+exit:
+       if (ovly && (dma_chan != INVALID_DMA_CHANNEL))
+               dspio_free_dma_chan(codec, dma_chan);
+
+       if (dma_engine->dmab->area)
+               snd_hda_codec_load_dsp_cleanup(codec, dma_engine->dmab);
+       kfree(dma_engine->dmab);
+       kfree(dma_engine);
+
+       return status;
+}
+
+/*
+ * CA0132 DSP download stuffs.
+ */
+static void dspload_post_setup(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       codec_dbg(codec, "---- dspload_post_setup ------\n");
+       if (!ca0132_use_alt_functions(spec)) {
+               /*set DSP speaker to 2.0 configuration*/
+               chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080);
+               chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x19), 0x3f800000);
+
+               /*update write pointer*/
+               chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x29), 0x00000002);
+       }
+}
+
+/**
+ * dspload_image - Download DSP from a DSP Image Fast Load structure.
+ *
+ * @codec: the HDA codec
+ * @fls: pointer to a fast load image
+ * @ovly: TRUE if overlay format is required
+ * @reloc: Relocation address for loading single-segment overlays, or 0 for
+ *        no relocation
+ * @autostart: TRUE if DSP starts after loading; ignored if ovly is TRUE
+ * @router_chans: number of audio router channels to be allocated (0 means use
+ *               internal defaults; max is 32)
+ *
+ * Download DSP from a DSP Image Fast Load structure. This structure is a
+ * linear, non-constant sized element array of structures, each of which
+ * contain the count of the data to be loaded, the data itself, and the
+ * corresponding starting chip address of the starting data location.
+ * Returns zero or a negative error code.
+ */
+static int dspload_image(struct hda_codec *codec,
+                       const struct dsp_image_seg *fls,
+                       bool ovly,
+                       unsigned int reloc,
+                       bool autostart,
+                       int router_chans)
+{
+       int status = 0;
+       unsigned int sample_rate;
+       unsigned short channels;
+
+       codec_dbg(codec, "---- dspload_image begin ------\n");
+       if (router_chans == 0) {
+               if (!ovly)
+                       router_chans = DMA_TRANSFER_FRAME_SIZE_NWORDS;
+               else
+                       router_chans = DMA_OVERLAY_FRAME_SIZE_NWORDS;
+       }
+
+       sample_rate = 48000;
+       channels = (unsigned short)router_chans;
+
+       while (channels > 16) {
+               sample_rate *= 2;
+               channels /= 2;
+       }
+
+       do {
+               codec_dbg(codec, "Ready to program DMA\n");
+               if (!ovly)
+                       status = dsp_reset(codec);
+
+               if (status < 0)
+                       break;
+
+               codec_dbg(codec, "dsp_reset() complete\n");
+               status = dspxfr_image(codec, fls, reloc, sample_rate, channels,
+                                     ovly);
+
+               if (status < 0)
+                       break;
+
+               codec_dbg(codec, "dspxfr_image() complete\n");
+               if (autostart && !ovly) {
+                       dspload_post_setup(codec);
+                       status = dsp_set_run_state(codec);
+               }
+
+               codec_dbg(codec, "LOAD FINISHED\n");
+       } while (0);
+
+       return status;
+}
+
+#ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP
+static bool dspload_is_loaded(struct hda_codec *codec)
+{
+       unsigned int data = 0;
+       int status = 0;
+
+       status = chipio_read(codec, 0x40004, &data);
+       if ((status < 0) || (data != 1))
+               return false;
+
+       return true;
+}
+#else
+#define dspload_is_loaded(codec)       false
+#endif
+
+static bool dspload_wait_loaded(struct hda_codec *codec)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(2000);
+
+       do {
+               if (dspload_is_loaded(codec)) {
+                       codec_info(codec, "ca0132 DSP downloaded and running\n");
+                       return true;
+               }
+               msleep(20);
+       } while (time_before(jiffies, timeout));
+
+       codec_err(codec, "ca0132 failed to download DSP\n");
+       return false;
+}
+
+/*
+ * ca0113 related functions. The ca0113 acts as the HDA bus for the pci-e
+ * based cards, and has a second mmio region, region2, that's used for special
+ * commands.
+ */
+
+/*
+ * For cards with PCI-E region2 (Sound Blaster Z/ZxR, Recon3D, and AE-5)
+ * the mmio address 0x320 is used to set GPIO pins. The format for the data
+ * The first eight bits are just the number of the pin. So far, I've only seen
+ * this number go to 7.
+ * AE-5 note: The AE-5 seems to use pins 2 and 3 to somehow set the color value
+ * of the on-card LED. It seems to use pin 2 for data, then toggles 3 to on and
+ * then off to send that bit.
+ */
+static void ca0113_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
+               bool enable)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned short gpio_data;
+
+       gpio_data = gpio_pin & 0xF;
+       gpio_data |= ((enable << 8) & 0x100);
+
+       writew(gpio_data, spec->mem_base + 0x320);
+}
+
+/*
+ * Special pci region2 commands that are only used by the AE-5. They follow
+ * a set format, and require reads at certain points to seemingly 'clear'
+ * the response data. My first tests didn't do these reads, and would cause
+ * the card to get locked up until the memory was read. These commands
+ * seem to work with three distinct values that I've taken to calling group,
+ * target-id, and value.
+ */
+static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group,
+               unsigned int target, unsigned int value)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int write_val;
+
+       writel(0x0000007e, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       writel(0x0000005a, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+
+       writel(0x00800005, spec->mem_base + 0x20c);
+       writel(group, spec->mem_base + 0x804);
+
+       writel(0x00800005, spec->mem_base + 0x20c);
+       write_val = (target & 0xff);
+       write_val |= (value << 8);
+
+
+       writel(write_val, spec->mem_base + 0x204);
+       /*
+        * Need delay here or else it goes too fast and works inconsistently.
+        */
+       msleep(20);
+
+       readl(spec->mem_base + 0x860);
+       readl(spec->mem_base + 0x854);
+       readl(spec->mem_base + 0x840);
+
+       writel(0x00800004, spec->mem_base + 0x20c);
+       writel(0x00000000, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+}
+
+/*
+ * This second type of command is used for setting the sound filter type.
+ */
+static void ca0113_mmio_command_set_type2(struct hda_codec *codec,
+               unsigned int group, unsigned int target, unsigned int value)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int write_val;
+
+       writel(0x0000007e, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       writel(0x0000005a, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+
+       writel(0x00800003, spec->mem_base + 0x20c);
+       writel(group, spec->mem_base + 0x804);
+
+       writel(0x00800005, spec->mem_base + 0x20c);
+       write_val = (target & 0xff);
+       write_val |= (value << 8);
+
+
+       writel(write_val, spec->mem_base + 0x204);
+       msleep(20);
+       readl(spec->mem_base + 0x860);
+       readl(spec->mem_base + 0x854);
+       readl(spec->mem_base + 0x840);
+
+       writel(0x00800004, spec->mem_base + 0x20c);
+       writel(0x00000000, spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+       readl(spec->mem_base + 0x210);
+}
+
+/*
+ * Setup GPIO for the other variants of Core3D.
+ */
+
+/*
+ * Sets up the GPIO pins so that they are discoverable. If this isn't done,
+ * the card shows as having no GPIO pins.
+ */
+static void ca0132_gpio_init(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+       case QUIRK_AE5:
+       case QUIRK_AE7:
+               snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+               snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+               snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23);
+               break;
+       case QUIRK_R3DI:
+               snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+               snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5B);
+               break;
+       default:
+               break;
+       }
+
+}
+
+/* Sets the GPIO for audio output. */
+static void ca0132_gpio_setup(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_DIRECTION, 0x07);
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_MASK, 0x07);
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_DATA, 0x04);
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_DATA, 0x06);
+               break;
+       case QUIRK_R3DI:
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_DIRECTION, 0x1E);
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_MASK, 0x1F);
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_DATA, 0x0C);
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * GPIO control functions for the Recon3D integrated.
+ */
+
+enum r3di_gpio_bit {
+       /* Bit 1 - Switch between front/rear mic. 0 = rear, 1 = front */
+       R3DI_MIC_SELECT_BIT = 1,
+       /* Bit 2 - Switch between headphone/line out. 0 = Headphone, 1 = Line */
+       R3DI_OUT_SELECT_BIT = 2,
+       /*
+        * I dunno what this actually does, but it stays on until the dsp
+        * is downloaded.
+        */
+       R3DI_GPIO_DSP_DOWNLOADING = 3,
+       /*
+        * Same as above, no clue what it does, but it comes on after the dsp
+        * is downloaded.
+        */
+       R3DI_GPIO_DSP_DOWNLOADED = 4
+};
+
+enum r3di_mic_select {
+       /* Set GPIO bit 1 to 0 for rear mic */
+       R3DI_REAR_MIC = 0,
+       /* Set GPIO bit 1 to 1 for front microphone*/
+       R3DI_FRONT_MIC = 1
+};
+
+enum r3di_out_select {
+       /* Set GPIO bit 2 to 0 for headphone */
+       R3DI_HEADPHONE_OUT = 0,
+       /* Set GPIO bit 2 to 1 for speaker */
+       R3DI_LINE_OUT = 1
+};
+enum r3di_dsp_status {
+       /* Set GPIO bit 3 to 1 until DSP is downloaded */
+       R3DI_DSP_DOWNLOADING = 0,
+       /* Set GPIO bit 4 to 1 once DSP is downloaded */
+       R3DI_DSP_DOWNLOADED = 1
+};
+
+
+static void r3di_gpio_mic_set(struct hda_codec *codec,
+               enum r3di_mic_select cur_mic)
+{
+       unsigned int cur_gpio;
+
+       /* Get the current GPIO Data setup */
+       cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0);
+
+       switch (cur_mic) {
+       case R3DI_REAR_MIC:
+               cur_gpio &= ~(1 << R3DI_MIC_SELECT_BIT);
+               break;
+       case R3DI_FRONT_MIC:
+               cur_gpio |= (1 << R3DI_MIC_SELECT_BIT);
+               break;
+       }
+       snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_SET_GPIO_DATA, cur_gpio);
+}
+
+static void r3di_gpio_dsp_status_set(struct hda_codec *codec,
+               enum r3di_dsp_status dsp_status)
+{
+       unsigned int cur_gpio;
+
+       /* Get the current GPIO Data setup */
+       cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0);
+
+       switch (dsp_status) {
+       case R3DI_DSP_DOWNLOADING:
+               cur_gpio |= (1 << R3DI_GPIO_DSP_DOWNLOADING);
+               snd_hda_codec_write(codec, codec->core.afg, 0,
+                               AC_VERB_SET_GPIO_DATA, cur_gpio);
+               break;
+       case R3DI_DSP_DOWNLOADED:
+               /* Set DOWNLOADING bit to 0. */
+               cur_gpio &= ~(1 << R3DI_GPIO_DSP_DOWNLOADING);
+
+               snd_hda_codec_write(codec, codec->core.afg, 0,
+                               AC_VERB_SET_GPIO_DATA, cur_gpio);
+
+               cur_gpio |= (1 << R3DI_GPIO_DSP_DOWNLOADED);
+               break;
+       }
+
+       snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_SET_GPIO_DATA, cur_gpio);
+}
+
+/*
+ * PCM callbacks
+ */
+static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       unsigned int stream_tag,
+                       unsigned int format,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
+
+       return 0;
+}
+
+static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       if (spec->dsp_state == DSP_DOWNLOADING)
+               return 0;
+
+       /*If Playback effects are on, allow stream some time to flush
+        *effects tail*/
+       if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
+               msleep(50);
+
+       snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
+
+       return 0;
+}
+
+static unsigned int ca0132_playback_pcm_delay(struct hda_pcm_stream *info,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int latency = DSP_PLAYBACK_INIT_LATENCY;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return 0;
+
+       /* Add latency if playback enhancement and either effect is enabled. */
+       if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) {
+               if ((spec->effects_switch[SURROUND - EFFECT_START_NID]) ||
+                   (spec->effects_switch[DIALOG_PLUS - EFFECT_START_NID]))
+                       latency += DSP_PLAY_ENHANCEMENT_LATENCY;
+       }
+
+       /* Applying Speaker EQ adds latency as well. */
+       if (spec->cur_out_type == SPEAKER_OUT)
+               latency += DSP_SPEAKER_OUT_LATENCY;
+
+       return (latency * runtime->rate) / 1000;
+}
+
+/*
+ * Digital out
+ */
+static int ca0132_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int ca0132_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       unsigned int stream_tag,
+                       unsigned int format,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+                                            stream_tag, format, substream);
+}
+
+static int ca0132_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
+}
+
+static int ca0132_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                        struct hda_codec *codec,
+                                        struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                       struct hda_codec *codec,
+                                       unsigned int stream_tag,
+                                       unsigned int format,
+                                       struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, hinfo->nid,
+                                  stream_tag, 0, format);
+
+       return 0;
+}
+
+static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       if (spec->dsp_state == DSP_DOWNLOADING)
+               return 0;
+
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+       return 0;
+}
+
+static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info,
+                       struct hda_codec *codec,
+                       struct snd_pcm_substream *substream)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int latency = DSP_CAPTURE_INIT_LATENCY;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return 0;
+
+       if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID])
+               latency += DSP_CRYSTAL_VOICE_LATENCY;
+
+       return (latency * runtime->rate) / 1000;
+}
+
+/*
+ * Controls stuffs.
+ */
+
+/*
+ * Mixer controls helpers.
+ */
+#define CA0132_CODEC_VOL_MONO(xname, nid, channel, dir) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+         .name = xname, \
+         .subdevice = HDA_SUBDEV_AMP_FLAG, \
+         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
+         .info = ca0132_volume_info, \
+         .get = ca0132_volume_get, \
+         .put = ca0132_volume_put, \
+         .tlv = { .c = ca0132_volume_tlv }, \
+         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
+
+/*
+ * Creates a mixer control that uses defaults of HDA_CODEC_VOL except for the
+ * volume put, which is used for setting the DSP volume. This was done because
+ * the ca0132 functions were taking too much time and causing lag.
+ */
+#define CA0132_ALT_CODEC_VOL_MONO(xname, nid, channel, dir) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+         .name = xname, \
+         .subdevice = HDA_SUBDEV_AMP_FLAG, \
+         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
+         .info = snd_hda_mixer_amp_volume_info, \
+         .get = snd_hda_mixer_amp_volume_get, \
+         .put = ca0132_alt_volume_put, \
+         .tlv = { .c = snd_hda_mixer_amp_tlv }, \
+         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
+
+#define CA0132_CODEC_MUTE_MONO(xname, nid, channel, dir) \
+       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+         .name = xname, \
+         .subdevice = HDA_SUBDEV_AMP_FLAG, \
+         .info = snd_hda_mixer_amp_switch_info, \
+         .get = ca0132_switch_get, \
+         .put = ca0132_switch_put, \
+         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
+
+/* stereo */
+#define CA0132_CODEC_VOL(xname, nid, dir) \
+       CA0132_CODEC_VOL_MONO(xname, nid, 3, dir)
+#define CA0132_ALT_CODEC_VOL(xname, nid, dir) \
+       CA0132_ALT_CODEC_VOL_MONO(xname, nid, 3, dir)
+#define CA0132_CODEC_MUTE(xname, nid, dir) \
+       CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir)
+
+/* lookup tables */
+/*
+ * Lookup table with decibel values for the DSP. When volume is changed in
+ * Windows, the DSP is also sent the dB value in floating point. In Windows,
+ * these values have decimal points, probably because the Windows driver
+ * actually uses floating point. We can't here, so I made a lookup table of
+ * values -90 to 9. -90 is the lowest decibel value for both the ADC's and the
+ * DAC's, and 9 is the maximum.
+ */
+static const unsigned int float_vol_db_lookup[] = {
+0xC2B40000, 0xC2B20000, 0xC2B00000, 0xC2AE0000, 0xC2AC0000, 0xC2AA0000,
+0xC2A80000, 0xC2A60000, 0xC2A40000, 0xC2A20000, 0xC2A00000, 0xC29E0000,
+0xC29C0000, 0xC29A0000, 0xC2980000, 0xC2960000, 0xC2940000, 0xC2920000,
+0xC2900000, 0xC28E0000, 0xC28C0000, 0xC28A0000, 0xC2880000, 0xC2860000,
+0xC2840000, 0xC2820000, 0xC2800000, 0xC27C0000, 0xC2780000, 0xC2740000,
+0xC2700000, 0xC26C0000, 0xC2680000, 0xC2640000, 0xC2600000, 0xC25C0000,
+0xC2580000, 0xC2540000, 0xC2500000, 0xC24C0000, 0xC2480000, 0xC2440000,
+0xC2400000, 0xC23C0000, 0xC2380000, 0xC2340000, 0xC2300000, 0xC22C0000,
+0xC2280000, 0xC2240000, 0xC2200000, 0xC21C0000, 0xC2180000, 0xC2140000,
+0xC2100000, 0xC20C0000, 0xC2080000, 0xC2040000, 0xC2000000, 0xC1F80000,
+0xC1F00000, 0xC1E80000, 0xC1E00000, 0xC1D80000, 0xC1D00000, 0xC1C80000,
+0xC1C00000, 0xC1B80000, 0xC1B00000, 0xC1A80000, 0xC1A00000, 0xC1980000,
+0xC1900000, 0xC1880000, 0xC1800000, 0xC1700000, 0xC1600000, 0xC1500000,
+0xC1400000, 0xC1300000, 0xC1200000, 0xC1100000, 0xC1000000, 0xC0E00000,
+0xC0C00000, 0xC0A00000, 0xC0800000, 0xC0400000, 0xC0000000, 0xBF800000,
+0x00000000, 0x3F800000, 0x40000000, 0x40400000, 0x40800000, 0x40A00000,
+0x40C00000, 0x40E00000, 0x41000000, 0x41100000
+};
+
+/*
+ * This table counts from float 0 to 1 in increments of .01, which is
+ * useful for a few different sliders.
+ */
+static const unsigned int float_zero_to_one_lookup[] = {
+0x00000000, 0x3C23D70A, 0x3CA3D70A, 0x3CF5C28F, 0x3D23D70A, 0x3D4CCCCD,
+0x3D75C28F, 0x3D8F5C29, 0x3DA3D70A, 0x3DB851EC, 0x3DCCCCCD, 0x3DE147AE,
+0x3DF5C28F, 0x3E051EB8, 0x3E0F5C29, 0x3E19999A, 0x3E23D70A, 0x3E2E147B,
+0x3E3851EC, 0x3E428F5C, 0x3E4CCCCD, 0x3E570A3D, 0x3E6147AE, 0x3E6B851F,
+0x3E75C28F, 0x3E800000, 0x3E851EB8, 0x3E8A3D71, 0x3E8F5C29, 0x3E947AE1,
+0x3E99999A, 0x3E9EB852, 0x3EA3D70A, 0x3EA8F5C3, 0x3EAE147B, 0x3EB33333,
+0x3EB851EC, 0x3EBD70A4, 0x3EC28F5C, 0x3EC7AE14, 0x3ECCCCCD, 0x3ED1EB85,
+0x3ED70A3D, 0x3EDC28F6, 0x3EE147AE, 0x3EE66666, 0x3EEB851F, 0x3EF0A3D7,
+0x3EF5C28F, 0x3EFAE148, 0x3F000000, 0x3F028F5C, 0x3F051EB8, 0x3F07AE14,
+0x3F0A3D71, 0x3F0CCCCD, 0x3F0F5C29, 0x3F11EB85, 0x3F147AE1, 0x3F170A3D,
+0x3F19999A, 0x3F1C28F6, 0x3F1EB852, 0x3F2147AE, 0x3F23D70A, 0x3F266666,
+0x3F28F5C3, 0x3F2B851F, 0x3F2E147B, 0x3F30A3D7, 0x3F333333, 0x3F35C28F,
+0x3F3851EC, 0x3F3AE148, 0x3F3D70A4, 0x3F400000, 0x3F428F5C, 0x3F451EB8,
+0x3F47AE14, 0x3F4A3D71, 0x3F4CCCCD, 0x3F4F5C29, 0x3F51EB85, 0x3F547AE1,
+0x3F570A3D, 0x3F59999A, 0x3F5C28F6, 0x3F5EB852, 0x3F6147AE, 0x3F63D70A,
+0x3F666666, 0x3F68F5C3, 0x3F6B851F, 0x3F6E147B, 0x3F70A3D7, 0x3F733333,
+0x3F75C28F, 0x3F7851EC, 0x3F7AE148, 0x3F7D70A4, 0x3F800000
+};
+
+/*
+ * This table counts from float 10 to 1000, which is the range of the x-bass
+ * crossover slider in Windows.
+ */
+static const unsigned int float_xbass_xover_lookup[] = {
+0x41200000, 0x41A00000, 0x41F00000, 0x42200000, 0x42480000, 0x42700000,
+0x428C0000, 0x42A00000, 0x42B40000, 0x42C80000, 0x42DC0000, 0x42F00000,
+0x43020000, 0x430C0000, 0x43160000, 0x43200000, 0x432A0000, 0x43340000,
+0x433E0000, 0x43480000, 0x43520000, 0x435C0000, 0x43660000, 0x43700000,
+0x437A0000, 0x43820000, 0x43870000, 0x438C0000, 0x43910000, 0x43960000,
+0x439B0000, 0x43A00000, 0x43A50000, 0x43AA0000, 0x43AF0000, 0x43B40000,
+0x43B90000, 0x43BE0000, 0x43C30000, 0x43C80000, 0x43CD0000, 0x43D20000,
+0x43D70000, 0x43DC0000, 0x43E10000, 0x43E60000, 0x43EB0000, 0x43F00000,
+0x43F50000, 0x43FA0000, 0x43FF0000, 0x44020000, 0x44048000, 0x44070000,
+0x44098000, 0x440C0000, 0x440E8000, 0x44110000, 0x44138000, 0x44160000,
+0x44188000, 0x441B0000, 0x441D8000, 0x44200000, 0x44228000, 0x44250000,
+0x44278000, 0x442A0000, 0x442C8000, 0x442F0000, 0x44318000, 0x44340000,
+0x44368000, 0x44390000, 0x443B8000, 0x443E0000, 0x44408000, 0x44430000,
+0x44458000, 0x44480000, 0x444A8000, 0x444D0000, 0x444F8000, 0x44520000,
+0x44548000, 0x44570000, 0x44598000, 0x445C0000, 0x445E8000, 0x44610000,
+0x44638000, 0x44660000, 0x44688000, 0x446B0000, 0x446D8000, 0x44700000,
+0x44728000, 0x44750000, 0x44778000, 0x447A0000
+};
+
+/* The following are for tuning of products */
+#ifdef ENABLE_TUNING_CONTROLS
+
+static const unsigned int voice_focus_vals_lookup[] = {
+0x41A00000, 0x41A80000, 0x41B00000, 0x41B80000, 0x41C00000, 0x41C80000,
+0x41D00000, 0x41D80000, 0x41E00000, 0x41E80000, 0x41F00000, 0x41F80000,
+0x42000000, 0x42040000, 0x42080000, 0x420C0000, 0x42100000, 0x42140000,
+0x42180000, 0x421C0000, 0x42200000, 0x42240000, 0x42280000, 0x422C0000,
+0x42300000, 0x42340000, 0x42380000, 0x423C0000, 0x42400000, 0x42440000,
+0x42480000, 0x424C0000, 0x42500000, 0x42540000, 0x42580000, 0x425C0000,
+0x42600000, 0x42640000, 0x42680000, 0x426C0000, 0x42700000, 0x42740000,
+0x42780000, 0x427C0000, 0x42800000, 0x42820000, 0x42840000, 0x42860000,
+0x42880000, 0x428A0000, 0x428C0000, 0x428E0000, 0x42900000, 0x42920000,
+0x42940000, 0x42960000, 0x42980000, 0x429A0000, 0x429C0000, 0x429E0000,
+0x42A00000, 0x42A20000, 0x42A40000, 0x42A60000, 0x42A80000, 0x42AA0000,
+0x42AC0000, 0x42AE0000, 0x42B00000, 0x42B20000, 0x42B40000, 0x42B60000,
+0x42B80000, 0x42BA0000, 0x42BC0000, 0x42BE0000, 0x42C00000, 0x42C20000,
+0x42C40000, 0x42C60000, 0x42C80000, 0x42CA0000, 0x42CC0000, 0x42CE0000,
+0x42D00000, 0x42D20000, 0x42D40000, 0x42D60000, 0x42D80000, 0x42DA0000,
+0x42DC0000, 0x42DE0000, 0x42E00000, 0x42E20000, 0x42E40000, 0x42E60000,
+0x42E80000, 0x42EA0000, 0x42EC0000, 0x42EE0000, 0x42F00000, 0x42F20000,
+0x42F40000, 0x42F60000, 0x42F80000, 0x42FA0000, 0x42FC0000, 0x42FE0000,
+0x43000000, 0x43010000, 0x43020000, 0x43030000, 0x43040000, 0x43050000,
+0x43060000, 0x43070000, 0x43080000, 0x43090000, 0x430A0000, 0x430B0000,
+0x430C0000, 0x430D0000, 0x430E0000, 0x430F0000, 0x43100000, 0x43110000,
+0x43120000, 0x43130000, 0x43140000, 0x43150000, 0x43160000, 0x43170000,
+0x43180000, 0x43190000, 0x431A0000, 0x431B0000, 0x431C0000, 0x431D0000,
+0x431E0000, 0x431F0000, 0x43200000, 0x43210000, 0x43220000, 0x43230000,
+0x43240000, 0x43250000, 0x43260000, 0x43270000, 0x43280000, 0x43290000,
+0x432A0000, 0x432B0000, 0x432C0000, 0x432D0000, 0x432E0000, 0x432F0000,
+0x43300000, 0x43310000, 0x43320000, 0x43330000, 0x43340000
+};
+
+static const unsigned int mic_svm_vals_lookup[] = {
+0x00000000, 0x3C23D70A, 0x3CA3D70A, 0x3CF5C28F, 0x3D23D70A, 0x3D4CCCCD,
+0x3D75C28F, 0x3D8F5C29, 0x3DA3D70A, 0x3DB851EC, 0x3DCCCCCD, 0x3DE147AE,
+0x3DF5C28F, 0x3E051EB8, 0x3E0F5C29, 0x3E19999A, 0x3E23D70A, 0x3E2E147B,
+0x3E3851EC, 0x3E428F5C, 0x3E4CCCCD, 0x3E570A3D, 0x3E6147AE, 0x3E6B851F,
+0x3E75C28F, 0x3E800000, 0x3E851EB8, 0x3E8A3D71, 0x3E8F5C29, 0x3E947AE1,
+0x3E99999A, 0x3E9EB852, 0x3EA3D70A, 0x3EA8F5C3, 0x3EAE147B, 0x3EB33333,
+0x3EB851EC, 0x3EBD70A4, 0x3EC28F5C, 0x3EC7AE14, 0x3ECCCCCD, 0x3ED1EB85,
+0x3ED70A3D, 0x3EDC28F6, 0x3EE147AE, 0x3EE66666, 0x3EEB851F, 0x3EF0A3D7,
+0x3EF5C28F, 0x3EFAE148, 0x3F000000, 0x3F028F5C, 0x3F051EB8, 0x3F07AE14,
+0x3F0A3D71, 0x3F0CCCCD, 0x3F0F5C29, 0x3F11EB85, 0x3F147AE1, 0x3F170A3D,
+0x3F19999A, 0x3F1C28F6, 0x3F1EB852, 0x3F2147AE, 0x3F23D70A, 0x3F266666,
+0x3F28F5C3, 0x3F2B851F, 0x3F2E147B, 0x3F30A3D7, 0x3F333333, 0x3F35C28F,
+0x3F3851EC, 0x3F3AE148, 0x3F3D70A4, 0x3F400000, 0x3F428F5C, 0x3F451EB8,
+0x3F47AE14, 0x3F4A3D71, 0x3F4CCCCD, 0x3F4F5C29, 0x3F51EB85, 0x3F547AE1,
+0x3F570A3D, 0x3F59999A, 0x3F5C28F6, 0x3F5EB852, 0x3F6147AE, 0x3F63D70A,
+0x3F666666, 0x3F68F5C3, 0x3F6B851F, 0x3F6E147B, 0x3F70A3D7, 0x3F733333,
+0x3F75C28F, 0x3F7851EC, 0x3F7AE148, 0x3F7D70A4, 0x3F800000
+};
+
+static const unsigned int equalizer_vals_lookup[] = {
+0xC1C00000, 0xC1B80000, 0xC1B00000, 0xC1A80000, 0xC1A00000, 0xC1980000,
+0xC1900000, 0xC1880000, 0xC1800000, 0xC1700000, 0xC1600000, 0xC1500000,
+0xC1400000, 0xC1300000, 0xC1200000, 0xC1100000, 0xC1000000, 0xC0E00000,
+0xC0C00000, 0xC0A00000, 0xC0800000, 0xC0400000, 0xC0000000, 0xBF800000,
+0x00000000, 0x3F800000, 0x40000000, 0x40400000, 0x40800000, 0x40A00000,
+0x40C00000, 0x40E00000, 0x41000000, 0x41100000, 0x41200000, 0x41300000,
+0x41400000, 0x41500000, 0x41600000, 0x41700000, 0x41800000, 0x41880000,
+0x41900000, 0x41980000, 0x41A00000, 0x41A80000, 0x41B00000, 0x41B80000,
+0x41C00000
+};
+
+static int tuning_ctl_set(struct hda_codec *codec, hda_nid_t nid,
+                         const unsigned int *lookup, int idx)
+{
+       int i = 0;
+
+       for (i = 0; i < TUNING_CTLS_COUNT; i++)
+               if (nid == ca0132_tuning_ctls[i].nid)
+                       goto found;
+
+       return -EINVAL;
+found:
+       snd_hda_power_up(codec);
+       dspio_set_param(codec, ca0132_tuning_ctls[i].mid, 0x20,
+                       ca0132_tuning_ctls[i].req,
+                       &(lookup[idx]), sizeof(unsigned int));
+       snd_hda_power_down(codec);
+
+       return 1;
+}
+
+static int tuning_ctl_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx = nid - TUNING_CTL_START_NID;
+
+       *valp = spec->cur_ctl_vals[idx];
+       return 0;
+}
+
+static int voice_focus_ctl_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       int chs = get_amp_channels(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = chs == 3 ? 2 : 1;
+       uinfo->value.integer.min = 20;
+       uinfo->value.integer.max = 180;
+       uinfo->value.integer.step = 1;
+
+       return 0;
+}
+
+static int voice_focus_ctl_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx;
+
+       idx = nid - TUNING_CTL_START_NID;
+       /* any change? */
+       if (spec->cur_ctl_vals[idx] == *valp)
+               return 0;
+
+       spec->cur_ctl_vals[idx] = *valp;
+
+       idx = *valp - 20;
+       tuning_ctl_set(codec, nid, voice_focus_vals_lookup, idx);
+
+       return 1;
+}
+
+static int mic_svm_ctl_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       int chs = get_amp_channels(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = chs == 3 ? 2 : 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 100;
+       uinfo->value.integer.step = 1;
+
+       return 0;
+}
+
+static int mic_svm_ctl_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx;
+
+       idx = nid - TUNING_CTL_START_NID;
+       /* any change? */
+       if (spec->cur_ctl_vals[idx] == *valp)
+               return 0;
+
+       spec->cur_ctl_vals[idx] = *valp;
+
+       idx = *valp;
+       tuning_ctl_set(codec, nid, mic_svm_vals_lookup, idx);
+
+       return 0;
+}
+
+static int equalizer_ctl_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       int chs = get_amp_channels(kcontrol);
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = chs == 3 ? 2 : 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 48;
+       uinfo->value.integer.step = 1;
+
+       return 0;
+}
+
+static int equalizer_ctl_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx;
+
+       idx = nid - TUNING_CTL_START_NID;
+       /* any change? */
+       if (spec->cur_ctl_vals[idx] == *valp)
+               return 0;
+
+       spec->cur_ctl_vals[idx] = *valp;
+
+       idx = *valp;
+       tuning_ctl_set(codec, nid, equalizer_vals_lookup, idx);
+
+       return 1;
+}
+
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(voice_focus_db_scale, 2000, 100, 0);
+static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(eq_db_scale, -2400, 100, 0);
+
+static int add_tuning_control(struct hda_codec *codec,
+                               hda_nid_t pnid, hda_nid_t nid,
+                               const char *name, int dir)
+{
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       int type = dir ? HDA_INPUT : HDA_OUTPUT;
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
+
+       knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ;
+       knew.tlv.c = NULL;
+       knew.tlv.p = NULL;
+       switch (pnid) {
+       case VOICE_FOCUS:
+               knew.info = voice_focus_ctl_info;
+               knew.get = tuning_ctl_get;
+               knew.put = voice_focus_ctl_put;
+               knew.tlv.p = voice_focus_db_scale;
+               break;
+       case MIC_SVM:
+               knew.info = mic_svm_ctl_info;
+               knew.get = tuning_ctl_get;
+               knew.put = mic_svm_ctl_put;
+               break;
+       case EQUALIZER:
+               knew.info = equalizer_ctl_info;
+               knew.get = tuning_ctl_get;
+               knew.put = equalizer_ctl_put;
+               knew.tlv.p = eq_db_scale;
+               break;
+       default:
+               return 0;
+       }
+       knew.private_value =
+               HDA_COMPOSE_AMP_VAL(nid, 1, 0, type);
+       snprintf(namestr, sizeof(namestr), "%s %s Volume", name, dirstr[dir]);
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+static int add_tuning_ctls(struct hda_codec *codec)
+{
+       int i;
+       int err;
+
+       for (i = 0; i < TUNING_CTLS_COUNT; i++) {
+               err = add_tuning_control(codec,
+                                       ca0132_tuning_ctls[i].parent_nid,
+                                       ca0132_tuning_ctls[i].nid,
+                                       ca0132_tuning_ctls[i].name,
+                                       ca0132_tuning_ctls[i].direct);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static void ca0132_init_tuning_defaults(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int i;
+
+       /* Wedge Angle defaults to 30.  10 below is 30 - 20.  20 is min. */
+       spec->cur_ctl_vals[WEDGE_ANGLE - TUNING_CTL_START_NID] = 10;
+       /* SVM level defaults to 0.74. */
+       spec->cur_ctl_vals[SVM_LEVEL - TUNING_CTL_START_NID] = 74;
+
+       /* EQ defaults to 0dB. */
+       for (i = 2; i < TUNING_CTLS_COUNT; i++)
+               spec->cur_ctl_vals[i] = 24;
+}
+#endif /*ENABLE_TUNING_CONTROLS*/
+
+/*
+ * Select the active output.
+ * If autodetect is enabled, output will be selected based on jack detection.
+ * If jack inserted, headphone will be selected, else built-in speakers
+ * If autodetect is disabled, output will be selected based on selection.
+ */
+static int ca0132_select_out(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int pin_ctl;
+       int jack_present;
+       int auto_jack;
+       unsigned int tmp;
+       int err;
+
+       codec_dbg(codec, "ca0132_select_out\n");
+
+       snd_hda_power_up_pm(codec);
+
+       auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
+
+       if (auto_jack)
+               jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_hp);
+       else
+               jack_present =
+                       spec->vnode_lswitch[VNID_HP_SEL - VNODE_START_NID];
+
+       if (jack_present)
+               spec->cur_out_type = HEADPHONE_OUT;
+       else
+               spec->cur_out_type = SPEAKER_OUT;
+
+       if (spec->cur_out_type == SPEAKER_OUT) {
+               codec_dbg(codec, "ca0132_select_out speaker\n");
+               /*speaker out config*/
+               tmp = FLOAT_ONE;
+               err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
+               if (err < 0)
+                       goto exit;
+               /*enable speaker EQ*/
+               tmp = FLOAT_ONE;
+               err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp);
+               if (err < 0)
+                       goto exit;
+
+               /* Setup EAPD */
+               snd_hda_codec_write(codec, spec->out_pins[1], 0,
+                                   VENDOR_CHIPIO_EAPD_SEL_SET, 0x02);
+               snd_hda_codec_write(codec, spec->out_pins[0], 0,
+                                   AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+               snd_hda_codec_write(codec, spec->out_pins[0], 0,
+                                   VENDOR_CHIPIO_EAPD_SEL_SET, 0x00);
+               snd_hda_codec_write(codec, spec->out_pins[0], 0,
+                                   AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+
+               /* disable headphone node */
+               pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
+                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_set_pin_ctl(codec, spec->out_pins[1],
+                                   pin_ctl & ~PIN_HP);
+               /* enable speaker node */
+               pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_set_pin_ctl(codec, spec->out_pins[0],
+                                   pin_ctl | PIN_OUT);
+       } else {
+               codec_dbg(codec, "ca0132_select_out hp\n");
+               /*headphone out config*/
+               tmp = FLOAT_ZERO;
+               err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
+               if (err < 0)
+                       goto exit;
+               /*disable speaker EQ*/
+               tmp = FLOAT_ZERO;
+               err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp);
+               if (err < 0)
+                       goto exit;
+
+               /* Setup EAPD */
+               snd_hda_codec_write(codec, spec->out_pins[0], 0,
+                                   VENDOR_CHIPIO_EAPD_SEL_SET, 0x00);
+               snd_hda_codec_write(codec, spec->out_pins[0], 0,
+                                   AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+               snd_hda_codec_write(codec, spec->out_pins[1], 0,
+                                   VENDOR_CHIPIO_EAPD_SEL_SET, 0x02);
+               snd_hda_codec_write(codec, spec->out_pins[0], 0,
+                                   AC_VERB_SET_EAPD_BTLENABLE, 0x02);
+
+               /* disable speaker*/
+               pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
+                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_set_pin_ctl(codec, spec->out_pins[0],
+                                   pin_ctl & ~PIN_HP);
+               /* enable headphone*/
+               pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
+                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_set_pin_ctl(codec, spec->out_pins[1],
+                                   pin_ctl | PIN_HP);
+       }
+
+exit:
+       snd_hda_power_down_pm(codec);
+
+       return err < 0 ? err : 0;
+}
+
+static int ae5_headphone_gain_set(struct hda_codec *codec, long val);
+static int zxr_headphone_gain_set(struct hda_codec *codec, long val);
+static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
+
+static void ae5_mmio_select_out(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       const struct ae_ca0113_output_set *out_cmds;
+       unsigned int i;
+
+       if (ca0132_quirk(spec) == QUIRK_AE5)
+               out_cmds = &ae5_ca0113_output_presets;
+       else
+               out_cmds = &ae7_ca0113_output_presets;
+
+       for (i = 0; i < AE_CA0113_OUT_SET_COMMANDS; i++)
+               ca0113_mmio_command_set(codec, out_cmds->group[i],
+                               out_cmds->target[i],
+                               out_cmds->vals[spec->cur_out_type][i]);
+}
+
+static int ca0132_alt_set_full_range_speaker(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int quirk = ca0132_quirk(spec);
+       unsigned int tmp;
+       int err;
+
+       /* 2.0/4.0 setup has no LFE channel, so setting full-range does nothing. */
+       if (spec->channel_cfg_val == SPEAKER_CHANNELS_4_0
+                       || spec->channel_cfg_val == SPEAKER_CHANNELS_2_0)
+               return 0;
+
+       /* Set front L/R full range. Zero for full-range, one for redirection. */
+       tmp = spec->speaker_range_val[0] ? FLOAT_ZERO : FLOAT_ONE;
+       err = dspio_set_uint_param(codec, 0x96,
+                       SPEAKER_FULL_RANGE_FRONT_L_R, tmp);
+       if (err < 0)
+               return err;
+
+       /* When setting full-range rear, both rear and center/lfe are set. */
+       tmp = spec->speaker_range_val[1] ? FLOAT_ZERO : FLOAT_ONE;
+       err = dspio_set_uint_param(codec, 0x96,
+                       SPEAKER_FULL_RANGE_CENTER_LFE, tmp);
+       if (err < 0)
+               return err;
+
+       err = dspio_set_uint_param(codec, 0x96,
+                       SPEAKER_FULL_RANGE_REAR_L_R, tmp);
+       if (err < 0)
+               return err;
+
+       /*
+        * Only the AE series cards set this value when setting full-range,
+        * and it's always 1.0f.
+        */
+       if (quirk == QUIRK_AE5 || quirk == QUIRK_AE7) {
+               err = dspio_set_uint_param(codec, 0x96,
+                               SPEAKER_FULL_RANGE_SURROUND_L_R, FLOAT_ONE);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int ca0132_alt_surround_set_bass_redirection(struct hda_codec *codec,
+               bool val)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+       int err;
+
+       if (val && spec->channel_cfg_val != SPEAKER_CHANNELS_4_0 &&
+                       spec->channel_cfg_val != SPEAKER_CHANNELS_2_0)
+               tmp = FLOAT_ONE;
+       else
+               tmp = FLOAT_ZERO;
+
+       err = dspio_set_uint_param(codec, 0x96, SPEAKER_BASS_REDIRECT, tmp);
+       if (err < 0)
+               return err;
+
+       /* If it is enabled, make sure to set the crossover frequency. */
+       if (tmp) {
+               tmp = float_xbass_xover_lookup[spec->xbass_xover_freq];
+               err = dspio_set_uint_param(codec, 0x96,
+                               SPEAKER_BASS_REDIRECT_XOVER_FREQ, tmp);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/*
+ * These are the commands needed to setup output on each of the different card
+ * types.
+ */
+static void ca0132_alt_select_out_get_quirk_data(struct hda_codec *codec,
+               const struct ca0132_alt_out_set_quirk_data **quirk_data)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int quirk = ca0132_quirk(spec);
+       unsigned int i;
+
+       *quirk_data = NULL;
+       for (i = 0; i < ARRAY_SIZE(quirk_out_set_data); i++) {
+               if (quirk_out_set_data[i].quirk_id == quirk) {
+                       *quirk_data = &quirk_out_set_data[i];
+                       return;
+               }
+       }
+}
+
+static int ca0132_alt_select_out_quirk_set(struct hda_codec *codec)
+{
+       const struct ca0132_alt_out_set_quirk_data *quirk_data;
+       const struct ca0132_alt_out_set_info *out_info;
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int i, gpio_data;
+       int err;
+
+       ca0132_alt_select_out_get_quirk_data(codec, &quirk_data);
+       if (!quirk_data)
+               return 0;
+
+       out_info = &quirk_data->out_set_info[spec->cur_out_type];
+       if (quirk_data->is_ae_series)
+               ae5_mmio_select_out(codec);
+
+       if (out_info->has_hda_gpio) {
+               gpio_data = snd_hda_codec_read(codec, codec->core.afg, 0,
+                               AC_VERB_GET_GPIO_DATA, 0);
+
+               if (out_info->hda_gpio_set)
+                       gpio_data |= (1 << out_info->hda_gpio_pin);
+               else
+                       gpio_data &= ~(1 << out_info->hda_gpio_pin);
+
+               snd_hda_codec_write(codec, codec->core.afg, 0,
+                                   AC_VERB_SET_GPIO_DATA, gpio_data);
+       }
+
+       if (out_info->mmio_gpio_count) {
+               for (i = 0; i < out_info->mmio_gpio_count; i++) {
+                       ca0113_mmio_gpio_set(codec, out_info->mmio_gpio_pin[i],
+                                       out_info->mmio_gpio_set[i]);
+               }
+       }
+
+       if (out_info->scp_cmds_count) {
+               for (i = 0; i < out_info->scp_cmds_count; i++) {
+                       err = dspio_set_uint_param(codec,
+                                       out_info->scp_cmd_mid[i],
+                                       out_info->scp_cmd_req[i],
+                                       out_info->scp_cmd_val[i]);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       chipio_set_control_param(codec, 0x0d, out_info->dac2port);
+
+       if (out_info->has_chipio_write) {
+               chipio_write(codec, out_info->chipio_write_addr,
+                               out_info->chipio_write_data);
+       }
+
+       if (quirk_data->has_headphone_gain) {
+               if (spec->cur_out_type != HEADPHONE_OUT) {
+                       if (quirk_data->is_ae_series)
+                               ae5_headphone_gain_set(codec, 2);
+                       else
+                               zxr_headphone_gain_set(codec, 0);
+               } else {
+                       if (quirk_data->is_ae_series)
+                               ae5_headphone_gain_set(codec,
+                                               spec->ae5_headphone_gain_val);
+                       else
+                               zxr_headphone_gain_set(codec,
+                                               spec->zxr_gain_set);
+               }
+       }
+
+       return 0;
+}
+
+static void ca0132_set_out_node_pincfg(struct hda_codec *codec, hda_nid_t nid,
+               bool out_enable, bool hp_enable)
+{
+       unsigned int pin_ctl;
+
+       pin_ctl = snd_hda_codec_read(codec, nid, 0,
+                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+       pin_ctl = hp_enable ? pin_ctl | PIN_HP_AMP : pin_ctl & ~PIN_HP_AMP;
+       pin_ctl = out_enable ? pin_ctl | PIN_OUT : pin_ctl & ~PIN_OUT;
+       snd_hda_set_pin_ctl(codec, nid, pin_ctl);
+}
+
+/*
+ * This function behaves similarly to the ca0132_select_out funciton above,
+ * except with a few differences. It adds the ability to select the current
+ * output with an enumerated control "output source" if the auto detect
+ * mute switch is set to off. If the auto detect mute switch is enabled, it
+ * will detect either headphone or lineout(SPEAKER_OUT) from jack detection.
+ * It also adds the ability to auto-detect the front headphone port.
+ */
+static int ca0132_alt_select_out(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp, outfx_set;
+       int jack_present;
+       int auto_jack;
+       int err;
+       /* Default Headphone is rear headphone */
+       hda_nid_t headphone_nid = spec->out_pins[1];
+
+       codec_dbg(codec, "%s\n", __func__);
+
+       snd_hda_power_up_pm(codec);
+
+       auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
+
+       /*
+        * If headphone rear or front is plugged in, set to headphone.
+        * If neither is plugged in, set to rear line out. Only if
+        * hp/speaker auto detect is enabled.
+        */
+       if (auto_jack) {
+               jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_hp) ||
+                          snd_hda_jack_detect(codec, spec->unsol_tag_front_hp);
+
+               if (jack_present)
+                       spec->cur_out_type = HEADPHONE_OUT;
+               else
+                       spec->cur_out_type = SPEAKER_OUT;
+       } else
+               spec->cur_out_type = spec->out_enum_val;
+
+       outfx_set = spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID];
+
+       /* Begin DSP output switch, mute DSP volume. */
+       err = dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_MUTE, FLOAT_ONE);
+       if (err < 0)
+               goto exit;
+
+       if (ca0132_alt_select_out_quirk_set(codec) < 0)
+               goto exit;
+
+       switch (spec->cur_out_type) {
+       case SPEAKER_OUT:
+               codec_dbg(codec, "%s speaker\n", __func__);
+
+               /* Enable EAPD */
+               snd_hda_codec_write(codec, spec->out_pins[0], 0,
+                       AC_VERB_SET_EAPD_BTLENABLE, 0x01);
+
+               /* Disable headphone node. */
+               ca0132_set_out_node_pincfg(codec, spec->out_pins[1], 0, 0);
+               /* Set front L-R to output. */
+               ca0132_set_out_node_pincfg(codec, spec->out_pins[0], 1, 0);
+               /* Set Center/LFE to output. */
+               ca0132_set_out_node_pincfg(codec, spec->out_pins[2], 1, 0);
+               /* Set rear surround to output. */
+               ca0132_set_out_node_pincfg(codec, spec->out_pins[3], 1, 0);
+
+               /*
+                * Without PlayEnhancement being enabled, if we've got a 2.0
+                * setup, set it to floating point eight to disable any DSP
+                * processing effects.
+                */
+               if (!outfx_set && spec->channel_cfg_val == SPEAKER_CHANNELS_2_0)
+                       tmp = FLOAT_EIGHT;
+               else
+                       tmp = speaker_channel_cfgs[spec->channel_cfg_val].val;
+
+               err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
+               if (err < 0)
+                       goto exit;
+
+               break;
+       case HEADPHONE_OUT:
+               codec_dbg(codec, "%s hp\n", __func__);
+               snd_hda_codec_write(codec, spec->out_pins[0], 0,
+                       AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+
+               /* Disable all speaker nodes. */
+               ca0132_set_out_node_pincfg(codec, spec->out_pins[0], 0, 0);
+               ca0132_set_out_node_pincfg(codec, spec->out_pins[2], 0, 0);
+               ca0132_set_out_node_pincfg(codec, spec->out_pins[3], 0, 0);
+
+               /* enable headphone, either front or rear */
+               if (snd_hda_jack_detect(codec, spec->unsol_tag_front_hp))
+                       headphone_nid = spec->out_pins[2];
+               else if (snd_hda_jack_detect(codec, spec->unsol_tag_hp))
+                       headphone_nid = spec->out_pins[1];
+
+               ca0132_set_out_node_pincfg(codec, headphone_nid, 1, 1);
+
+               if (outfx_set)
+                       err = dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE);
+               else
+                       err = dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ZERO);
+
+               if (err < 0)
+                       goto exit;
+               break;
+       }
+       /*
+        * If output effects are enabled, set the X-Bass effect value again to
+        * make sure that it's properly enabled/disabled for speaker
+        * configurations with an LFE channel.
+        */
+       if (outfx_set)
+               ca0132_effects_set(codec, X_BASS,
+                       spec->effects_switch[X_BASS - EFFECT_START_NID]);
+
+       /* Set speaker EQ bypass attenuation to 0. */
+       err = dspio_set_uint_param(codec, 0x8f, 0x01, FLOAT_ZERO);
+       if (err < 0)
+               goto exit;
+
+       /*
+        * Although unused on all cards but the AE series, this is always set
+        * to zero when setting the output.
+        */
+       err = dspio_set_uint_param(codec, 0x96,
+                       SPEAKER_TUNING_USE_SPEAKER_EQ, FLOAT_ZERO);
+       if (err < 0)
+               goto exit;
+
+       if (spec->cur_out_type == SPEAKER_OUT)
+               err = ca0132_alt_surround_set_bass_redirection(codec,
+                               spec->bass_redirection_val);
+       else
+               err = ca0132_alt_surround_set_bass_redirection(codec, 0);
+
+       /* Unmute DSP now that we're done with output selection. */
+       err = dspio_set_uint_param(codec, 0x96,
+                       SPEAKER_TUNING_MUTE, FLOAT_ZERO);
+       if (err < 0)
+               goto exit;
+
+       if (spec->cur_out_type == SPEAKER_OUT) {
+               err = ca0132_alt_set_full_range_speaker(codec);
+               if (err < 0)
+                       goto exit;
+       }
+
+exit:
+       snd_hda_power_down_pm(codec);
+
+       return err < 0 ? err : 0;
+}
+
+static void ca0132_unsol_hp_delayed(struct work_struct *work)
+{
+       struct ca0132_spec *spec = container_of(
+               to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
+       struct hda_jack_tbl *jack;
+
+       if (ca0132_use_alt_functions(spec))
+               ca0132_alt_select_out(spec->codec);
+       else
+               ca0132_select_out(spec->codec);
+
+       jack = snd_hda_jack_tbl_get(spec->codec, spec->unsol_tag_hp);
+       if (jack) {
+               jack->block_report = 0;
+               snd_hda_jack_report_sync(spec->codec);
+       }
+}
+
+static void ca0132_set_dmic(struct hda_codec *codec, int enable);
+static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
+static void resume_mic1(struct hda_codec *codec, unsigned int oldval);
+static int stop_mic1(struct hda_codec *codec);
+static int ca0132_cvoice_switch_set(struct hda_codec *codec);
+static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val);
+
+/*
+ * Select the active VIP source
+ */
+static int ca0132_set_vipsource(struct hda_codec *codec, int val)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return 0;
+
+       /* if CrystalVoice if off, vipsource should be 0 */
+       if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ||
+           (val == 0)) {
+               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
+               if (spec->cur_mic_type == DIGITAL_MIC)
+                       tmp = FLOAT_TWO;
+               else
+                       tmp = FLOAT_ONE;
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+               tmp = FLOAT_ZERO;
+               dspio_set_uint_param(codec, 0x80, 0x05, tmp);
+       } else {
+               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000);
+               if (spec->cur_mic_type == DIGITAL_MIC)
+                       tmp = FLOAT_TWO;
+               else
+                       tmp = FLOAT_ONE;
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+               tmp = FLOAT_ONE;
+               dspio_set_uint_param(codec, 0x80, 0x05, tmp);
+               msleep(20);
+               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, val);
+       }
+
+       return 1;
+}
+
+static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return 0;
+
+       codec_dbg(codec, "%s\n", __func__);
+
+       chipio_set_stream_control(codec, 0x03, 0);
+       chipio_set_stream_control(codec, 0x04, 0);
+
+       /* if CrystalVoice is off, vipsource should be 0 */
+       if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ||
+           (val == 0) || spec->in_enum_val == REAR_LINE_IN) {
+               codec_dbg(codec, "%s: off.", __func__);
+               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0);
+
+               tmp = FLOAT_ZERO;
+               dspio_set_uint_param(codec, 0x80, 0x05, tmp);
+
+               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
+                       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+
+
+               if (spec->in_enum_val == REAR_LINE_IN)
+                       tmp = FLOAT_ZERO;
+               else {
+                       if (ca0132_quirk(spec) == QUIRK_SBZ)
+                               tmp = FLOAT_THREE;
+                       else
+                               tmp = FLOAT_ONE;
+               }
+
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+       } else {
+               codec_dbg(codec, "%s: on.", __func__);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000);
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
+                       chipio_set_conn_rate(codec, 0x0F, SR_16_000);
+
+               if (spec->effects_switch[VOICE_FOCUS - EFFECT_START_NID])
+                       tmp = FLOAT_TWO;
+               else
+                       tmp = FLOAT_ONE;
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+               tmp = FLOAT_ONE;
+               dspio_set_uint_param(codec, 0x80, 0x05, tmp);
+
+               msleep(20);
+               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, val);
+       }
+
+       chipio_set_stream_control(codec, 0x03, 1);
+       chipio_set_stream_control(codec, 0x04, 1);
+
+       return 1;
+}
+
+/*
+ * Select the active microphone.
+ * If autodetect is enabled, mic will be selected based on jack detection.
+ * If jack inserted, ext.mic will be selected, else built-in mic
+ * If autodetect is disabled, mic will be selected based on selection.
+ */
+static int ca0132_select_mic(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int jack_present;
+       int auto_jack;
+
+       codec_dbg(codec, "ca0132_select_mic\n");
+
+       snd_hda_power_up_pm(codec);
+
+       auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID];
+
+       if (auto_jack)
+               jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_amic1);
+       else
+               jack_present =
+                       spec->vnode_lswitch[VNID_AMIC1_SEL - VNODE_START_NID];
+
+       if (jack_present)
+               spec->cur_mic_type = LINE_MIC_IN;
+       else
+               spec->cur_mic_type = DIGITAL_MIC;
+
+       if (spec->cur_mic_type == DIGITAL_MIC) {
+               /* enable digital Mic */
+               chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_32_000);
+               ca0132_set_dmic(codec, 1);
+               ca0132_mic_boost_set(codec, 0);
+               /* set voice focus */
+               ca0132_effects_set(codec, VOICE_FOCUS,
+                                  spec->effects_switch
+                                  [VOICE_FOCUS - EFFECT_START_NID]);
+       } else {
+               /* disable digital Mic */
+               chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_96_000);
+               ca0132_set_dmic(codec, 0);
+               ca0132_mic_boost_set(codec, spec->cur_mic_boost);
+               /* disable voice focus */
+               ca0132_effects_set(codec, VOICE_FOCUS, 0);
+       }
+
+       snd_hda_power_down_pm(codec);
+
+       return 0;
+}
+
+/*
+ * Select the active input.
+ * Mic detection isn't used, because it's kind of pointless on the SBZ.
+ * The front mic has no jack-detection, so the only way to switch to it
+ * is to do it manually in alsamixer.
+ */
+static int ca0132_alt_select_in(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+
+       codec_dbg(codec, "%s\n", __func__);
+
+       snd_hda_power_up_pm(codec);
+
+       chipio_set_stream_control(codec, 0x03, 0);
+       chipio_set_stream_control(codec, 0x04, 0);
+
+       spec->cur_mic_type = spec->in_enum_val;
+
+       switch (spec->cur_mic_type) {
+       case REAR_MIC:
+               switch (ca0132_quirk(spec)) {
+               case QUIRK_SBZ:
+               case QUIRK_R3D:
+                       ca0113_mmio_gpio_set(codec, 0, false);
+                       tmp = FLOAT_THREE;
+                       break;
+               case QUIRK_ZXR:
+                       tmp = FLOAT_THREE;
+                       break;
+               case QUIRK_R3DI:
+                       r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
+                       tmp = FLOAT_ONE;
+                       break;
+               case QUIRK_AE5:
+                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
+                       tmp = FLOAT_THREE;
+                       break;
+               case QUIRK_AE7:
+                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
+                       tmp = FLOAT_THREE;
+                       chipio_set_conn_rate(codec, MEM_CONNID_MICIN2,
+                                       SR_96_000);
+                       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2,
+                                       SR_96_000);
+                       dspio_set_uint_param(codec, 0x80, 0x01, FLOAT_ZERO);
+                       break;
+               default:
+                       tmp = FLOAT_ONE;
+                       break;
+               }
+
+               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
+                       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+               chipio_set_stream_control(codec, 0x03, 1);
+               chipio_set_stream_control(codec, 0x04, 1);
+               switch (ca0132_quirk(spec)) {
+               case QUIRK_SBZ:
+                       chipio_write(codec, 0x18B098, 0x0000000C);
+                       chipio_write(codec, 0x18B09C, 0x0000000C);
+                       break;
+               case QUIRK_ZXR:
+                       chipio_write(codec, 0x18B098, 0x0000000C);
+                       chipio_write(codec, 0x18B09C, 0x000000CC);
+                       break;
+               case QUIRK_AE5:
+                       chipio_write(codec, 0x18B098, 0x0000000C);
+                       chipio_write(codec, 0x18B09C, 0x0000004C);
+                       break;
+               default:
+                       break;
+               }
+               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
+               break;
+       case REAR_LINE_IN:
+               ca0132_mic_boost_set(codec, 0);
+               switch (ca0132_quirk(spec)) {
+               case QUIRK_SBZ:
+               case QUIRK_R3D:
+                       ca0113_mmio_gpio_set(codec, 0, false);
+                       break;
+               case QUIRK_R3DI:
+                       r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
+                       break;
+               case QUIRK_AE5:
+                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
+                       break;
+               case QUIRK_AE7:
+                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x3f);
+                       chipio_set_conn_rate(codec, MEM_CONNID_MICIN2,
+                                       SR_96_000);
+                       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2,
+                                       SR_96_000);
+                       dspio_set_uint_param(codec, 0x80, 0x01, FLOAT_ZERO);
+                       break;
+               default:
+                       break;
+               }
+
+               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
+                       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+
+               if (ca0132_quirk(spec) == QUIRK_AE7)
+                       tmp = FLOAT_THREE;
+               else
+                       tmp = FLOAT_ZERO;
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+               switch (ca0132_quirk(spec)) {
+               case QUIRK_SBZ:
+               case QUIRK_AE5:
+                       chipio_write(codec, 0x18B098, 0x00000000);
+                       chipio_write(codec, 0x18B09C, 0x00000000);
+                       break;
+               default:
+                       break;
+               }
+               chipio_set_stream_control(codec, 0x03, 1);
+               chipio_set_stream_control(codec, 0x04, 1);
+               break;
+       case FRONT_MIC:
+               switch (ca0132_quirk(spec)) {
+               case QUIRK_SBZ:
+               case QUIRK_R3D:
+                       ca0113_mmio_gpio_set(codec, 0, true);
+                       ca0113_mmio_gpio_set(codec, 5, false);
+                       tmp = FLOAT_THREE;
+                       break;
+               case QUIRK_R3DI:
+                       r3di_gpio_mic_set(codec, R3DI_FRONT_MIC);
+                       tmp = FLOAT_ONE;
+                       break;
+               case QUIRK_AE5:
+                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x3f);
+                       tmp = FLOAT_THREE;
+                       break;
+               default:
+                       tmp = FLOAT_ONE;
+                       break;
+               }
+
+               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
+               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
+               if (ca0132_quirk(spec) == QUIRK_R3DI)
+                       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+               chipio_set_stream_control(codec, 0x03, 1);
+               chipio_set_stream_control(codec, 0x04, 1);
+
+               switch (ca0132_quirk(spec)) {
+               case QUIRK_SBZ:
+                       chipio_write(codec, 0x18B098, 0x0000000C);
+                       chipio_write(codec, 0x18B09C, 0x000000CC);
+                       break;
+               case QUIRK_AE5:
+                       chipio_write(codec, 0x18B098, 0x0000000C);
+                       chipio_write(codec, 0x18B09C, 0x0000004C);
+                       break;
+               default:
+                       break;
+               }
+               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
+               break;
+       }
+       ca0132_cvoice_switch_set(codec);
+
+       snd_hda_power_down_pm(codec);
+       return 0;
+}
+
+/*
+ * Check if VNODE settings take effect immediately.
+ */
+static bool ca0132_is_vnode_effective(struct hda_codec *codec,
+                                    hda_nid_t vnid,
+                                    hda_nid_t *shared_nid)
+{
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid;
+
+       switch (vnid) {
+       case VNID_SPK:
+               nid = spec->shared_out_nid;
+               break;
+       case VNID_MIC:
+               nid = spec->shared_mic_nid;
+               break;
+       default:
+               return false;
+       }
+
+       if (shared_nid)
+               *shared_nid = nid;
+
+       return true;
+}
+
+/*
+* The following functions are control change helpers.
+* They return 0 if no changed.  Return 1 if changed.
+*/
+static int ca0132_voicefx_set(struct hda_codec *codec, int enable)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+
+       /* based on CrystalVoice state to enable VoiceFX. */
+       if (enable) {
+               tmp = spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ?
+                       FLOAT_ONE : FLOAT_ZERO;
+       } else {
+               tmp = FLOAT_ZERO;
+       }
+
+       dspio_set_uint_param(codec, ca0132_voicefx.mid,
+                            ca0132_voicefx.reqs[0], tmp);
+
+       return 1;
+}
+
+/*
+ * Set the effects parameters
+ */
+static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int on, tmp, channel_cfg;
+       int num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
+       int err = 0;
+       int idx = nid - EFFECT_START_NID;
+
+       if ((idx < 0) || (idx >= num_fx))
+               return 0; /* no changed */
+
+       /* for out effect, qualify with PE */
+       if ((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) {
+               /* if PE if off, turn off out effects. */
+               if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
+                       val = 0;
+               if (spec->cur_out_type == SPEAKER_OUT && nid == X_BASS) {
+                       channel_cfg = spec->channel_cfg_val;
+                       if (channel_cfg != SPEAKER_CHANNELS_2_0 &&
+                                       channel_cfg != SPEAKER_CHANNELS_4_0)
+                               val = 0;
+               }
+       }
+
+       /* for in effect, qualify with CrystalVoice */
+       if ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID)) {
+               /* if CrystalVoice if off, turn off in effects. */
+               if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID])
+                       val = 0;
+
+               /* Voice Focus applies to 2-ch Mic, Digital Mic */
+               if ((nid == VOICE_FOCUS) && (spec->cur_mic_type != DIGITAL_MIC))
+                       val = 0;
+
+               /* If Voice Focus on SBZ, set to two channel. */
+               if ((nid == VOICE_FOCUS) && ca0132_use_pci_mmio(spec)
+                               && (spec->cur_mic_type != REAR_LINE_IN)) {
+                       if (spec->effects_switch[CRYSTAL_VOICE -
+                                                EFFECT_START_NID]) {
+
+                               if (spec->effects_switch[VOICE_FOCUS -
+                                                        EFFECT_START_NID]) {
+                                       tmp = FLOAT_TWO;
+                                       val = 1;
+                               } else
+                                       tmp = FLOAT_ONE;
+
+                               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+                       }
+               }
+               /*
+                * For SBZ noise reduction, there's an extra command
+                * to module ID 0x47. No clue why.
+                */
+               if ((nid == NOISE_REDUCTION) && ca0132_use_pci_mmio(spec)
+                               && (spec->cur_mic_type != REAR_LINE_IN)) {
+                       if (spec->effects_switch[CRYSTAL_VOICE -
+                                                EFFECT_START_NID]) {
+                               if (spec->effects_switch[NOISE_REDUCTION -
+                                                        EFFECT_START_NID])
+                                       tmp = FLOAT_ONE;
+                               else
+                                       tmp = FLOAT_ZERO;
+                       } else
+                               tmp = FLOAT_ZERO;
+
+                       dspio_set_uint_param(codec, 0x47, 0x00, tmp);
+               }
+
+               /* If rear line in disable effects. */
+               if (ca0132_use_alt_functions(spec) &&
+                               spec->in_enum_val == REAR_LINE_IN)
+                       val = 0;
+       }
+
+       codec_dbg(codec, "ca0132_effect_set: nid=0x%x, val=%ld\n",
+                   nid, val);
+
+       on = (val == 0) ? FLOAT_ZERO : FLOAT_ONE;
+       err = dspio_set_uint_param(codec, ca0132_effects[idx].mid,
+                                  ca0132_effects[idx].reqs[0], on);
+
+       if (err < 0)
+               return 0; /* no changed */
+
+       return 1;
+}
+
+/*
+ * Turn on/off Playback Enhancements
+ */
+static int ca0132_pe_switch_set(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid;
+       int i, ret = 0;
+
+       codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n",
+                   spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]);
+
+       if (ca0132_use_alt_functions(spec))
+               ca0132_alt_select_out(codec);
+
+       i = OUT_EFFECT_START_NID - EFFECT_START_NID;
+       nid = OUT_EFFECT_START_NID;
+       /* PE affects all out effects */
+       for (; nid < OUT_EFFECT_END_NID; nid++, i++)
+               ret |= ca0132_effects_set(codec, nid, spec->effects_switch[i]);
+
+       return ret;
+}
+
+/* Check if Mic1 is streaming, if so, stop streaming */
+static int stop_mic1(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int oldval = snd_hda_codec_read(codec, spec->adcs[0], 0,
+                                                AC_VERB_GET_CONV, 0);
+       if (oldval != 0)
+               snd_hda_codec_write(codec, spec->adcs[0], 0,
+                                   AC_VERB_SET_CHANNEL_STREAMID,
+                                   0);
+       return oldval;
+}
+
+/* Resume Mic1 streaming if it was stopped. */
+static void resume_mic1(struct hda_codec *codec, unsigned int oldval)
+{
+       struct ca0132_spec *spec = codec->spec;
+       /* Restore the previous stream and channel */
+       if (oldval != 0)
+               snd_hda_codec_write(codec, spec->adcs[0], 0,
+                                   AC_VERB_SET_CHANNEL_STREAMID,
+                                   oldval);
+}
+
+/*
+ * Turn on/off CrystalVoice
+ */
+static int ca0132_cvoice_switch_set(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid;
+       int i, ret = 0;
+       unsigned int oldval;
+
+       codec_dbg(codec, "ca0132_cvoice_switch_set: val=%ld\n",
+                   spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]);
+
+       i = IN_EFFECT_START_NID - EFFECT_START_NID;
+       nid = IN_EFFECT_START_NID;
+       /* CrystalVoice affects all in effects */
+       for (; nid < IN_EFFECT_END_NID; nid++, i++)
+               ret |= ca0132_effects_set(codec, nid, spec->effects_switch[i]);
+
+       /* including VoiceFX */
+       ret |= ca0132_voicefx_set(codec, (spec->voicefx_val ? 1 : 0));
+
+       /* set correct vipsource */
+       oldval = stop_mic1(codec);
+       if (ca0132_use_alt_functions(spec))
+               ret |= ca0132_alt_set_vipsource(codec, 1);
+       else
+               ret |= ca0132_set_vipsource(codec, 1);
+       resume_mic1(codec, oldval);
+       return ret;
+}
+
+static int ca0132_mic_boost_set(struct hda_codec *codec, long val)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int ret = 0;
+
+       if (val) /* on */
+               ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
+                                       HDA_INPUT, 0, HDA_AMP_VOLMASK, 3);
+       else /* off */
+               ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
+                                       HDA_INPUT, 0, HDA_AMP_VOLMASK, 0);
+
+       return ret;
+}
+
+static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int ret = 0;
+
+       ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
+                               HDA_INPUT, 0, HDA_AMP_VOLMASK, val);
+       return ret;
+}
+
+static int ae5_headphone_gain_set(struct hda_codec *codec, long val)
+{
+       unsigned int i;
+
+       for (i = 0; i < 4; i++)
+               ca0113_mmio_command_set(codec, 0x48, 0x11 + i,
+                               ae5_headphone_gain_presets[val].vals[i]);
+       return 0;
+}
+
+/*
+ * gpio pin 1 is a relay that switches on/off, apparently setting the headphone
+ * amplifier to handle a 600 ohm load.
+ */
+static int zxr_headphone_gain_set(struct hda_codec *codec, long val)
+{
+       ca0113_mmio_gpio_set(codec, 1, val);
+
+       return 0;
+}
+
+static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       hda_nid_t shared_nid = 0;
+       bool effective;
+       int ret = 0;
+       struct ca0132_spec *spec = codec->spec;
+       int auto_jack;
+
+       if (nid == VNID_HP_SEL) {
+               auto_jack =
+                       spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
+               if (!auto_jack) {
+                       if (ca0132_use_alt_functions(spec))
+                               ca0132_alt_select_out(codec);
+                       else
+                               ca0132_select_out(codec);
+               }
+               return 1;
+       }
+
+       if (nid == VNID_AMIC1_SEL) {
+               auto_jack =
+                       spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID];
+               if (!auto_jack)
+                       ca0132_select_mic(codec);
+               return 1;
+       }
+
+       if (nid == VNID_HP_ASEL) {
+               if (ca0132_use_alt_functions(spec))
+                       ca0132_alt_select_out(codec);
+               else
+                       ca0132_select_out(codec);
+               return 1;
+       }
+
+       if (nid == VNID_AMIC1_ASEL) {
+               ca0132_select_mic(codec);
+               return 1;
+       }
+
+       /* if effective conditions, then update hw immediately. */
+       effective = ca0132_is_vnode_effective(codec, nid, &shared_nid);
+       if (effective) {
+               int dir = get_amp_direction(kcontrol);
+               int ch = get_amp_channels(kcontrol);
+               unsigned long pval;
+
+               mutex_lock(&codec->control_mutex);
+               pval = kcontrol->private_value;
+               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch,
+                                                               0, dir);
+               ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+               kcontrol->private_value = pval;
+               mutex_unlock(&codec->control_mutex);
+       }
+
+       return ret;
+}
+/* End of control change helpers. */
+
+static void ca0132_alt_bass_redirection_xover_set(struct hda_codec *codec,
+               long idx)
+{
+       snd_hda_power_up(codec);
+
+       dspio_set_param(codec, 0x96, 0x20, SPEAKER_BASS_REDIRECT_XOVER_FREQ,
+                       &(float_xbass_xover_lookup[idx]), sizeof(unsigned int));
+
+       snd_hda_power_down(codec);
+}
+
+/*
+ * Below I've added controls to mess with the effect levels, I've only enabled
+ * them on the Sound Blaster Z, but they would probably also work on the
+ * Chromebook. I figured they were probably tuned specifically for it, and left
+ * out for a reason.
+ */
+
+/* Sets DSP effect level from the sliders above the controls */
+
+static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid,
+                         const unsigned int *lookup, int idx)
+{
+       int i = 0;
+       unsigned int y;
+       /*
+        * For X_BASS, req 2 is actually crossover freq instead of
+        * effect level
+        */
+       if (nid == X_BASS)
+               y = 2;
+       else
+               y = 1;
+
+       snd_hda_power_up(codec);
+       if (nid == XBASS_XOVER) {
+               for (i = 0; i < OUT_EFFECTS_COUNT; i++)
+                       if (ca0132_effects[i].nid == X_BASS)
+                               break;
+
+               dspio_set_param(codec, ca0132_effects[i].mid, 0x20,
+                               ca0132_effects[i].reqs[1],
+                               &(lookup[idx - 1]), sizeof(unsigned int));
+       } else {
+               /* Find the actual effect structure */
+               for (i = 0; i < OUT_EFFECTS_COUNT; i++)
+                       if (nid == ca0132_effects[i].nid)
+                               break;
+
+               dspio_set_param(codec, ca0132_effects[i].mid, 0x20,
+                               ca0132_effects[i].reqs[y],
+                               &(lookup[idx]), sizeof(unsigned int));
+       }
+
+       snd_hda_power_down(codec);
+
+       return 0;
+}
+
+static int ca0132_alt_xbass_xover_slider_ctl_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       long *valp = ucontrol->value.integer.value;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+
+       if (nid == BASS_REDIRECTION_XOVER)
+               *valp = spec->bass_redirect_xover_freq;
+       else
+               *valp = spec->xbass_xover_freq;
+
+       return 0;
+}
+
+static int ca0132_alt_slider_ctl_get(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx = nid - OUT_EFFECT_START_NID;
+
+       *valp = spec->fx_ctl_val[idx];
+       return 0;
+}
+
+/*
+ * The X-bass crossover starts at 10hz, so the min is 1. The
+ * frequency is set in multiples of 10.
+ */
+static int ca0132_alt_xbass_xover_slider_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 1;
+       uinfo->value.integer.max = 100;
+       uinfo->value.integer.step = 1;
+
+       return 0;
+}
+
+static int ca0132_alt_effect_slider_info(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_info *uinfo)
+{
+       int chs = get_amp_channels(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = chs == 3 ? 2 : 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 100;
+       uinfo->value.integer.step = 1;
+
+       return 0;
+}
+
+static int ca0132_alt_xbass_xover_slider_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       long *cur_val;
+       int idx;
+
+       if (nid == BASS_REDIRECTION_XOVER)
+               cur_val = &spec->bass_redirect_xover_freq;
+       else
+               cur_val = &spec->xbass_xover_freq;
+
+       /* any change? */
+       if (*cur_val == *valp)
+               return 0;
+
+       *cur_val = *valp;
+
+       idx = *valp;
+       if (nid == BASS_REDIRECTION_XOVER)
+               ca0132_alt_bass_redirection_xover_set(codec, *cur_val);
+       else
+               ca0132_alt_slider_ctl_set(codec, nid, float_xbass_xover_lookup, idx);
+
+       return 0;
+}
+
+static int ca0132_alt_effect_slider_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int idx;
+
+       idx = nid - EFFECT_START_NID;
+       /* any change? */
+       if (spec->fx_ctl_val[idx] == *valp)
+               return 0;
+
+       spec->fx_ctl_val[idx] = *valp;
+
+       idx = *valp;
+       ca0132_alt_slider_ctl_set(codec, nid, float_zero_to_one_lookup, idx);
+
+       return 0;
+}
+
+
+/*
+ * Mic Boost Enum for alternative ca0132 codecs. I didn't like that the original
+ * only has off or full 30 dB, and didn't like making a volume slider that has
+ * traditional 0-100 in alsamixer that goes in big steps. I like enum better.
+ */
+#define MIC_BOOST_NUM_OF_STEPS 4
+#define MIC_BOOST_ENUM_MAX_STRLEN 10
+
+static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       const char *sfx = "dB";
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = MIC_BOOST_NUM_OF_STEPS;
+       if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS)
+               uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1;
+       sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx);
+       strcpy(uinfo->value.enumerated.name, namestr);
+       return 0;
+}
+
+static int ca0132_alt_mic_boost_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->mic_boost_enum_val;
+       return 0;
+}
+
+static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = MIC_BOOST_NUM_OF_STEPS;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ca0132_alt_mic_boost: boost=%d\n",
+                   sel);
+
+       spec->mic_boost_enum_val = sel;
+
+       if (spec->in_enum_val != REAR_LINE_IN)
+               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
+
+       return 1;
+}
+
+/*
+ * Sound BlasterX AE-5 Headphone Gain Controls.
+ */
+#define AE5_HEADPHONE_GAIN_MAX 3
+static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       const char *sfx = " Ohms)";
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX;
+       if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX)
+               uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1;
+       sprintf(namestr, "%s %s",
+               ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
+               sfx);
+       strcpy(uinfo->value.enumerated.name, namestr);
+       return 0;
+}
+
+static int ae5_headphone_gain_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->ae5_headphone_gain_val;
+       return 0;
+}
+
+static int ae5_headphone_gain_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = AE5_HEADPHONE_GAIN_MAX;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ae5_headphone_gain: boost=%d\n",
+                   sel);
+
+       spec->ae5_headphone_gain_val = sel;
+
+       if (spec->out_enum_val == HEADPHONE_OUT)
+               ae5_headphone_gain_set(codec, spec->ae5_headphone_gain_val);
+
+       return 1;
+}
+
+/*
+ * Sound BlasterX AE-5 sound filter enumerated control.
+ */
+#define AE5_SOUND_FILTER_MAX 3
+
+static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX;
+       if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX)
+               uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1;
+       sprintf(namestr, "%s",
+                       ae5_filter_presets[uinfo->value.enumerated.item].name);
+       strcpy(uinfo->value.enumerated.name, namestr);
+       return 0;
+}
+
+static int ae5_sound_filter_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->ae5_filter_val;
+       return 0;
+}
+
+static int ae5_sound_filter_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = AE5_SOUND_FILTER_MAX;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ae5_sound_filter: %s\n",
+                       ae5_filter_presets[sel].name);
+
+       spec->ae5_filter_val = sel;
+
+       ca0113_mmio_command_set_type2(codec, 0x48, 0x07,
+                       ae5_filter_presets[sel].val);
+
+       return 1;
+}
+
+/*
+ * Input Select Control for alternative ca0132 codecs. This exists because
+ * front microphone has no auto-detect, and we need a way to set the rear
+ * as line-in
+ */
+static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS;
+       if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS)
+               uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1;
+       strcpy(uinfo->value.enumerated.name,
+                       in_src_str[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int ca0132_alt_input_source_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->in_enum_val;
+       return 0;
+}
+
+static int ca0132_alt_input_source_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = IN_SRC_NUM_OF_INPUTS;
+
+       /*
+        * The AE-7 has no front microphone, so limit items to 2: rear mic and
+        * line-in.
+        */
+       if (ca0132_quirk(spec) == QUIRK_AE7)
+               items = 2;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ca0132_alt_input_select: sel=%d, preset=%s\n",
+                   sel, in_src_str[sel]);
+
+       spec->in_enum_val = sel;
+
+       ca0132_alt_select_in(codec);
+
+       return 1;
+}
+
+/* Sound Blaster Z Output Select Control */
+static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = NUM_OF_OUTPUTS;
+       if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS)
+               uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1;
+       strcpy(uinfo->value.enumerated.name,
+                       out_type_str[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int ca0132_alt_output_select_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->out_enum_val;
+       return 0;
+}
+
+static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = NUM_OF_OUTPUTS;
+       unsigned int auto_jack;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ca0132_alt_output_select: sel=%d, preset=%s\n",
+                   sel, out_type_str[sel]);
+
+       spec->out_enum_val = sel;
+
+       auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
+
+       if (!auto_jack)
+               ca0132_alt_select_out(codec);
+
+       return 1;
+}
+
+/* Select surround output type: 2.1, 4.0, 4.1, or 5.1. */
+static int ca0132_alt_speaker_channel_cfg_get_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int items = SPEAKER_CHANNEL_CFG_COUNT;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = items;
+       if (uinfo->value.enumerated.item >= items)
+               uinfo->value.enumerated.item = items - 1;
+       strcpy(uinfo->value.enumerated.name,
+                       speaker_channel_cfgs[uinfo->value.enumerated.item].name);
+       return 0;
+}
+
+static int ca0132_alt_speaker_channel_cfg_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->channel_cfg_val;
+       return 0;
+}
+
+static int ca0132_alt_speaker_channel_cfg_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = SPEAKER_CHANNEL_CFG_COUNT;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ca0132_alt_speaker_channels: sel=%d, channels=%s\n",
+                   sel, speaker_channel_cfgs[sel].name);
+
+       spec->channel_cfg_val = sel;
+
+       if (spec->out_enum_val == SPEAKER_OUT)
+               ca0132_alt_select_out(codec);
+
+       return 1;
+}
+
+/*
+ * Smart Volume output setting control. Three different settings, Normal,
+ * which takes the value from the smart volume slider. The two others, loud
+ * and night, disregard the slider value and have uneditable values.
+ */
+#define NUM_OF_SVM_SETTINGS 3
+static const char *const out_svm_set_enum_str[3] = {"Normal", "Loud", "Night" };
+
+static int ca0132_alt_svm_setting_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = NUM_OF_SVM_SETTINGS;
+       if (uinfo->value.enumerated.item >= NUM_OF_SVM_SETTINGS)
+               uinfo->value.enumerated.item = NUM_OF_SVM_SETTINGS - 1;
+       strcpy(uinfo->value.enumerated.name,
+                       out_svm_set_enum_str[uinfo->value.enumerated.item]);
+       return 0;
+}
+
+static int ca0132_alt_svm_setting_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->smart_volume_setting;
+       return 0;
+}
+
+static int ca0132_alt_svm_setting_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = NUM_OF_SVM_SETTINGS;
+       unsigned int idx = SMART_VOLUME - EFFECT_START_NID;
+       unsigned int tmp;
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "ca0132_alt_svm_setting: sel=%d, preset=%s\n",
+                   sel, out_svm_set_enum_str[sel]);
+
+       spec->smart_volume_setting = sel;
+
+       switch (sel) {
+       case 0:
+               tmp = FLOAT_ZERO;
+               break;
+       case 1:
+               tmp = FLOAT_ONE;
+               break;
+       case 2:
+               tmp = FLOAT_TWO;
+               break;
+       default:
+               tmp = FLOAT_ZERO;
+               break;
+       }
+       /* Req 2 is the Smart Volume Setting req. */
+       dspio_set_uint_param(codec, ca0132_effects[idx].mid,
+                       ca0132_effects[idx].reqs[2], tmp);
+       return 1;
+}
+
+/* Sound Blaster Z EQ preset controls */
+static int ca0132_alt_eq_preset_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int items = ARRAY_SIZE(ca0132_alt_eq_presets);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = items;
+       if (uinfo->value.enumerated.item >= items)
+               uinfo->value.enumerated.item = items - 1;
+       strcpy(uinfo->value.enumerated.name,
+               ca0132_alt_eq_presets[uinfo->value.enumerated.item].name);
+       return 0;
+}
+
+static int ca0132_alt_eq_preset_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->eq_preset_val;
+       return 0;
+}
+
+static int ca0132_alt_eq_preset_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int i, err = 0;
+       int sel = ucontrol->value.enumerated.item[0];
+       unsigned int items = ARRAY_SIZE(ca0132_alt_eq_presets);
+
+       if (sel >= items)
+               return 0;
+
+       codec_dbg(codec, "%s: sel=%d, preset=%s\n", __func__, sel,
+                       ca0132_alt_eq_presets[sel].name);
+       /*
+        * Idx 0 is default.
+        * Default needs to qualify with CrystalVoice state.
+        */
+       for (i = 0; i < EQ_PRESET_MAX_PARAM_COUNT; i++) {
+               err = dspio_set_uint_param(codec, ca0132_alt_eq_enum.mid,
+                               ca0132_alt_eq_enum.reqs[i],
+                               ca0132_alt_eq_presets[sel].vals[i]);
+               if (err < 0)
+                       break;
+       }
+
+       if (err >= 0)
+               spec->eq_preset_val = sel;
+
+       return 1;
+}
+
+static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int items = ARRAY_SIZE(ca0132_voicefx_presets);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = items;
+       if (uinfo->value.enumerated.item >= items)
+               uinfo->value.enumerated.item = items - 1;
+       strcpy(uinfo->value.enumerated.name,
+              ca0132_voicefx_presets[uinfo->value.enumerated.item].name);
+       return 0;
+}
+
+static int ca0132_voicefx_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->voicefx_val;
+       return 0;
+}
+
+static int ca0132_voicefx_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       int i, err = 0;
+       int sel = ucontrol->value.enumerated.item[0];
+
+       if (sel >= ARRAY_SIZE(ca0132_voicefx_presets))
+               return 0;
+
+       codec_dbg(codec, "ca0132_voicefx_put: sel=%d, preset=%s\n",
+                   sel, ca0132_voicefx_presets[sel].name);
+
+       /*
+        * Idx 0 is default.
+        * Default needs to qualify with CrystalVoice state.
+        */
+       for (i = 0; i < VOICEFX_MAX_PARAM_COUNT; i++) {
+               err = dspio_set_uint_param(codec, ca0132_voicefx.mid,
+                               ca0132_voicefx.reqs[i],
+                               ca0132_voicefx_presets[sel].vals[i]);
+               if (err < 0)
+                       break;
+       }
+
+       if (err >= 0) {
+               spec->voicefx_val = sel;
+               /* enable voice fx */
+               ca0132_voicefx_set(codec, (sel ? 1 : 0));
+       }
+
+       return 1;
+}
+
+static int ca0132_switch_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       int ch = get_amp_channels(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+
+       /* vnode */
+       if ((nid >= VNODE_START_NID) && (nid < VNODE_END_NID)) {
+               if (ch & 1) {
+                       *valp = spec->vnode_lswitch[nid - VNODE_START_NID];
+                       valp++;
+               }
+               if (ch & 2) {
+                       *valp = spec->vnode_rswitch[nid - VNODE_START_NID];
+                       valp++;
+               }
+               return 0;
+       }
+
+       /* effects, include PE and CrystalVoice */
+       if ((nid >= EFFECT_START_NID) && (nid < EFFECT_END_NID)) {
+               *valp = spec->effects_switch[nid - EFFECT_START_NID];
+               return 0;
+       }
+
+       /* mic boost */
+       if (nid == spec->input_pins[0]) {
+               *valp = spec->cur_mic_boost;
+               return 0;
+       }
+
+       if (nid == ZXR_HEADPHONE_GAIN) {
+               *valp = spec->zxr_gain_set;
+               return 0;
+       }
+
+       if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) {
+               *valp = spec->speaker_range_val[nid - SPEAKER_FULL_RANGE_FRONT];
+               return 0;
+       }
+
+       if (nid == BASS_REDIRECTION) {
+               *valp = spec->bass_redirection_val;
+               return 0;
+       }
+
+       return 0;
+}
+
+static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       int ch = get_amp_channels(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       int changed = 1;
+
+       codec_dbg(codec, "ca0132_switch_put: nid=0x%x, val=%ld\n",
+                   nid, *valp);
+
+       snd_hda_power_up(codec);
+       /* vnode */
+       if ((nid >= VNODE_START_NID) && (nid < VNODE_END_NID)) {
+               if (ch & 1) {
+                       spec->vnode_lswitch[nid - VNODE_START_NID] = *valp;
+                       valp++;
+               }
+               if (ch & 2) {
+                       spec->vnode_rswitch[nid - VNODE_START_NID] = *valp;
+                       valp++;
+               }
+               changed = ca0132_vnode_switch_set(kcontrol, ucontrol);
+               goto exit;
+       }
+
+       /* PE */
+       if (nid == PLAY_ENHANCEMENT) {
+               spec->effects_switch[nid - EFFECT_START_NID] = *valp;
+               changed = ca0132_pe_switch_set(codec);
+               goto exit;
+       }
+
+       /* CrystalVoice */
+       if (nid == CRYSTAL_VOICE) {
+               spec->effects_switch[nid - EFFECT_START_NID] = *valp;
+               changed = ca0132_cvoice_switch_set(codec);
+               goto exit;
+       }
+
+       /* out and in effects */
+       if (((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) ||
+           ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID))) {
+               spec->effects_switch[nid - EFFECT_START_NID] = *valp;
+               changed = ca0132_effects_set(codec, nid, *valp);
+               goto exit;
+       }
+
+       /* mic boost */
+       if (nid == spec->input_pins[0]) {
+               spec->cur_mic_boost = *valp;
+               if (ca0132_use_alt_functions(spec)) {
+                       if (spec->in_enum_val != REAR_LINE_IN)
+                               changed = ca0132_mic_boost_set(codec, *valp);
+               } else {
+                       /* Mic boost does not apply to Digital Mic */
+                       if (spec->cur_mic_type != DIGITAL_MIC)
+                               changed = ca0132_mic_boost_set(codec, *valp);
+               }
+
+               goto exit;
+       }
+
+       if (nid == ZXR_HEADPHONE_GAIN) {
+               spec->zxr_gain_set = *valp;
+               if (spec->cur_out_type == HEADPHONE_OUT)
+                       changed = zxr_headphone_gain_set(codec, *valp);
+               else
+                       changed = 0;
+
+               goto exit;
+       }
+
+       if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) {
+               spec->speaker_range_val[nid - SPEAKER_FULL_RANGE_FRONT] = *valp;
+               if (spec->cur_out_type == SPEAKER_OUT)
+                       ca0132_alt_set_full_range_speaker(codec);
+
+               changed = 0;
+       }
+
+       if (nid == BASS_REDIRECTION) {
+               spec->bass_redirection_val = *valp;
+               if (spec->cur_out_type == SPEAKER_OUT)
+                       ca0132_alt_surround_set_bass_redirection(codec, *valp);
+
+               changed = 0;
+       }
+
+exit:
+       snd_hda_power_down(codec);
+       return changed;
+}
+
+/*
+ * Volume related
+ */
+/*
+ * Sets the internal DSP decibel level to match the DAC for output, and the
+ * ADC for input. Currently only the SBZ sets dsp capture volume level, and
+ * all alternative codecs set DSP playback volume.
+ */
+static void ca0132_alt_dsp_volume_put(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int dsp_dir;
+       unsigned int lookup_val;
+
+       if (nid == VNID_SPK)
+               dsp_dir = DSP_VOL_OUT;
+       else
+               dsp_dir = DSP_VOL_IN;
+
+       lookup_val = spec->vnode_lvol[nid - VNODE_START_NID];
+
+       dspio_set_uint_param(codec,
+               ca0132_alt_vol_ctls[dsp_dir].mid,
+               ca0132_alt_vol_ctls[dsp_dir].reqs[0],
+               float_vol_db_lookup[lookup_val]);
+
+       lookup_val = spec->vnode_rvol[nid - VNODE_START_NID];
+
+       dspio_set_uint_param(codec,
+               ca0132_alt_vol_ctls[dsp_dir].mid,
+               ca0132_alt_vol_ctls[dsp_dir].reqs[1],
+               float_vol_db_lookup[lookup_val]);
+
+       dspio_set_uint_param(codec,
+               ca0132_alt_vol_ctls[dsp_dir].mid,
+               ca0132_alt_vol_ctls[dsp_dir].reqs[2], FLOAT_ZERO);
+}
+
+static int ca0132_volume_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       int ch = get_amp_channels(kcontrol);
+       int dir = get_amp_direction(kcontrol);
+       unsigned long pval;
+       int err;
+
+       switch (nid) {
+       case VNID_SPK:
+               /* follow shared_out info */
+               nid = spec->shared_out_nid;
+               mutex_lock(&codec->control_mutex);
+               pval = kcontrol->private_value;
+               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
+               err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
+               kcontrol->private_value = pval;
+               mutex_unlock(&codec->control_mutex);
+               break;
+       case VNID_MIC:
+               /* follow shared_mic info */
+               nid = spec->shared_mic_nid;
+               mutex_lock(&codec->control_mutex);
+               pval = kcontrol->private_value;
+               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
+               err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
+               kcontrol->private_value = pval;
+               mutex_unlock(&codec->control_mutex);
+               break;
+       default:
+               err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
+       }
+       return err;
+}
+
+static int ca0132_volume_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       int ch = get_amp_channels(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+
+       /* store the left and right volume */
+       if (ch & 1) {
+               *valp = spec->vnode_lvol[nid - VNODE_START_NID];
+               valp++;
+       }
+       if (ch & 2) {
+               *valp = spec->vnode_rvol[nid - VNODE_START_NID];
+               valp++;
+       }
+       return 0;
+}
+
+static int ca0132_volume_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       int ch = get_amp_channels(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       hda_nid_t shared_nid = 0;
+       bool effective;
+       int changed = 1;
+
+       /* store the left and right volume */
+       if (ch & 1) {
+               spec->vnode_lvol[nid - VNODE_START_NID] = *valp;
+               valp++;
+       }
+       if (ch & 2) {
+               spec->vnode_rvol[nid - VNODE_START_NID] = *valp;
+               valp++;
+       }
+
+       /* if effective conditions, then update hw immediately. */
+       effective = ca0132_is_vnode_effective(codec, nid, &shared_nid);
+       if (effective) {
+               int dir = get_amp_direction(kcontrol);
+               unsigned long pval;
+
+               snd_hda_power_up(codec);
+               mutex_lock(&codec->control_mutex);
+               pval = kcontrol->private_value;
+               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch,
+                                                               0, dir);
+               changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+               kcontrol->private_value = pval;
+               mutex_unlock(&codec->control_mutex);
+               snd_hda_power_down(codec);
+       }
+
+       return changed;
+}
+
+/*
+ * This function is the same as the one above, because using an if statement
+ * inside of the above volume control for the DSP volume would cause too much
+ * lag. This is a lot more smooth.
+ */
+static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       int ch = get_amp_channels(kcontrol);
+       long *valp = ucontrol->value.integer.value;
+       hda_nid_t vnid = 0;
+       int changed;
+
+       switch (nid) {
+       case 0x02:
+               vnid = VNID_SPK;
+               break;
+       case 0x07:
+               vnid = VNID_MIC;
+               break;
+       }
+
+       /* store the left and right volume */
+       if (ch & 1) {
+               spec->vnode_lvol[vnid - VNODE_START_NID] = *valp;
+               valp++;
+       }
+       if (ch & 2) {
+               spec->vnode_rvol[vnid - VNODE_START_NID] = *valp;
+               valp++;
+       }
+
+       snd_hda_power_up(codec);
+       ca0132_alt_dsp_volume_put(codec, vnid);
+       mutex_lock(&codec->control_mutex);
+       changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+       mutex_unlock(&codec->control_mutex);
+       snd_hda_power_down(codec);
+
+       return changed;
+}
+
+static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
+                            unsigned int size, unsigned int __user *tlv)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct ca0132_spec *spec = codec->spec;
+       hda_nid_t nid = get_amp_nid(kcontrol);
+       int ch = get_amp_channels(kcontrol);
+       int dir = get_amp_direction(kcontrol);
+       unsigned long pval;
+       int err;
+
+       switch (nid) {
+       case VNID_SPK:
+               /* follow shared_out tlv */
+               nid = spec->shared_out_nid;
+               mutex_lock(&codec->control_mutex);
+               pval = kcontrol->private_value;
+               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
+               err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
+               kcontrol->private_value = pval;
+               mutex_unlock(&codec->control_mutex);
+               break;
+       case VNID_MIC:
+               /* follow shared_mic tlv */
+               nid = spec->shared_mic_nid;
+               mutex_lock(&codec->control_mutex);
+               pval = kcontrol->private_value;
+               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
+               err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
+               kcontrol->private_value = pval;
+               mutex_unlock(&codec->control_mutex);
+               break;
+       default:
+               err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
+       }
+       return err;
+}
+
+/* Add volume slider control for effect level */
+static int ca0132_alt_add_effect_slider(struct hda_codec *codec, hda_nid_t nid,
+                                       const char *pfx, int dir)
+{
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       int type = dir ? HDA_INPUT : HDA_OUTPUT;
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
+
+       sprintf(namestr, "FX: %s %s Volume", pfx, dirstr[dir]);
+
+       knew.tlv.c = NULL;
+
+       switch (nid) {
+       case XBASS_XOVER:
+               knew.info = ca0132_alt_xbass_xover_slider_info;
+               knew.get = ca0132_alt_xbass_xover_slider_ctl_get;
+               knew.put = ca0132_alt_xbass_xover_slider_put;
+               break;
+       default:
+               knew.info = ca0132_alt_effect_slider_info;
+               knew.get = ca0132_alt_slider_ctl_get;
+               knew.put = ca0132_alt_effect_slider_put;
+               knew.private_value =
+                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, type);
+               break;
+       }
+
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Added FX: prefix for the alternative codecs, because otherwise the surround
+ * effect would conflict with the Surround sound volume control. Also seems more
+ * clear as to what the switches do. Left alone for others.
+ */
+static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
+                        const char *pfx, int dir)
+{
+       struct ca0132_spec *spec = codec->spec;
+       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       int type = dir ? HDA_INPUT : HDA_OUTPUT;
+       struct snd_kcontrol_new knew =
+               CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type);
+       /* If using alt_controls, add FX: prefix. But, don't add FX:
+        * prefix to OutFX or InFX enable controls.
+        */
+       if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID))
+               sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]);
+       else
+               sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
+
+       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
+}
+
+static int add_voicefx(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO(ca0132_voicefx.name,
+                                   VOICEFX, 1, 0, HDA_INPUT);
+       knew.info = ca0132_voicefx_info;
+       knew.get = ca0132_voicefx_get;
+       knew.put = ca0132_voicefx_put;
+       return snd_hda_ctl_add(codec, VOICEFX, snd_ctl_new1(&knew, codec));
+}
+
+/* Create the EQ Preset control */
+static int add_ca0132_alt_eq_presets(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO(ca0132_alt_eq_enum.name,
+                                   EQ_PRESET_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ca0132_alt_eq_preset_info;
+       knew.get = ca0132_alt_eq_preset_get;
+       knew.put = ca0132_alt_eq_preset_put;
+       return snd_hda_ctl_add(codec, EQ_PRESET_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Add enumerated control for the three different settings of the smart volume
+ * output effect. Normal just uses the slider value, and loud and night are
+ * their own things that ignore that value.
+ */
+static int ca0132_alt_add_svm_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("FX: Smart Volume Setting",
+                                   SMART_VOLUME_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ca0132_alt_svm_setting_info;
+       knew.get = ca0132_alt_svm_setting_get;
+       knew.put = ca0132_alt_svm_setting_put;
+       return snd_hda_ctl_add(codec, SMART_VOLUME_ENUM,
+                               snd_ctl_new1(&knew, codec));
+
+}
+
+/*
+ * Create an Output Select enumerated control for codecs with surround
+ * out capabilities.
+ */
+static int ca0132_alt_add_output_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("Output Select",
+                                   OUTPUT_SOURCE_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ca0132_alt_output_select_get_info;
+       knew.get = ca0132_alt_output_select_get;
+       knew.put = ca0132_alt_output_select_put;
+       return snd_hda_ctl_add(codec, OUTPUT_SOURCE_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Add a control for selecting channel count on speaker output. Setting this
+ * allows the DSP to do bass redirection and channel upmixing on surround
+ * configurations.
+ */
+static int ca0132_alt_add_speaker_channel_cfg_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("Surround Channel Config",
+                                   SPEAKER_CHANNEL_CFG_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ca0132_alt_speaker_channel_cfg_get_info;
+       knew.get = ca0132_alt_speaker_channel_cfg_get;
+       knew.put = ca0132_alt_speaker_channel_cfg_put;
+       return snd_hda_ctl_add(codec, SPEAKER_CHANNEL_CFG_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Full range front stereo and rear surround switches. When these are set to
+ * full range, the lower frequencies from these channels are no longer
+ * redirected to the LFE channel.
+ */
+static int ca0132_alt_add_front_full_range_switch(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               CA0132_CODEC_MUTE_MONO("Full-Range Front Speakers",
+                                   SPEAKER_FULL_RANGE_FRONT, 1, HDA_OUTPUT);
+
+       return snd_hda_ctl_add(codec, SPEAKER_FULL_RANGE_FRONT,
+                               snd_ctl_new1(&knew, codec));
+}
+
+static int ca0132_alt_add_rear_full_range_switch(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               CA0132_CODEC_MUTE_MONO("Full-Range Rear Speakers",
+                                   SPEAKER_FULL_RANGE_REAR, 1, HDA_OUTPUT);
+
+       return snd_hda_ctl_add(codec, SPEAKER_FULL_RANGE_REAR,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Bass redirection redirects audio below the crossover frequency to the LFE
+ * channel on speakers that are set as not being full-range. On configurations
+ * without an LFE channel, it does nothing. Bass redirection seems to be the
+ * replacement for X-Bass on configurations with an LFE channel.
+ */
+static int ca0132_alt_add_bass_redirection_crossover(struct hda_codec *codec)
+{
+       const char *namestr = "Bass Redirection Crossover";
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_VOLUME_MONO(namestr, BASS_REDIRECTION_XOVER, 1, 0,
+                               HDA_OUTPUT);
+
+       knew.tlv.c = NULL;
+       knew.info = ca0132_alt_xbass_xover_slider_info;
+       knew.get = ca0132_alt_xbass_xover_slider_ctl_get;
+       knew.put = ca0132_alt_xbass_xover_slider_put;
+
+       return snd_hda_ctl_add(codec, BASS_REDIRECTION_XOVER,
+                       snd_ctl_new1(&knew, codec));
+}
+
+static int ca0132_alt_add_bass_redirection_switch(struct hda_codec *codec)
+{
+       const char *namestr = "Bass Redirection";
+       struct snd_kcontrol_new knew =
+               CA0132_CODEC_MUTE_MONO(namestr, BASS_REDIRECTION, 1,
+                               HDA_OUTPUT);
+
+       return snd_hda_ctl_add(codec, BASS_REDIRECTION,
+                       snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Create an Input Source enumerated control for the alternate ca0132 codecs
+ * because the front microphone has no auto-detect, and Line-in has to be set
+ * somehow.
+ */
+static int ca0132_alt_add_input_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("Input Source",
+                                   INPUT_SOURCE_ENUM, 1, 0, HDA_INPUT);
+       knew.info = ca0132_alt_input_source_info;
+       knew.get = ca0132_alt_input_source_get;
+       knew.put = ca0132_alt_input_source_put;
+       return snd_hda_ctl_add(codec, INPUT_SOURCE_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Add mic boost enumerated control. Switches through 0dB to 30dB. This adds
+ * more control than the original mic boost, which is either full 30dB or off.
+ */
+static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("Mic Boost Capture Switch",
+                                   MIC_BOOST_ENUM, 1, 0, HDA_INPUT);
+       knew.info = ca0132_alt_mic_boost_info;
+       knew.get = ca0132_alt_mic_boost_get;
+       knew.put = ca0132_alt_mic_boost_put;
+       return snd_hda_ctl_add(codec, MIC_BOOST_ENUM,
+                               snd_ctl_new1(&knew, codec));
+
+}
+
+/*
+ * Add headphone gain enumerated control for the AE-5. This switches between
+ * three modes, low, medium, and high. When non-headphone outputs are selected,
+ * it is automatically set to high. This is the same behavior as Windows.
+ */
+static int ae5_add_headphone_gain_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain",
+                                   AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ae5_headphone_gain_info;
+       knew.get = ae5_headphone_gain_get;
+       knew.put = ae5_headphone_gain_put;
+       return snd_hda_ctl_add(codec, AE5_HEADPHONE_GAIN_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Add sound filter enumerated control for the AE-5. This adds three different
+ * settings: Slow Roll Off, Minimum Phase, and Fast Roll Off. From what I've
+ * read into it, it changes the DAC's interpolation filter.
+ */
+static int ae5_add_sound_filter_enum(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               HDA_CODEC_MUTE_MONO("AE-5: Sound Filter",
+                                   AE5_SOUND_FILTER_ENUM, 1, 0, HDA_OUTPUT);
+       knew.info = ae5_sound_filter_info;
+       knew.get = ae5_sound_filter_get;
+       knew.put = ae5_sound_filter_put;
+       return snd_hda_ctl_add(codec, AE5_SOUND_FILTER_ENUM,
+                               snd_ctl_new1(&knew, codec));
+}
+
+static int zxr_add_headphone_gain_switch(struct hda_codec *codec)
+{
+       struct snd_kcontrol_new knew =
+               CA0132_CODEC_MUTE_MONO("ZxR: 600 Ohm Gain",
+                                   ZXR_HEADPHONE_GAIN, 1, HDA_OUTPUT);
+
+       return snd_hda_ctl_add(codec, ZXR_HEADPHONE_GAIN,
+                               snd_ctl_new1(&knew, codec));
+}
+
+/*
+ * Need to create follower controls for the alternate codecs that have surround
+ * capabilities.
+ */
+static const char * const ca0132_alt_follower_pfxs[] = {
+       "Front", "Surround", "Center", "LFE", NULL,
+};
+
+/*
+ * Also need special channel map, because the default one is incorrect.
+ * I think this has to do with the pin for rear surround being 0x11,
+ * and the center/lfe being 0x10. Usually the pin order is the opposite.
+ */
+static const struct snd_pcm_chmap_elem ca0132_alt_chmaps[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+       { .channels = 4,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { .channels = 6,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
+                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
+       { }
+};
+
+/* Add the correct chmap for streams with 6 channels. */
+static void ca0132_alt_add_chmap_ctls(struct hda_codec *codec)
+{
+       int err = 0;
+       struct hda_pcm *pcm;
+
+       list_for_each_entry(pcm, &codec->pcm_list_head, list) {
+               struct hda_pcm_stream *hinfo =
+                       &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
+               struct snd_pcm_chmap *chmap;
+               const struct snd_pcm_chmap_elem *elem;
+
+               elem = ca0132_alt_chmaps;
+               if (hinfo->channels_max == 6) {
+                       err = snd_pcm_add_chmap_ctls(pcm->pcm,
+                                       SNDRV_PCM_STREAM_PLAYBACK,
+                                       elem, hinfo->channels_max, 0, &chmap);
+                       if (err < 0)
+                               codec_dbg(codec, "snd_pcm_add_chmap_ctls failed!");
+               }
+       }
+}
+
+/*
+ * When changing Node IDs for Mixer Controls below, make sure to update
+ * Node IDs in ca0132_config() as well.
+ */
+static const struct snd_kcontrol_new ca0132_mixer[] = {
+       CA0132_CODEC_VOL("Master Playback Volume", VNID_SPK, HDA_OUTPUT),
+       CA0132_CODEC_MUTE("Master Playback Switch", VNID_SPK, HDA_OUTPUT),
+       CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT),
+       CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
+       HDA_CODEC_VOLUME("Analog-Mic2 Capture Volume", 0x08, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("Analog-Mic2 Capture Switch", 0x08, 0, HDA_INPUT),
+       HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT),
+       CA0132_CODEC_MUTE_MONO("Mic1-Boost (30dB) Capture Switch",
+                              0x12, 1, HDA_INPUT),
+       CA0132_CODEC_MUTE_MONO("HP/Speaker Playback Switch",
+                              VNID_HP_SEL, 1, HDA_OUTPUT),
+       CA0132_CODEC_MUTE_MONO("AMic1/DMic Capture Switch",
+                              VNID_AMIC1_SEL, 1, HDA_INPUT),
+       CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch",
+                              VNID_HP_ASEL, 1, HDA_OUTPUT),
+       CA0132_CODEC_MUTE_MONO("AMic1/DMic Auto Detect Capture Switch",
+                              VNID_AMIC1_ASEL, 1, HDA_INPUT),
+       { } /* end */
+};
+
+/*
+ * Desktop specific control mixer. Removes auto-detect for mic, and adds
+ * surround controls. Also sets both the Front Playback and Capture Volume
+ * controls to alt so they set the DSP's decibel level.
+ */
+static const struct snd_kcontrol_new desktop_mixer[] = {
+       CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
+       CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT),
+       CA0132_ALT_CODEC_VOL("Capture Volume", 0x07, HDA_INPUT),
+       CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
+       HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT),
+       CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch",
+                               VNID_HP_ASEL, 1, HDA_OUTPUT),
+       { } /* end */
+};
+
+/*
+ * Same as the Sound Blaster Z, except doesn't use the alt volume for capture
+ * because it doesn't set decibel levels for the DSP for capture.
+ */
+static const struct snd_kcontrol_new r3di_mixer[] = {
+       CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
+       CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
+       HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT),
+       CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT),
+       CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
+       HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
+       HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT),
+       CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch",
+                               VNID_HP_ASEL, 1, HDA_OUTPUT),
+       { } /* end */
+};
+
+static int ca0132_build_controls(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int i, num_fx, num_sliders;
+       int err = 0;
+
+       /* Add Mixer controls */
+       for (i = 0; i < spec->num_mixers; i++) {
+               err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
+               if (err < 0)
+                       return err;
+       }
+       /* Setup vmaster with surround followers for desktop ca0132 devices */
+       if (ca0132_use_alt_functions(spec)) {
+               snd_hda_set_vmaster_tlv(codec, spec->dacs[0], HDA_OUTPUT,
+                                       spec->tlv);
+               snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                       spec->tlv, ca0132_alt_follower_pfxs,
+                                       "Playback Volume", 0);
+               err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                           NULL, ca0132_alt_follower_pfxs,
+                                           "Playback Switch",
+                                           true, 0, &spec->vmaster_mute.sw_kctl);
+               if (err < 0)
+                       return err;
+       }
+
+       /* Add in and out effects controls.
+        * VoiceFX, PE and CrystalVoice are added separately.
+        */
+       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
+       for (i = 0; i < num_fx; i++) {
+               /* Desktop cards break if Echo Cancellation is used. */
+               if (ca0132_use_pci_mmio(spec)) {
+                       if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
+                                               OUT_EFFECTS_COUNT))
+                               continue;
+               }
+
+               err = add_fx_switch(codec, ca0132_effects[i].nid,
+                                   ca0132_effects[i].name,
+                                   ca0132_effects[i].direct);
+               if (err < 0)
+                       return err;
+       }
+       /*
+        * If codec has use_alt_controls set to true, add effect level sliders,
+        * EQ presets, and Smart Volume presets. Also, change names to add FX
+        * prefix, and change PlayEnhancement and CrystalVoice to match.
+        */
+       if (ca0132_use_alt_controls(spec)) {
+               err = ca0132_alt_add_svm_enum(codec);
+               if (err < 0)
+                       return err;
+
+               err = add_ca0132_alt_eq_presets(codec);
+               if (err < 0)
+                       return err;
+
+               err = add_fx_switch(codec, PLAY_ENHANCEMENT,
+                                       "Enable OutFX", 0);
+               if (err < 0)
+                       return err;
+
+               err = add_fx_switch(codec, CRYSTAL_VOICE,
+                                       "Enable InFX", 1);
+               if (err < 0)
+                       return err;
+
+               num_sliders = OUT_EFFECTS_COUNT - 1;
+               for (i = 0; i < num_sliders; i++) {
+                       err = ca0132_alt_add_effect_slider(codec,
+                                           ca0132_effects[i].nid,
+                                           ca0132_effects[i].name,
+                                           ca0132_effects[i].direct);
+                       if (err < 0)
+                               return err;
+               }
+
+               err = ca0132_alt_add_effect_slider(codec, XBASS_XOVER,
+                                       "X-Bass Crossover", EFX_DIR_OUT);
+
+               if (err < 0)
+                       return err;
+       } else {
+               err = add_fx_switch(codec, PLAY_ENHANCEMENT,
+                                       "PlayEnhancement", 0);
+               if (err < 0)
+                       return err;
+
+               err = add_fx_switch(codec, CRYSTAL_VOICE,
+                                       "CrystalVoice", 1);
+               if (err < 0)
+                       return err;
+       }
+       err = add_voicefx(codec);
+       if (err < 0)
+               return err;
+
+       /*
+        * If the codec uses alt_functions, you need the enumerated controls
+        * to select the new outputs and inputs, plus add the new mic boost
+        * setting control.
+        */
+       if (ca0132_use_alt_functions(spec)) {
+               err = ca0132_alt_add_output_enum(codec);
+               if (err < 0)
+                       return err;
+               err = ca0132_alt_add_speaker_channel_cfg_enum(codec);
+               if (err < 0)
+                       return err;
+               err = ca0132_alt_add_front_full_range_switch(codec);
+               if (err < 0)
+                       return err;
+               err = ca0132_alt_add_rear_full_range_switch(codec);
+               if (err < 0)
+                       return err;
+               err = ca0132_alt_add_bass_redirection_crossover(codec);
+               if (err < 0)
+                       return err;
+               err = ca0132_alt_add_bass_redirection_switch(codec);
+               if (err < 0)
+                       return err;
+               err = ca0132_alt_add_mic_boost_enum(codec);
+               if (err < 0)
+                       return err;
+               /*
+                * ZxR only has microphone input, there is no front panel
+                * header on the card, and aux-in is handled by the DBPro board.
+                */
+               if (ca0132_quirk(spec) != QUIRK_ZXR) {
+                       err = ca0132_alt_add_input_enum(codec);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_AE5:
+       case QUIRK_AE7:
+               err = ae5_add_headphone_gain_enum(codec);
+               if (err < 0)
+                       return err;
+               err = ae5_add_sound_filter_enum(codec);
+               if (err < 0)
+                       return err;
+               break;
+       case QUIRK_ZXR:
+               err = zxr_add_headphone_gain_switch(codec);
+               if (err < 0)
+                       return err;
+               break;
+       default:
+               break;
+       }
+
+#ifdef ENABLE_TUNING_CONTROLS
+       add_tuning_ctls(codec);
+#endif
+
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       if (spec->dig_out) {
+               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
+                                                   spec->dig_out);
+               if (err < 0)
+                       return err;
+               err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
+               if (err < 0)
+                       return err;
+               /* spec->multiout.share_spdif = 1; */
+       }
+
+       if (spec->dig_in) {
+               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+               if (err < 0)
+                       return err;
+       }
+
+       if (ca0132_use_alt_functions(spec))
+               ca0132_alt_add_chmap_ctls(codec);
+
+       return 0;
+}
+
+static int dbpro_build_controls(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int err = 0;
+
+       if (spec->dig_out) {
+               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
+                               spec->dig_out);
+               if (err < 0)
+                       return err;
+       }
+
+       if (spec->dig_in) {
+               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/*
+ * PCM
+ */
+static const struct hda_pcm_stream ca0132_pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 6,
+       .ops = {
+               .prepare = ca0132_playback_pcm_prepare,
+               .cleanup = ca0132_playback_pcm_cleanup,
+               .get_delay = ca0132_playback_pcm_delay,
+       },
+};
+
+static const struct hda_pcm_stream ca0132_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .prepare = ca0132_capture_pcm_prepare,
+               .cleanup = ca0132_capture_pcm_cleanup,
+               .get_delay = ca0132_capture_pcm_delay,
+       },
+};
+
+static const struct hda_pcm_stream ca0132_pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .open = ca0132_dig_playback_pcm_open,
+               .close = ca0132_dig_playback_pcm_close,
+               .prepare = ca0132_dig_playback_pcm_prepare,
+               .cleanup = ca0132_dig_playback_pcm_cleanup
+       },
+};
+
+static const struct hda_pcm_stream ca0132_pcm_digital_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+};
+
+static int ca0132_build_pcms(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct hda_pcm *info;
+
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
+       if (!info)
+               return -ENOMEM;
+       if (ca0132_use_alt_functions(spec)) {
+               info->own_chmap = true;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap
+                       = ca0132_alt_chmaps;
+       }
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+               spec->multiout.max_channels;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
+
+       /* With the DSP enabled, desktops don't use this ADC. */
+       if (!ca0132_use_alt_functions(spec)) {
+               info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
+               if (!info)
+                       return -ENOMEM;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                       ca0132_pcm_analog_capture;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1];
+       }
+
+       info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear");
+       if (!info)
+               return -ENOMEM;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2];
+
+       if (!spec->dig_out && !spec->dig_in)
+               return 0;
+
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
+       if (!info)
+               return -ENOMEM;
+       info->pcm_type = HDA_PCM_TYPE_SPDIF;
+       if (spec->dig_out) {
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                       ca0132_pcm_digital_playback;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
+       }
+       if (spec->dig_in) {
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                       ca0132_pcm_digital_capture;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+       }
+
+       return 0;
+}
+
+static int dbpro_build_pcms(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct hda_pcm *info;
+
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Alt Analog");
+       if (!info)
+               return -ENOMEM;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
+
+
+       if (!spec->dig_out && !spec->dig_in)
+               return 0;
+
+       info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
+       if (!info)
+               return -ENOMEM;
+       info->pcm_type = HDA_PCM_TYPE_SPDIF;
+       if (spec->dig_out) {
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
+                       ca0132_pcm_digital_playback;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
+       }
+       if (spec->dig_in) {
+               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
+                       ca0132_pcm_digital_capture;
+               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
+       }
+
+       return 0;
+}
+
+static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
+{
+       if (pin) {
+               snd_hda_set_pin_ctl(codec, pin, PIN_HP);
+               if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+                       snd_hda_codec_write(codec, pin, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_OUT_UNMUTE);
+       }
+       if (dac && (get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
+               snd_hda_codec_write(codec, dac, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
+}
+
+static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
+{
+       if (pin) {
+               snd_hda_set_pin_ctl(codec, pin, PIN_VREF80);
+               if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
+                       snd_hda_codec_write(codec, pin, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_IN_UNMUTE(0));
+       }
+       if (adc && (get_wcaps(codec, adc) & AC_WCAP_IN_AMP)) {
+               snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_IN_UNMUTE(0));
+
+               /* init to 0 dB and unmute. */
+               snd_hda_codec_amp_stereo(codec, adc, HDA_INPUT, 0,
+                                        HDA_AMP_VOLMASK, 0x5a);
+               snd_hda_codec_amp_stereo(codec, adc, HDA_INPUT, 0,
+                                        HDA_AMP_MUTE, 0);
+       }
+}
+
+static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+       unsigned int caps;
+
+       caps = snd_hda_param_read(codec, nid, dir == HDA_OUTPUT ?
+                                 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
+       snd_hda_override_amp_caps(codec, nid, dir, caps);
+}
+
+/*
+ * Switch between Digital built-in mic and analog mic.
+ */
+static void ca0132_set_dmic(struct hda_codec *codec, int enable)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+       u8 val;
+       unsigned int oldval;
+
+       codec_dbg(codec, "ca0132_set_dmic: enable=%d\n", enable);
+
+       oldval = stop_mic1(codec);
+       ca0132_set_vipsource(codec, 0);
+       if (enable) {
+               /* set DMic input as 2-ch */
+               tmp = FLOAT_TWO;
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+               val = spec->dmic_ctl;
+               val |= 0x80;
+               snd_hda_codec_write(codec, spec->input_pins[0], 0,
+                                   VENDOR_CHIPIO_DMIC_CTL_SET, val);
+
+               if (!(spec->dmic_ctl & 0x20))
+                       chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 1);
+       } else {
+               /* set AMic input as mono */
+               tmp = FLOAT_ONE;
+               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+               val = spec->dmic_ctl;
+               /* clear bit7 and bit5 to disable dmic */
+               val &= 0x5f;
+               snd_hda_codec_write(codec, spec->input_pins[0], 0,
+                                   VENDOR_CHIPIO_DMIC_CTL_SET, val);
+
+               if (!(spec->dmic_ctl & 0x20))
+                       chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 0);
+       }
+       ca0132_set_vipsource(codec, 1);
+       resume_mic1(codec, oldval);
+}
+
+/*
+ * Initialization for Digital Mic.
+ */
+static void ca0132_init_dmic(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       u8 val;
+
+       /* Setup Digital Mic here, but don't enable.
+        * Enable based on jack detect.
+        */
+
+       /* MCLK uses MPIO1, set to enable.
+        * Bit 2-0: MPIO select
+        * Bit   3: set to disable
+        * Bit 7-4: reserved
+        */
+       val = 0x01;
+       snd_hda_codec_write(codec, spec->input_pins[0], 0,
+                           VENDOR_CHIPIO_DMIC_MCLK_SET, val);
+
+       /* Data1 uses MPIO3. Data2 not use
+        * Bit 2-0: Data1 MPIO select
+        * Bit   3: set disable Data1
+        * Bit 6-4: Data2 MPIO select
+        * Bit   7: set disable Data2
+        */
+       val = 0x83;
+       snd_hda_codec_write(codec, spec->input_pins[0], 0,
+                           VENDOR_CHIPIO_DMIC_PIN_SET, val);
+
+       /* Use Ch-0 and Ch-1. Rate is 48K, mode 1. Disable DMic first.
+        * Bit 3-0: Channel mask
+        * Bit   4: set for 48KHz, clear for 32KHz
+        * Bit   5: mode
+        * Bit   6: set to select Data2, clear for Data1
+        * Bit   7: set to enable DMic, clear for AMic
+        */
+       if (ca0132_quirk(spec) == QUIRK_ALIENWARE_M17XR4)
+               val = 0x33;
+       else
+               val = 0x23;
+       /* keep a copy of dmic ctl val for enable/disable dmic purpuse */
+       spec->dmic_ctl = val;
+       snd_hda_codec_write(codec, spec->input_pins[0], 0,
+                           VENDOR_CHIPIO_DMIC_CTL_SET, val);
+}
+
+/*
+ * Initialization for Analog Mic 2
+ */
+static void ca0132_init_analog_mic2(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       chipio_8051_write_exram_no_mutex(codec, 0x1920, 0x00);
+       chipio_8051_write_exram_no_mutex(codec, 0x192d, 0x00);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ca0132_refresh_widget_caps(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int i;
+
+       codec_dbg(codec, "ca0132_refresh_widget_caps.\n");
+       snd_hda_codec_update_widgets(codec);
+
+       for (i = 0; i < spec->multiout.num_dacs; i++)
+               refresh_amp_caps(codec, spec->dacs[i], HDA_OUTPUT);
+
+       for (i = 0; i < spec->num_outputs; i++)
+               refresh_amp_caps(codec, spec->out_pins[i], HDA_OUTPUT);
+
+       for (i = 0; i < spec->num_inputs; i++) {
+               refresh_amp_caps(codec, spec->adcs[i], HDA_INPUT);
+               refresh_amp_caps(codec, spec->input_pins[i], HDA_INPUT);
+       }
+}
+
+
+/* If there is an active channel for some reason, find it and free it. */
+static void ca0132_alt_free_active_dma_channels(struct hda_codec *codec)
+{
+       unsigned int i, tmp;
+       int status;
+
+       /* Read active DSPDMAC channel register. */
+       status = chipio_read(codec, DSPDMAC_CHNLSTART_MODULE_OFFSET, &tmp);
+       if (status >= 0) {
+               /* AND against 0xfff to get the active channel bits. */
+               tmp = tmp & 0xfff;
+
+               /* If there are no active channels, nothing to free. */
+               if (!tmp)
+                       return;
+       } else {
+               codec_dbg(codec, "%s: Failed to read active DSP DMA channel register.\n",
+                               __func__);
+               return;
+       }
+
+       /*
+        * Check each DSP DMA channel for activity, and if the channel is
+        * active, free it.
+        */
+       for (i = 0; i < DSPDMAC_DMA_CFG_CHANNEL_COUNT; i++) {
+               if (dsp_is_dma_active(codec, i)) {
+                       status = dspio_free_dma_chan(codec, i);
+                       if (status < 0)
+                               codec_dbg(codec, "%s: Failed to free active DSP DMA channel %d.\n",
+                                               __func__, i);
+               }
+       }
+}
+
+/*
+ * In the case of CT_EXTENSIONS_ENABLE being set to 1, and the DSP being in
+ * use, audio is no longer routed directly to the DAC/ADC from the HDA stream.
+ * Instead, audio is now routed through the DSP's DMA controllers, which
+ * the DSP is tasked with setting up itself. Through debugging, it seems the
+ * cause of most of the no-audio on startup issues were due to improperly
+ * configured DSP DMA channels.
+ *
+ * Normally, the DSP configures these the first time an HDA audio stream is
+ * started post DSP firmware download. That is why creating a 'dummy' stream
+ * worked in fixing the audio in some cases. This works most of the time, but
+ * sometimes if a stream is started/stopped before the DSP can setup the DMA
+ * configuration registers, it ends up in a broken state. Issues can also
+ * arise if streams are started in an unusual order, i.e the audio output dma
+ * channel being sandwiched between the mic1 and mic2 dma channels.
+ *
+ * The solution to this is to make sure that the DSP has no DMA channels
+ * in use post DSP firmware download, and then to manually start each default
+ * DSP stream that uses the DMA channels. These are 0x0c, the audio output
+ * stream, 0x03, analog mic 1, and 0x04, analog mic 2.
+ */
+static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec)
+{
+       static const unsigned int dsp_dma_stream_ids[] = { 0x0c, 0x03, 0x04 };
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int i, tmp;
+
+       /*
+        * Check if any of the default streams are active, and if they are,
+        * stop them.
+        */
+       mutex_lock(&spec->chipio_mutex);
+
+       for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
+               chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp);
+
+               if (tmp) {
+                       chipio_set_stream_control(codec,
+                                       dsp_dma_stream_ids[i], 0);
+               }
+       }
+
+       mutex_unlock(&spec->chipio_mutex);
+
+       /*
+        * If all DSP streams are inactive, there should be no active DSP DMA
+        * channels. Check and make sure this is the case, and if it isn't,
+        * free any active channels.
+        */
+       ca0132_alt_free_active_dma_channels(codec);
+
+       mutex_lock(&spec->chipio_mutex);
+
+       /* Make sure stream 0x0c is six channels. */
+       chipio_set_stream_channels(codec, 0x0c, 6);
+
+       for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
+               chipio_set_stream_control(codec,
+                               dsp_dma_stream_ids[i], 1);
+
+               /* Give the DSP some time to setup the DMA channel. */
+               msleep(75);
+       }
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+/*
+ * The region of ChipIO memory from 0x190000-0x1903fc is a sort of 'audio
+ * router', where each entry represents a 48khz audio channel, with a format
+ * of an 8-bit destination, an 8-bit source, and an unknown 2-bit number
+ * value. The 2-bit number value is seemingly 0 if inactive, 1 if active,
+ * and 3 if it's using Sample Rate Converter ports.
+ * An example is:
+ * 0x0001f8c0
+ * In this case, f8 is the destination, and c0 is the source. The number value
+ * is 1.
+ * This region of memory is normally managed internally by the 8051, where
+ * the region of exram memory from 0x1477-0x1575 has each byte represent an
+ * entry within the 0x190000 range, and when a range of entries is in use, the
+ * ending value is overwritten with 0xff.
+ * 0x1578 in exram is a table of 0x25 entries, corresponding to the ChipIO
+ * streamID's, where each entry is a starting 0x190000 port offset.
+ * 0x159d in exram is the same as 0x1578, except it contains the ending port
+ * offset for the corresponding streamID.
+ *
+ * On certain cards, such as the SBZ/ZxR/AE7, these are originally setup by
+ * the 8051, then manually overwritten to remap the ports to work with the
+ * new DACs.
+ *
+ * Currently known portID's:
+ * 0x00-0x1f: HDA audio stream input/output ports.
+ * 0x80-0xbf: Sample rate converter input/outputs. Only valid ports seem to
+ *            have the lower-nibble set to 0x1, 0x2, and 0x9.
+ * 0xc0-0xdf: DSP DMA input/output ports. Dynamically assigned.
+ * 0xe0-0xff: DAC/ADC audio input/output ports.
+ *
+ * Currently known streamID's:
+ * 0x03: Mic1 ADC to DSP.
+ * 0x04: Mic2 ADC to DSP.
+ * 0x05: HDA node 0x02 audio stream to DSP.
+ * 0x0f: DSP Mic exit to HDA node 0x07.
+ * 0x0c: DSP processed audio to DACs.
+ * 0x14: DAC0, front L/R.
+ *
+ * It is possible to route the HDA audio streams directly to the DAC and
+ * bypass the DSP entirely, with the only downside being that since the DSP
+ * does volume control, the only volume control you'll get is through PCM on
+ * the PC side, in the same way volume is handled for optical out. This may be
+ * useful for debugging.
+ */
+static void chipio_remap_stream(struct hda_codec *codec,
+               const struct chipio_stream_remap_data *remap_data)
+{
+       unsigned int i, stream_offset;
+
+       /* Get the starting port for the stream to be remapped. */
+       chipio_8051_read_exram(codec, 0x1578 + remap_data->stream_id,
+                       &stream_offset);
+
+       /*
+        * Check if the stream's port value is 0xff, because the 8051 may not
+        * have gotten around to setting up the stream yet. Wait until it's
+        * setup to remap it's ports.
+        */
+       if (stream_offset == 0xff) {
+               for (i = 0; i < 5; i++) {
+                       msleep(25);
+
+                       chipio_8051_read_exram(codec, 0x1578 + remap_data->stream_id,
+                                       &stream_offset);
+
+                       if (stream_offset != 0xff)
+                               break;
+               }
+       }
+
+       if (stream_offset == 0xff) {
+               codec_info(codec, "%s: Stream 0x%02x ports aren't allocated, remap failed!\n",
+                               __func__, remap_data->stream_id);
+               return;
+       }
+
+       /* Offset isn't in bytes, its in 32-bit words, so multiply it by 4. */
+       stream_offset *= 0x04;
+       stream_offset += 0x190000;
+
+       for (i = 0; i < remap_data->count; i++) {
+               chipio_write_no_mutex(codec,
+                               stream_offset + remap_data->offset[i],
+                               remap_data->value[i]);
+       }
+
+       /* Update stream map configuration. */
+       chipio_write_no_mutex(codec, 0x19042c, 0x00000001);
+}
+
+/*
+ * Default speaker tuning values setup for alternative codecs.
+ */
+static const unsigned int sbz_default_delay_values[] = {
+       /* Non-zero values are floating point 0.000198. */
+       0x394f9e38, 0x394f9e38, 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+static const unsigned int zxr_default_delay_values[] = {
+       /* Non-zero values are floating point 0.000220. */
+       0x00000000, 0x00000000, 0x3966afcd, 0x3966afcd, 0x3966afcd, 0x3966afcd
+};
+
+static const unsigned int ae5_default_delay_values[] = {
+       /* Non-zero values are floating point 0.000100. */
+       0x00000000, 0x00000000, 0x38d1b717, 0x38d1b717, 0x38d1b717, 0x38d1b717
+};
+
+/*
+ * If we never change these, probably only need them on initialization.
+ */
+static void ca0132_alt_init_speaker_tuning(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int i, tmp, start_req, end_req;
+       const unsigned int *values;
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+               values = sbz_default_delay_values;
+               break;
+       case QUIRK_ZXR:
+               values = zxr_default_delay_values;
+               break;
+       case QUIRK_AE5:
+       case QUIRK_AE7:
+               values = ae5_default_delay_values;
+               break;
+       default:
+               values = sbz_default_delay_values;
+               break;
+       }
+
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_ENABLE_CENTER_EQ, tmp);
+
+       start_req = SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL;
+       end_req = SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL;
+       for (i = start_req; i < end_req + 1; i++)
+               dspio_set_uint_param(codec, 0x96, i, tmp);
+
+       start_req = SPEAKER_TUNING_FRONT_LEFT_INVERT;
+       end_req = SPEAKER_TUNING_REAR_RIGHT_INVERT;
+       for (i = start_req; i < end_req + 1; i++)
+               dspio_set_uint_param(codec, 0x96, i, tmp);
+
+
+       for (i = 0; i < 6; i++)
+               dspio_set_uint_param(codec, 0x96,
+                               SPEAKER_TUNING_FRONT_LEFT_DELAY + i, values[i]);
+}
+
+/*
+ * Initialize mic for non-chromebook ca0132 implementations.
+ */
+static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+
+       /* Mic 1 Setup */
+       chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
+       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
+       if (ca0132_quirk(spec) == QUIRK_R3DI) {
+               chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+               tmp = FLOAT_ONE;
+       } else
+               tmp = FLOAT_THREE;
+       dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+       /* Mic 2 setup (not present on desktop cards) */
+       chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
+       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
+       if (ca0132_quirk(spec) == QUIRK_R3DI)
+               chipio_set_conn_rate(codec, 0x0F, SR_96_000);
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x80, 0x01, tmp);
+}
+
+/*
+ * Sets the source of stream 0x14 to connpointID 0x48, and the destination
+ * connpointID to 0x91. If this isn't done, the destination is 0x71, and
+ * you get no sound. I'm guessing this has to do with the Sound Blaster Z
+ * having an updated DAC, which changes the destination to that DAC.
+ */
+static void sbz_connect_streams(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       codec_dbg(codec, "Connect Streams entered, mutex locked and loaded.\n");
+
+       /* This value is 0x43 for 96khz, and 0x83 for 192khz. */
+       chipio_write_no_mutex(codec, 0x18a020, 0x00000043);
+
+       /* Setup stream 0x14 with it's source and destination points */
+       chipio_set_stream_source_dest(codec, 0x14, 0x48, 0x91);
+       chipio_set_conn_rate_no_mutex(codec, 0x48, SR_96_000);
+       chipio_set_conn_rate_no_mutex(codec, 0x91, SR_96_000);
+       chipio_set_stream_channels(codec, 0x14, 2);
+       chipio_set_stream_control(codec, 0x14, 1);
+
+       codec_dbg(codec, "Connect Streams exited, mutex released.\n");
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+/*
+ * Write data through ChipIO to setup proper stream destinations.
+ * Not sure how it exactly works, but it seems to direct data
+ * to different destinations. Example is f8 to c0, e0 to c0.
+ * All I know is, if you don't set these, you get no sound.
+ */
+static void sbz_chipio_startup_data(struct hda_codec *codec)
+{
+       const struct chipio_stream_remap_data *dsp_out_remap_data;
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+       codec_dbg(codec, "Startup Data entered, mutex locked and loaded.\n");
+
+       /* Remap DAC0's output ports. */
+       chipio_remap_stream(codec, &stream_remap_data[0]);
+
+       /* Remap DSP audio output stream ports. */
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+               dsp_out_remap_data = &stream_remap_data[1];
+               break;
+
+       case QUIRK_ZXR:
+               dsp_out_remap_data = &stream_remap_data[2];
+               break;
+
+       default:
+               dsp_out_remap_data = NULL;
+               break;
+       }
+
+       if (dsp_out_remap_data)
+               chipio_remap_stream(codec, dsp_out_remap_data);
+
+       codec_dbg(codec, "Startup Data exited, mutex released.\n");
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+
+       chipio_set_stream_control(codec, 0x03, 0);
+       chipio_set_stream_control(codec, 0x04, 0);
+
+       chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
+       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
+
+       tmp = FLOAT_THREE;
+       dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+
+       chipio_set_stream_control(codec, 0x03, 1);
+       chipio_set_stream_control(codec, 0x04, 1);
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+               chipio_write(codec, 0x18b098, 0x0000000c);
+               chipio_write(codec, 0x18b09C, 0x0000000c);
+               break;
+       case QUIRK_AE5:
+               chipio_write(codec, 0x18b098, 0x0000000c);
+               chipio_write(codec, 0x18b09c, 0x0000004c);
+               break;
+       default:
+               break;
+       }
+}
+
+static void ae5_post_dsp_register_set(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       chipio_8051_write_direct(codec, 0x93, 0x10);
+       chipio_8051_write_pll_pmu(codec, 0x44, 0xc2);
+
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+       writeb(0x00, spec->mem_base + 0x100);
+       writeb(0xff, spec->mem_base + 0x304);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x3f);
+       ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+}
+
+static void ae5_post_dsp_param_setup(struct hda_codec *codec)
+{
+       /*
+        * Param3 in the 8051's memory is represented by the ascii string 'mch'
+        * which seems to be 'multichannel'. This is also mentioned in the
+        * AE-5's registry values in Windows.
+        */
+       chipio_set_control_param(codec, 3, 0);
+       /*
+        * I believe ASI is 'audio serial interface' and that it's used to
+        * change colors on the external LED strip connected to the AE-5.
+        */
+       chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83);
+       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+       chipio_8051_write_exram(codec, 0xfa92, 0x22);
+}
+
+static void ae5_post_dsp_pll_setup(struct hda_codec *codec)
+{
+       chipio_8051_write_pll_pmu(codec, 0x41, 0xc8);
+       chipio_8051_write_pll_pmu(codec, 0x45, 0xcc);
+       chipio_8051_write_pll_pmu(codec, 0x40, 0xcb);
+       chipio_8051_write_pll_pmu(codec, 0x43, 0xc7);
+       chipio_8051_write_pll_pmu(codec, 0x51, 0x8d);
+}
+
+static void ae5_post_dsp_stream_setup(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
+
+       chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000);
+
+       chipio_set_stream_source_dest(codec, 0x5, 0x43, 0x0);
+
+       chipio_set_stream_source_dest(codec, 0x18, 0x9, 0xd0);
+       chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
+       chipio_set_stream_channels(codec, 0x18, 6);
+       chipio_set_stream_control(codec, 0x18, 1);
+
+       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4);
+
+       chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7);
+
+       ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ae5_post_dsp_startup_data(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       chipio_write_no_mutex(codec, 0x189000, 0x0001f101);
+       chipio_write_no_mutex(codec, 0x189004, 0x0001f101);
+       chipio_write_no_mutex(codec, 0x189024, 0x00014004);
+       chipio_write_no_mutex(codec, 0x189028, 0x0002000f);
+
+       ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
+       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
+       ca0113_mmio_command_set(codec, 0x48, 0x0b, 0x12);
+       ca0113_mmio_command_set(codec, 0x48, 0x04, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x06, 0x48);
+       ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+       ca0113_mmio_gpio_set(codec, 0, true);
+       ca0113_mmio_gpio_set(codec, 1, true);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x80);
+
+       chipio_write_no_mutex(codec, 0x18b03c, 0x00000012);
+
+       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ae7_post_dsp_setup_ports(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       /* Seems to share the same port remapping as the SBZ. */
+       chipio_remap_stream(codec, &stream_remap_data[1]);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x0d, 0x40);
+       ca0113_mmio_command_set(codec, 0x48, 0x17, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x19, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x11, 0xff);
+       ca0113_mmio_command_set(codec, 0x48, 0x12, 0xff);
+       ca0113_mmio_command_set(codec, 0x48, 0x13, 0xff);
+       ca0113_mmio_command_set(codec, 0x48, 0x14, 0x7f);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ae7_post_dsp_asi_stream_setup(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
+       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
+
+       chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000);
+
+       chipio_set_stream_source_dest(codec, 0x05, 0x43, 0x00);
+       chipio_set_stream_source_dest(codec, 0x18, 0x09, 0xd0);
+
+       chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
+       chipio_set_stream_channels(codec, 0x18, 6);
+       chipio_set_stream_control(codec, 0x18, 1);
+
+       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+static void ae7_post_dsp_pll_setup(struct hda_codec *codec)
+{
+       static const unsigned int addr[] = {
+               0x41, 0x45, 0x40, 0x43, 0x51
+       };
+       static const unsigned int data[] = {
+               0xc8, 0xcc, 0xcb, 0xc7, 0x8d
+       };
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(addr); i++)
+               chipio_8051_write_pll_pmu_no_mutex(codec, addr[i], data[i]);
+}
+
+static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       static const unsigned int target[] = {
+               0x0b, 0x04, 0x06, 0x0a, 0x0c, 0x11, 0x12, 0x13, 0x14
+       };
+       static const unsigned int data[] = {
+               0x12, 0x00, 0x48, 0x05, 0x5f, 0xff, 0xff, 0xff, 0x7f
+       };
+       unsigned int i;
+
+       mutex_lock(&spec->chipio_mutex);
+
+       chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7);
+
+       chipio_write_no_mutex(codec, 0x189000, 0x0001f101);
+       chipio_write_no_mutex(codec, 0x189004, 0x0001f101);
+       chipio_write_no_mutex(codec, 0x189024, 0x00014004);
+       chipio_write_no_mutex(codec, 0x189028, 0x0002000f);
+
+       ae7_post_dsp_pll_setup(codec);
+       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
+
+       for (i = 0; i < ARRAY_SIZE(target); i++)
+               ca0113_mmio_command_set(codec, 0x48, target[i], data[i]);
+
+       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+
+       chipio_set_stream_source_dest(codec, 0x21, 0x64, 0x56);
+       chipio_set_stream_channels(codec, 0x21, 2);
+       chipio_set_conn_rate_no_mutex(codec, 0x56, SR_8_000);
+
+       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_NODE_ID, 0x09);
+       /*
+        * In the 8051's memory, this param is referred to as 'n2sid', which I
+        * believe is 'node to streamID'. It seems to be a way to assign a
+        * stream to a given HDA node.
+        */
+       chipio_set_control_param_no_mutex(codec, 0x20, 0x21);
+
+       chipio_write_no_mutex(codec, 0x18b038, 0x00000088);
+
+       /*
+        * Now, at this point on Windows, an actual stream is setup and
+        * seemingly sends data to the HDA node 0x09, which is the digital
+        * audio input node. This is left out here, because obviously I don't
+        * know what data is being sent. Interestingly, the AE-5 seems to go
+        * through the motions of getting here and never actually takes this
+        * step, but the AE-7 does.
+        */
+
+       ca0113_mmio_gpio_set(codec, 0, 1);
+       ca0113_mmio_gpio_set(codec, 1, 1);
+
+       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
+       chipio_write_no_mutex(codec, 0x18b03c, 0x00000000);
+       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
+       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
+
+       chipio_set_stream_source_dest(codec, 0x05, 0x43, 0x00);
+       chipio_set_stream_source_dest(codec, 0x18, 0x09, 0xd0);
+
+       chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
+       chipio_set_stream_channels(codec, 0x18, 6);
+
+       /*
+        * Runs again, this has been repeated a few times, but I'm just
+        * following what the Windows driver does.
+        */
+       ae7_post_dsp_pll_setup(codec);
+       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
+
+       mutex_unlock(&spec->chipio_mutex);
+}
+
+/*
+ * The Windows driver has commands that seem to setup ASI, which I believe to
+ * be some sort of audio serial interface. My current speculation is that it's
+ * related to communicating with the new DAC.
+ */
+static void ae7_post_dsp_asi_setup(struct hda_codec *codec)
+{
+       chipio_8051_write_direct(codec, 0x93, 0x10);
+
+       chipio_8051_write_pll_pmu(codec, 0x44, 0xc2);
+
+       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
+
+       chipio_set_control_param(codec, 3, 3);
+       chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83);
+       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+       snd_hda_codec_write(codec, 0x17, 0, 0x794, 0x00);
+
+       chipio_8051_write_exram(codec, 0xfa92, 0x22);
+
+       ae7_post_dsp_pll_setup(codec);
+       ae7_post_dsp_asi_stream_setup(codec);
+
+       chipio_8051_write_pll_pmu(codec, 0x43, 0xc7);
+
+       ae7_post_dsp_asi_setup_ports(codec);
+}
+
+/*
+ * Setup default parameters for DSP
+ */
+static void ca0132_setup_defaults(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+       int num_fx;
+       int idx, i;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return;
+
+       /* out, in effects + voicefx */
+       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
+       for (idx = 0; idx < num_fx; idx++) {
+               for (i = 0; i <= ca0132_effects[idx].params; i++) {
+                       dspio_set_uint_param(codec, ca0132_effects[idx].mid,
+                                            ca0132_effects[idx].reqs[i],
+                                            ca0132_effects[idx].def_vals[i]);
+               }
+       }
+
+       /*remove DSP headroom*/
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
+
+       /*set speaker EQ bypass attenuation*/
+       dspio_set_uint_param(codec, 0x8f, 0x01, tmp);
+
+       /* set AMic1 and AMic2 as mono mic */
+       tmp = FLOAT_ONE;
+       dspio_set_uint_param(codec, 0x80, 0x00, tmp);
+       dspio_set_uint_param(codec, 0x80, 0x01, tmp);
+
+       /* set AMic1 as CrystalVoice input */
+       tmp = FLOAT_ONE;
+       dspio_set_uint_param(codec, 0x80, 0x05, tmp);
+
+       /* set WUH source */
+       tmp = FLOAT_TWO;
+       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
+}
+
+/*
+ * Setup default parameters for Recon3D/Recon3Di DSP.
+ */
+
+static void r3d_setup_defaults(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+       int num_fx;
+       int idx, i;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return;
+
+       ca0132_alt_init_analog_mics(codec);
+       ca0132_alt_start_dsp_audio_streams(codec);
+
+       /*remove DSP headroom*/
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
+
+       /* set WUH source */
+       tmp = FLOAT_TWO;
+       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
+       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+
+       /* Set speaker source? */
+       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
+
+       if (ca0132_quirk(spec) == QUIRK_R3DI)
+               r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED);
+
+       /* Disable mute on Center/LFE. */
+       if (ca0132_quirk(spec) == QUIRK_R3D) {
+               ca0113_mmio_gpio_set(codec, 2, false);
+               ca0113_mmio_gpio_set(codec, 4, true);
+       }
+
+       /* Setup effect defaults */
+       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
+       for (idx = 0; idx < num_fx; idx++) {
+               for (i = 0; i <= ca0132_effects[idx].params; i++) {
+                       dspio_set_uint_param(codec,
+                                       ca0132_effects[idx].mid,
+                                       ca0132_effects[idx].reqs[i],
+                                       ca0132_effects[idx].def_vals[i]);
+               }
+       }
+}
+
+/*
+ * Setup default parameters for the Sound Blaster Z DSP. A lot more going on
+ * than the Chromebook setup.
+ */
+static void sbz_setup_defaults(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+       int num_fx;
+       int idx, i;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return;
+
+       ca0132_alt_init_analog_mics(codec);
+       ca0132_alt_start_dsp_audio_streams(codec);
+       sbz_connect_streams(codec);
+       sbz_chipio_startup_data(codec);
+
+       /*
+        * Sets internal input loopback to off, used to have a switch to
+        * enable input loopback, but turned out to be way too buggy.
+        */
+       tmp = FLOAT_ONE;
+       dspio_set_uint_param(codec, 0x37, 0x08, tmp);
+       dspio_set_uint_param(codec, 0x37, 0x10, tmp);
+
+       /*remove DSP headroom*/
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
+
+       /* set WUH source */
+       tmp = FLOAT_TWO;
+       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
+       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+
+       /* Set speaker source? */
+       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
+
+       ca0132_alt_dsp_initial_mic_setup(codec);
+
+       /* out, in effects + voicefx */
+       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
+       for (idx = 0; idx < num_fx; idx++) {
+               for (i = 0; i <= ca0132_effects[idx].params; i++) {
+                       dspio_set_uint_param(codec,
+                                       ca0132_effects[idx].mid,
+                                       ca0132_effects[idx].reqs[i],
+                                       ca0132_effects[idx].def_vals[i]);
+               }
+       }
+
+       ca0132_alt_init_speaker_tuning(codec);
+}
+
+/*
+ * Setup default parameters for the Sound BlasterX AE-5 DSP.
+ */
+static void ae5_setup_defaults(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+       int num_fx;
+       int idx, i;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return;
+
+       ca0132_alt_init_analog_mics(codec);
+       ca0132_alt_start_dsp_audio_streams(codec);
+
+       /* New, unknown SCP req's */
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, 0x29, tmp);
+       dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
+       dspio_set_uint_param(codec, 0x80, 0x0d, tmp);
+       dspio_set_uint_param(codec, 0x80, 0x0e, tmp);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
+
+       /* Internal loopback off */
+       tmp = FLOAT_ONE;
+       dspio_set_uint_param(codec, 0x37, 0x08, tmp);
+       dspio_set_uint_param(codec, 0x37, 0x10, tmp);
+
+       /*remove DSP headroom*/
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
+
+       /* set WUH source */
+       tmp = FLOAT_TWO;
+       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
+       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+
+       /* Set speaker source? */
+       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
+
+       ca0132_alt_dsp_initial_mic_setup(codec);
+       ae5_post_dsp_register_set(codec);
+       ae5_post_dsp_param_setup(codec);
+       ae5_post_dsp_pll_setup(codec);
+       ae5_post_dsp_stream_setup(codec);
+       ae5_post_dsp_startup_data(codec);
+
+       /* out, in effects + voicefx */
+       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
+       for (idx = 0; idx < num_fx; idx++) {
+               for (i = 0; i <= ca0132_effects[idx].params; i++) {
+                       dspio_set_uint_param(codec,
+                                       ca0132_effects[idx].mid,
+                                       ca0132_effects[idx].reqs[i],
+                                       ca0132_effects[idx].def_vals[i]);
+               }
+       }
+
+       ca0132_alt_init_speaker_tuning(codec);
+}
+
+/*
+ * Setup default parameters for the Sound Blaster AE-7 DSP.
+ */
+static void ae7_setup_defaults(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp;
+       int num_fx;
+       int idx, i;
+
+       if (spec->dsp_state != DSP_DOWNLOADED)
+               return;
+
+       ca0132_alt_init_analog_mics(codec);
+       ca0132_alt_start_dsp_audio_streams(codec);
+       ae7_post_dsp_setup_ports(codec);
+
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96,
+                       SPEAKER_TUNING_FRONT_LEFT_INVERT, tmp);
+       dspio_set_uint_param(codec, 0x96,
+                       SPEAKER_TUNING_FRONT_RIGHT_INVERT, tmp);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
+
+       /* New, unknown SCP req's */
+       dspio_set_uint_param(codec, 0x80, 0x0d, tmp);
+       dspio_set_uint_param(codec, 0x80, 0x0e, tmp);
+
+       ca0113_mmio_gpio_set(codec, 0, false);
+
+       /* Internal loopback off */
+       tmp = FLOAT_ONE;
+       dspio_set_uint_param(codec, 0x37, 0x08, tmp);
+       dspio_set_uint_param(codec, 0x37, 0x10, tmp);
+
+       /*remove DSP headroom*/
+       tmp = FLOAT_ZERO;
+       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
+
+       /* set WUH source */
+       tmp = FLOAT_TWO;
+       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
+       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+
+       /* Set speaker source? */
+       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
+       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
+
+       /*
+        * This is the second time we've called this, but this is seemingly
+        * what Windows does.
+        */
+       ca0132_alt_init_analog_mics(codec);
+
+       ae7_post_dsp_asi_setup(codec);
+
+       /*
+        * Not sure why, but these are both set to 1. They're only set to 0
+        * upon shutdown.
+        */
+       ca0113_mmio_gpio_set(codec, 0, true);
+       ca0113_mmio_gpio_set(codec, 1, true);
+
+       /* Volume control related. */
+       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x04);
+       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x04);
+       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x80);
+
+       /* out, in effects + voicefx */
+       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
+       for (idx = 0; idx < num_fx; idx++) {
+               for (i = 0; i <= ca0132_effects[idx].params; i++) {
+                       dspio_set_uint_param(codec,
+                                       ca0132_effects[idx].mid,
+                                       ca0132_effects[idx].reqs[i],
+                                       ca0132_effects[idx].def_vals[i]);
+               }
+       }
+
+       ca0132_alt_init_speaker_tuning(codec);
+}
+
+/*
+ * Initialization of flags in chip
+ */
+static void ca0132_init_flags(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       if (ca0132_use_alt_functions(spec)) {
+               chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, 1);
+               chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, 1);
+               chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, 1);
+               chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_96KHZ, 1);
+               chipio_set_control_flag(codec, CONTROL_FLAG_SRC_RATE_96KHZ, 1);
+               chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0);
+               chipio_set_control_flag(codec, CONTROL_FLAG_SPDIF2OUT, 0);
+               chipio_set_control_flag(codec,
+                               CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0);
+               chipio_set_control_flag(codec,
+                               CONTROL_FLAG_PORT_A_10KOHM_LOAD, 1);
+       } else {
+               chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0);
+               chipio_set_control_flag(codec,
+                               CONTROL_FLAG_PORT_A_COMMON_MODE, 0);
+               chipio_set_control_flag(codec,
+                               CONTROL_FLAG_PORT_D_COMMON_MODE, 0);
+               chipio_set_control_flag(codec,
+                               CONTROL_FLAG_PORT_A_10KOHM_LOAD, 0);
+               chipio_set_control_flag(codec,
+                               CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0);
+               chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_HIGH_PASS, 1);
+       }
+}
+
+/*
+ * Initialization of parameters in chip
+ */
+static void ca0132_init_params(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       if (ca0132_use_alt_functions(spec)) {
+               chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+               chipio_set_conn_rate(codec, 0x0B, SR_48_000);
+               chipio_set_control_param(codec, CONTROL_PARAM_SPDIF1_SOURCE, 0);
+               chipio_set_control_param(codec, 0, 0);
+               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0);
+       }
+
+       chipio_set_control_param(codec, CONTROL_PARAM_PORTA_160OHM_GAIN, 6);
+       chipio_set_control_param(codec, CONTROL_PARAM_PORTD_160OHM_GAIN, 6);
+}
+
+static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k)
+{
+       chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, is96k);
+       chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, is96k);
+       chipio_set_control_flag(codec, CONTROL_FLAG_SRC_RATE_96KHZ, is96k);
+       chipio_set_control_flag(codec, CONTROL_FLAG_SRC_CLOCK_196MHZ, is96k);
+       chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, is96k);
+       chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_96KHZ, is96k);
+
+       chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
+       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
+       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
+}
+
+static bool ca0132_download_dsp_images(struct hda_codec *codec)
+{
+       bool dsp_loaded = false;
+       struct ca0132_spec *spec = codec->spec;
+       const struct dsp_image_seg *dsp_os_image;
+       const struct firmware *fw_entry = NULL;
+       /*
+        * Alternate firmwares for different variants. The Recon3Di apparently
+        * can use the default firmware, but I'll leave the option in case
+        * it needs it again.
+        */
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+       case QUIRK_R3D:
+       case QUIRK_AE5:
+               if (request_firmware(&fw_entry, DESKTOP_EFX_FILE,
+                                       codec->card->dev) != 0)
+                       codec_dbg(codec, "Desktop firmware not found.");
+               else
+                       codec_dbg(codec, "Desktop firmware selected.");
+               break;
+       case QUIRK_R3DI:
+               if (request_firmware(&fw_entry, R3DI_EFX_FILE,
+                                       codec->card->dev) != 0)
+                       codec_dbg(codec, "Recon3Di alt firmware not detected.");
+               else
+                       codec_dbg(codec, "Recon3Di firmware selected.");
+               break;
+       default:
+               break;
+       }
+       /*
+        * Use default ctefx.bin if no alt firmware is detected, or if none
+        * exists for your particular codec.
+        */
+       if (!fw_entry) {
+               codec_dbg(codec, "Default firmware selected.");
+               if (request_firmware(&fw_entry, EFX_FILE,
+                                       codec->card->dev) != 0)
+                       return false;
+       }
+
+       dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
+       if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) {
+               codec_err(codec, "ca0132 DSP load image failed\n");
+               goto exit_download;
+       }
+
+       dsp_loaded = dspload_wait_loaded(codec);
+
+exit_download:
+       release_firmware(fw_entry);
+
+       return dsp_loaded;
+}
+
+static void ca0132_download_dsp(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+#ifndef CONFIG_SND_HDA_CODEC_CA0132_DSP
+       return; /* NOP */
+#endif
+
+       if (spec->dsp_state == DSP_DOWNLOAD_FAILED)
+               return; /* don't retry failures */
+
+       chipio_enable_clocks(codec);
+       if (spec->dsp_state != DSP_DOWNLOADED) {
+               spec->dsp_state = DSP_DOWNLOADING;
+
+               if (!ca0132_download_dsp_images(codec))
+                       spec->dsp_state = DSP_DOWNLOAD_FAILED;
+               else
+                       spec->dsp_state = DSP_DOWNLOADED;
+       }
+
+       /* For codecs using alt functions, this is already done earlier */
+       if (spec->dsp_state == DSP_DOWNLOADED && !ca0132_use_alt_functions(spec))
+               ca0132_set_dsp_msr(codec, true);
+}
+
+static void ca0132_process_dsp_response(struct hda_codec *codec,
+                                       struct hda_jack_callback *callback)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       codec_dbg(codec, "ca0132_process_dsp_response\n");
+       snd_hda_power_up_pm(codec);
+       if (spec->wait_scp) {
+               if (dspio_get_response_data(codec) >= 0)
+                       spec->wait_scp = 0;
+       }
+
+       dspio_clear_response_queue(codec);
+       snd_hda_power_down_pm(codec);
+}
+
+static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct hda_jack_tbl *tbl;
+
+       /* Delay enabling the HP amp, to let the mic-detection
+        * state machine run.
+        */
+       tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+       if (tbl)
+               tbl->block_report = 1;
+       schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
+}
+
+static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       if (ca0132_use_alt_functions(spec))
+               ca0132_alt_select_in(codec);
+       else
+               ca0132_select_mic(codec);
+}
+
+static void ca0132_setup_unsol(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_hp, hp_callback);
+       snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_amic1,
+                                           amic_callback);
+       snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
+                                           ca0132_process_dsp_response);
+       /* Front headphone jack detection */
+       if (ca0132_use_alt_functions(spec))
+               snd_hda_jack_detect_enable_callback(codec,
+                       spec->unsol_tag_front_hp, hp_callback);
+}
+
+/*
+ * Verbs tables.
+ */
+
+/* Sends before DSP download. */
+static const struct hda_verb ca0132_base_init_verbs[] = {
+       /*enable ct extension*/
+       {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x1},
+       {}
+};
+
+/* Send at exit. */
+static const struct hda_verb ca0132_base_exit_verbs[] = {
+       /*set afg to D3*/
+       {0x01, AC_VERB_SET_POWER_STATE, 0x03},
+       /*disable ct extension*/
+       {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0},
+       {}
+};
+
+/* Other verbs tables. Sends after DSP download. */
+
+static const struct hda_verb ca0132_init_verbs0[] = {
+       /* chip init verbs */
+       {0x15, 0x70D, 0xF0},
+       {0x15, 0x70E, 0xFE},
+       {0x15, 0x707, 0x75},
+       {0x15, 0x707, 0xD3},
+       {0x15, 0x707, 0x09},
+       {0x15, 0x707, 0x53},
+       {0x15, 0x707, 0xD4},
+       {0x15, 0x707, 0xEF},
+       {0x15, 0x707, 0x75},
+       {0x15, 0x707, 0xD3},
+       {0x15, 0x707, 0x09},
+       {0x15, 0x707, 0x02},
+       {0x15, 0x707, 0x37},
+       {0x15, 0x707, 0x78},
+       {0x15, 0x53C, 0xCE},
+       {0x15, 0x575, 0xC9},
+       {0x15, 0x53D, 0xCE},
+       {0x15, 0x5B7, 0xC9},
+       {0x15, 0x70D, 0xE8},
+       {0x15, 0x70E, 0xFE},
+       {0x15, 0x707, 0x02},
+       {0x15, 0x707, 0x68},
+       {0x15, 0x707, 0x62},
+       {0x15, 0x53A, 0xCE},
+       {0x15, 0x546, 0xC9},
+       {0x15, 0x53B, 0xCE},
+       {0x15, 0x5E8, 0xC9},
+       {}
+};
+
+/* Extra init verbs for desktop cards. */
+static const struct hda_verb ca0132_init_verbs1[] = {
+       {0x15, 0x70D, 0x20},
+       {0x15, 0x70E, 0x19},
+       {0x15, 0x707, 0x00},
+       {0x15, 0x539, 0xCE},
+       {0x15, 0x546, 0xC9},
+       {0x15, 0x70D, 0xB7},
+       {0x15, 0x70E, 0x09},
+       {0x15, 0x707, 0x10},
+       {0x15, 0x70D, 0xAF},
+       {0x15, 0x70E, 0x09},
+       {0x15, 0x707, 0x01},
+       {0x15, 0x707, 0x05},
+       {0x15, 0x70D, 0x73},
+       {0x15, 0x70E, 0x09},
+       {0x15, 0x707, 0x14},
+       {0x15, 0x6FF, 0xC4},
+       {}
+};
+
+static void ca0132_init_chip(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       int num_fx;
+       int i;
+       unsigned int on;
+
+       mutex_init(&spec->chipio_mutex);
+
+       /*
+        * The Windows driver always does this upon startup, which seems to
+        * clear out any previous configuration. This should help issues where
+        * a boot into Windows prior to a boot into Linux breaks things. Also,
+        * Windows always sends the reset twice.
+        */
+       if (ca0132_use_alt_functions(spec)) {
+               chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0);
+               chipio_write_no_mutex(codec, 0x18b0a4, 0x000000c2);
+
+               snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_SET_CODEC_RESET, 0);
+               snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_SET_CODEC_RESET, 0);
+       }
+
+       spec->cur_out_type = SPEAKER_OUT;
+       if (!ca0132_use_alt_functions(spec))
+               spec->cur_mic_type = DIGITAL_MIC;
+       else
+               spec->cur_mic_type = REAR_MIC;
+
+       spec->cur_mic_boost = 0;
+
+       for (i = 0; i < VNODES_COUNT; i++) {
+               spec->vnode_lvol[i] = 0x5a;
+               spec->vnode_rvol[i] = 0x5a;
+               spec->vnode_lswitch[i] = 0;
+               spec->vnode_rswitch[i] = 0;
+       }
+
+       /*
+        * Default states for effects are in ca0132_effects[].
+        */
+       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
+       for (i = 0; i < num_fx; i++) {
+               on = (unsigned int)ca0132_effects[i].reqs[0];
+               spec->effects_switch[i] = on ? 1 : 0;
+       }
+       /*
+        * Sets defaults for the effect slider controls, only for alternative
+        * ca0132 codecs. Also sets x-bass crossover frequency to 80hz.
+        */
+       if (ca0132_use_alt_controls(spec)) {
+               /* Set speakers to default to full range. */
+               spec->speaker_range_val[0] = 1;
+               spec->speaker_range_val[1] = 1;
+
+               spec->xbass_xover_freq = 8;
+               for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++)
+                       spec->fx_ctl_val[i] = effect_slider_defaults[i];
+
+               spec->bass_redirect_xover_freq = 8;
+       }
+
+       spec->voicefx_val = 0;
+       spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1;
+       spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0;
+
+       /*
+        * The ZxR doesn't have a front panel header, and it's line-in is on
+        * the daughter board. So, there is no input enum control, and we need
+        * to make sure that spec->in_enum_val is set properly.
+        */
+       if (ca0132_quirk(spec) == QUIRK_ZXR)
+               spec->in_enum_val = REAR_MIC;
+
+#ifdef ENABLE_TUNING_CONTROLS
+       ca0132_init_tuning_defaults(codec);
+#endif
+}
+
+/*
+ * Recon3Di exit specific commands.
+ */
+/* prevents popping noise on shutdown */
+static void r3di_gpio_shutdown(struct hda_codec *codec)
+{
+       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0x00);
+}
+
+/*
+ * Sound Blaster Z exit specific commands.
+ */
+static void sbz_region2_exit(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int i;
+
+       for (i = 0; i < 4; i++)
+               writeb(0x0, spec->mem_base + 0x100);
+       for (i = 0; i < 8; i++)
+               writeb(0xb3, spec->mem_base + 0x304);
+
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_gpio_set(codec, 1, false);
+       ca0113_mmio_gpio_set(codec, 4, true);
+       ca0113_mmio_gpio_set(codec, 5, false);
+       ca0113_mmio_gpio_set(codec, 7, false);
+}
+
+static void sbz_set_pin_ctl_default(struct hda_codec *codec)
+{
+       static const hda_nid_t pins[] = {0x0B, 0x0C, 0x0E, 0x12, 0x13};
+       unsigned int i;
+
+       snd_hda_codec_write(codec, 0x11, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
+
+       for (i = 0; i < ARRAY_SIZE(pins); i++)
+               snd_hda_codec_write(codec, pins[i], 0,
+                               AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
+}
+
+static void ca0132_clear_unsolicited(struct hda_codec *codec)
+{
+       static const hda_nid_t pins[] = {0x0B, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13};
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(pins); i++) {
+               snd_hda_codec_write(codec, pins[i], 0,
+                               AC_VERB_SET_UNSOLICITED_ENABLE, 0x00);
+       }
+}
+
+/* On shutdown, sends commands in sets of three */
+static void sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir,
+                                                       int mask, int data)
+{
+       if (dir >= 0)
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_DIRECTION, dir);
+       if (mask >= 0)
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_MASK, mask);
+
+       if (data >= 0)
+               snd_hda_codec_write(codec, 0x01, 0,
+                               AC_VERB_SET_GPIO_DATA, data);
+}
+
+static void zxr_dbpro_power_state_shutdown(struct hda_codec *codec)
+{
+       static const hda_nid_t pins[] = {0x05, 0x0c, 0x09, 0x0e, 0x08, 0x11, 0x01};
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(pins); i++)
+               snd_hda_codec_write(codec, pins[i], 0,
+                               AC_VERB_SET_POWER_STATE, 0x03);
+}
+
+static void sbz_exit_chip(struct hda_codec *codec)
+{
+       chipio_set_stream_control(codec, 0x03, 0);
+       chipio_set_stream_control(codec, 0x04, 0);
+
+       /* Mess with GPIO */
+       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, -1);
+       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x05);
+       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x01);
+
+       chipio_set_stream_control(codec, 0x14, 0);
+       chipio_set_stream_control(codec, 0x0C, 0);
+
+       chipio_set_conn_rate(codec, 0x41, SR_192_000);
+       chipio_set_conn_rate(codec, 0x91, SR_192_000);
+
+       chipio_write(codec, 0x18a020, 0x00000083);
+
+       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x03);
+       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x07);
+       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x06);
+
+       chipio_set_stream_control(codec, 0x0C, 0);
+
+       chipio_set_control_param(codec, 0x0D, 0x24);
+
+       ca0132_clear_unsolicited(codec);
+       sbz_set_pin_ctl_default(codec);
+
+       snd_hda_codec_write(codec, 0x0B, 0,
+               AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+
+       sbz_region2_exit(codec);
+}
+
+static void r3d_exit_chip(struct hda_codec *codec)
+{
+       ca0132_clear_unsolicited(codec);
+       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b);
+}
+
+static void ae5_exit_chip(struct hda_codec *codec)
+{
+       chipio_set_stream_control(codec, 0x03, 0);
+       chipio_set_stream_control(codec, 0x04, 0);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
+       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
+       ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x00);
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_gpio_set(codec, 1, false);
+
+       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+
+       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+       chipio_set_stream_control(codec, 0x18, 0);
+       chipio_set_stream_control(codec, 0x0c, 0);
+
+       snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83);
+}
+
+static void ae7_exit_chip(struct hda_codec *codec)
+{
+       chipio_set_stream_control(codec, 0x18, 0);
+       chipio_set_stream_source_dest(codec, 0x21, 0xc8, 0xc8);
+       chipio_set_stream_channels(codec, 0x21, 0);
+       chipio_set_control_param(codec, CONTROL_PARAM_NODE_ID, 0x09);
+       chipio_set_control_param(codec, 0x20, 0x01);
+
+       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
+
+       chipio_set_stream_control(codec, 0x18, 0);
+       chipio_set_stream_control(codec, 0x0c, 0);
+
+       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
+       snd_hda_codec_write(codec, 0x15, 0, 0x724, 0x83);
+       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
+       ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
+       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x00);
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_gpio_set(codec, 1, false);
+       ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+
+       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+}
+
+static void zxr_exit_chip(struct hda_codec *codec)
+{
+       chipio_set_stream_control(codec, 0x03, 0);
+       chipio_set_stream_control(codec, 0x04, 0);
+       chipio_set_stream_control(codec, 0x14, 0);
+       chipio_set_stream_control(codec, 0x0C, 0);
+
+       chipio_set_conn_rate(codec, 0x41, SR_192_000);
+       chipio_set_conn_rate(codec, 0x91, SR_192_000);
+
+       chipio_write(codec, 0x18a020, 0x00000083);
+
+       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
+       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
+
+       ca0132_clear_unsolicited(codec);
+       sbz_set_pin_ctl_default(codec);
+       snd_hda_codec_write(codec, 0x0B, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00);
+
+       ca0113_mmio_gpio_set(codec, 5, false);
+       ca0113_mmio_gpio_set(codec, 2, false);
+       ca0113_mmio_gpio_set(codec, 3, false);
+       ca0113_mmio_gpio_set(codec, 0, false);
+       ca0113_mmio_gpio_set(codec, 4, true);
+       ca0113_mmio_gpio_set(codec, 0, true);
+       ca0113_mmio_gpio_set(codec, 5, true);
+       ca0113_mmio_gpio_set(codec, 2, false);
+       ca0113_mmio_gpio_set(codec, 3, false);
+}
+
+static void ca0132_exit_chip(struct hda_codec *codec)
+{
+       /* put any chip cleanup stuffs here. */
+
+       if (dspload_is_loaded(codec))
+               dsp_reset(codec);
+}
+
+/*
+ * This fixes a problem that was hard to reproduce. Very rarely, I would
+ * boot up, and there would be no sound, but the DSP indicated it had loaded
+ * properly. I did a few memory dumps to see if anything was different, and
+ * there were a few areas of memory uninitialized with a1a2a3a4. This function
+ * checks if those areas are uninitialized, and if they are, it'll attempt to
+ * reload the card 3 times. Usually it fixes by the second.
+ */
+static void sbz_dsp_startup_check(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int dsp_data_check[4];
+       unsigned int cur_address = 0x390;
+       unsigned int i;
+       unsigned int failure = 0;
+       unsigned int reload = 3;
+
+       if (spec->startup_check_entered)
+               return;
+
+       spec->startup_check_entered = true;
+
+       for (i = 0; i < 4; i++) {
+               chipio_read(codec, cur_address, &dsp_data_check[i]);
+               cur_address += 0x4;
+       }
+       for (i = 0; i < 4; i++) {
+               if (dsp_data_check[i] == 0xa1a2a3a4)
+                       failure = 1;
+       }
+
+       codec_dbg(codec, "Startup Check: %d ", failure);
+       if (failure)
+               codec_info(codec, "DSP not initialized properly. Attempting to fix.");
+       /*
+        * While the failure condition is true, and we haven't reached our
+        * three reload limit, continue trying to reload the driver and
+        * fix the issue.
+        */
+       while (failure && (reload != 0)) {
+               codec_info(codec, "Reloading... Tries left: %d", reload);
+               sbz_exit_chip(codec);
+               spec->dsp_state = DSP_DOWNLOAD_INIT;
+               codec->patch_ops.init(codec);
+               failure = 0;
+               for (i = 0; i < 4; i++) {
+                       chipio_read(codec, cur_address, &dsp_data_check[i]);
+                       cur_address += 0x4;
+               }
+               for (i = 0; i < 4; i++) {
+                       if (dsp_data_check[i] == 0xa1a2a3a4)
+                               failure = 1;
+               }
+               reload--;
+       }
+
+       if (!failure && reload < 3)
+               codec_info(codec, "DSP fixed.");
+
+       if (!failure)
+               return;
+
+       codec_info(codec, "DSP failed to initialize properly. Either try a full shutdown or a suspend to clear the internal memory.");
+}
+
+/*
+ * This is for the extra volume verbs 0x797 (left) and 0x798 (right). These add
+ * extra precision for decibel values. If you had the dB value in floating point
+ * you would take the value after the decimal point, multiply by 64, and divide
+ * by 2. So for 8.59, it's (59 * 64) / 100. Useful if someone wanted to
+ * implement fixed point or floating point dB volumes. For now, I'll set them
+ * to 0 just incase a value has lingered from a boot into Windows.
+ */
+static void ca0132_alt_vol_setup(struct hda_codec *codec)
+{
+       snd_hda_codec_write(codec, 0x02, 0, 0x797, 0x00);
+       snd_hda_codec_write(codec, 0x02, 0, 0x798, 0x00);
+       snd_hda_codec_write(codec, 0x03, 0, 0x797, 0x00);
+       snd_hda_codec_write(codec, 0x03, 0, 0x798, 0x00);
+       snd_hda_codec_write(codec, 0x04, 0, 0x797, 0x00);
+       snd_hda_codec_write(codec, 0x04, 0, 0x798, 0x00);
+       snd_hda_codec_write(codec, 0x07, 0, 0x797, 0x00);
+       snd_hda_codec_write(codec, 0x07, 0, 0x798, 0x00);
+}
+
+/*
+ * Extra commands that don't really fit anywhere else.
+ */
+static void sbz_pre_dsp_setup(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       writel(0x00820680, spec->mem_base + 0x01C);
+       writel(0x00820680, spec->mem_base + 0x01C);
+
+       chipio_write(codec, 0x18b0a4, 0x000000c2);
+
+       snd_hda_codec_write(codec, 0x11, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44);
+}
+
+static void r3d_pre_dsp_setup(struct hda_codec *codec)
+{
+       chipio_write(codec, 0x18b0a4, 0x000000c2);
+
+       chipio_8051_write_exram(codec, 0x1c1e, 0x5b);
+
+       snd_hda_codec_write(codec, 0x11, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44);
+}
+
+static void r3di_pre_dsp_setup(struct hda_codec *codec)
+{
+       chipio_write(codec, 0x18b0a4, 0x000000c2);
+
+       chipio_8051_write_exram(codec, 0x1c1e, 0x5b);
+       chipio_8051_write_exram(codec, 0x1920, 0x00);
+       chipio_8051_write_exram(codec, 0x1921, 0x40);
+
+       snd_hda_codec_write(codec, 0x11, 0,
+                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x04);
+}
+
+/*
+ * The ZxR seems to use alternative DAC's for the surround channels, which
+ * require PLL PMU setup for the clock rate, I'm guessing. Without setting
+ * this up, we get no audio out of the surround jacks.
+ */
+static void zxr_pre_dsp_setup(struct hda_codec *codec)
+{
+       static const unsigned int addr[] = { 0x43, 0x40, 0x41, 0x42, 0x45 };
+       static const unsigned int data[] = { 0x08, 0x0c, 0x0b, 0x07, 0x0d };
+       unsigned int i;
+
+       chipio_write(codec, 0x189000, 0x0001f100);
+       msleep(50);
+       chipio_write(codec, 0x18900c, 0x0001f100);
+       msleep(50);
+
+       /*
+        * This writes a RET instruction at the entry point of the function at
+        * 0xfa92 in exram. This function seems to have something to do with
+        * ASI. Might be some way to prevent the card from reconfiguring the
+        * ASI stuff itself.
+        */
+       chipio_8051_write_exram(codec, 0xfa92, 0x22);
+
+       chipio_8051_write_pll_pmu(codec, 0x51, 0x98);
+
+       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x82);
+       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 3);
+
+       chipio_write(codec, 0x18902c, 0x00000000);
+       msleep(50);
+       chipio_write(codec, 0x18902c, 0x00000003);
+       msleep(50);
+
+       for (i = 0; i < ARRAY_SIZE(addr); i++)
+               chipio_8051_write_pll_pmu(codec, addr[i], data[i]);
+}
+
+/*
+ * These are sent before the DSP is downloaded. Not sure
+ * what they do, or if they're necessary. Could possibly
+ * be removed. Figure they're better to leave in.
+ */
+static const unsigned int ca0113_mmio_init_address_sbz[] = {
+       0x400, 0x408, 0x40c, 0x01c, 0xc0c, 0xc00, 0xc04, 0xc0c, 0xc0c, 0xc0c,
+       0xc0c, 0xc08, 0xc08, 0xc08, 0xc08, 0xc08, 0xc04
+};
+
+static const unsigned int ca0113_mmio_init_data_sbz[] = {
+       0x00000030, 0x00000000, 0x00000003, 0x00000003, 0x00000003,
+       0x00000003, 0x000000c1, 0x000000f1, 0x00000001, 0x000000c7,
+       0x000000c1, 0x00000080
+};
+
+static const unsigned int ca0113_mmio_init_data_zxr[] = {
+       0x00000030, 0x00000000, 0x00000000, 0x00000003, 0x00000003,
+       0x00000003, 0x00000001, 0x000000f1, 0x00000001, 0x000000c7,
+       0x000000c1, 0x00000080
+};
+
+static const unsigned int ca0113_mmio_init_address_ae5[] = {
+       0x400, 0x42c, 0x46c, 0x4ac, 0x4ec, 0x43c, 0x47c, 0x4bc, 0x4fc, 0x408,
+       0x100, 0x410, 0x40c, 0x100, 0x100, 0x830, 0x86c, 0x800, 0x86c, 0x800,
+       0x804, 0x20c, 0x01c, 0xc0c, 0xc00, 0xc04, 0xc0c, 0xc0c, 0xc0c, 0xc0c,
+       0xc08, 0xc08, 0xc08, 0xc08, 0xc08, 0xc04, 0x01c
+};
+
+static const unsigned int ca0113_mmio_init_data_ae5[] = {
+       0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
+       0x00000600, 0x00000014, 0x00000001, 0x0000060f, 0x0000070f,
+       0x00000aff, 0x00000000, 0x0000006b, 0x00000001, 0x0000006b,
+       0x00000057, 0x00800000, 0x00880680, 0x00000080, 0x00000030,
+       0x00000000, 0x00000000, 0x00000003, 0x00000003, 0x00000003,
+       0x00000001, 0x000000f1, 0x00000001, 0x000000c7, 0x000000c1,
+       0x00000080, 0x00880680
+};
+
+static void ca0132_mmio_init_sbz(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int tmp[2], i, count, cur_addr;
+       const unsigned int *addr, *data;
+
+       addr = ca0113_mmio_init_address_sbz;
+       for (i = 0; i < 3; i++)
+               writel(0x00000000, spec->mem_base + addr[i]);
+
+       cur_addr = i;
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_ZXR:
+               tmp[0] = 0x00880480;
+               tmp[1] = 0x00000080;
+               break;
+       case QUIRK_SBZ:
+               tmp[0] = 0x00820680;
+               tmp[1] = 0x00000083;
+               break;
+       case QUIRK_R3D:
+               tmp[0] = 0x00880680;
+               tmp[1] = 0x00000083;
+               break;
+       default:
+               tmp[0] = 0x00000000;
+               tmp[1] = 0x00000000;
+               break;
+       }
+
+       for (i = 0; i < 2; i++)
+               writel(tmp[i], spec->mem_base + addr[cur_addr + i]);
+
+       cur_addr += i;
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_ZXR:
+               count = ARRAY_SIZE(ca0113_mmio_init_data_zxr);
+               data = ca0113_mmio_init_data_zxr;
+               break;
+       default:
+               count = ARRAY_SIZE(ca0113_mmio_init_data_sbz);
+               data = ca0113_mmio_init_data_sbz;
+               break;
+       }
+
+       for (i = 0; i < count; i++)
+               writel(data[i], spec->mem_base + addr[cur_addr + i]);
+}
+
+static void ca0132_mmio_init_ae5(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       const unsigned int *addr, *data;
+       unsigned int i, count;
+
+       addr = ca0113_mmio_init_address_ae5;
+       data = ca0113_mmio_init_data_ae5;
+       count = ARRAY_SIZE(ca0113_mmio_init_data_ae5);
+
+       if (ca0132_quirk(spec) == QUIRK_AE7) {
+               writel(0x00000680, spec->mem_base + 0x1c);
+               writel(0x00880680, spec->mem_base + 0x1c);
+       }
+
+       for (i = 0; i < count; i++) {
+               /*
+                * AE-7 shares all writes with the AE-5, except that it writes
+                * a different value to 0x20c.
+                */
+               if (i == 21 && ca0132_quirk(spec) == QUIRK_AE7) {
+                       writel(0x00800001, spec->mem_base + addr[i]);
+                       continue;
+               }
+
+               writel(data[i], spec->mem_base + addr[i]);
+       }
+
+       if (ca0132_quirk(spec) == QUIRK_AE5)
+               writel(0x00880680, spec->mem_base + 0x1c);
+}
+
+static void ca0132_mmio_init(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_R3D:
+       case QUIRK_SBZ:
+       case QUIRK_ZXR:
+               ca0132_mmio_init_sbz(codec);
+               break;
+       case QUIRK_AE5:
+               ca0132_mmio_init_ae5(codec);
+               break;
+       default:
+               break;
+       }
+}
+
+static const unsigned int ca0132_ae5_register_set_addresses[] = {
+       0x304, 0x304, 0x304, 0x304, 0x100, 0x304, 0x100, 0x304, 0x100, 0x304,
+       0x100, 0x304, 0x86c, 0x800, 0x86c, 0x800, 0x804
+};
+
+static const unsigned char ca0132_ae5_register_set_data[] = {
+       0x0f, 0x0e, 0x1f, 0x0c, 0x3f, 0x08, 0x7f, 0x00, 0xff, 0x00, 0x6b,
+       0x01, 0x6b, 0x57
+};
+
+/*
+ * This function writes to some SFR's, does some region2 writes, and then
+ * eventually resets the codec with the 0x7ff verb. Not quite sure why it does
+ * what it does.
+ */
+static void ae5_register_set(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       unsigned int count = ARRAY_SIZE(ca0132_ae5_register_set_addresses);
+       const unsigned int *addr = ca0132_ae5_register_set_addresses;
+       const unsigned char *data = ca0132_ae5_register_set_data;
+       unsigned int i, cur_addr;
+       unsigned char tmp[3];
+
+       if (ca0132_quirk(spec) == QUIRK_AE7)
+               chipio_8051_write_pll_pmu(codec, 0x41, 0xc8);
+
+       chipio_8051_write_direct(codec, 0x93, 0x10);
+       chipio_8051_write_pll_pmu(codec, 0x44, 0xc2);
+
+       if (ca0132_quirk(spec) == QUIRK_AE7) {
+               tmp[0] = 0x03;
+               tmp[1] = 0x03;
+               tmp[2] = 0x07;
+       } else {
+               tmp[0] = 0x0f;
+               tmp[1] = 0x0f;
+               tmp[2] = 0x0f;
+       }
+
+       for (i = cur_addr = 0; i < 3; i++, cur_addr++)
+               writeb(tmp[i], spec->mem_base + addr[cur_addr]);
+
+       /*
+        * First writes are in single bytes, final are in 4 bytes. So, we use
+        * writeb, then writel.
+        */
+       for (i = 0; cur_addr < 12; i++, cur_addr++)
+               writeb(data[i], spec->mem_base + addr[cur_addr]);
+
+       for (; cur_addr < count; i++, cur_addr++)
+               writel(data[i], spec->mem_base + addr[cur_addr]);
+
+       writel(0x00800001, spec->mem_base + 0x20c);
+
+       if (ca0132_quirk(spec) == QUIRK_AE7) {
+               ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
+               ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
+       } else {
+               ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
+       }
+
+       chipio_8051_write_direct(codec, 0x90, 0x00);
+       chipio_8051_write_direct(codec, 0x90, 0x10);
+
+       if (ca0132_quirk(spec) == QUIRK_AE5)
+               ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
+}
+
+/*
+ * Extra init functions for alternative ca0132 codecs. Done
+ * here so they don't clutter up the main ca0132_init function
+ * anymore than they have to.
+ */
+static void ca0132_alt_init(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       ca0132_alt_vol_setup(codec);
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+               codec_dbg(codec, "SBZ alt_init");
+               ca0132_gpio_init(codec);
+               sbz_pre_dsp_setup(codec);
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+               break;
+       case QUIRK_R3DI:
+               codec_dbg(codec, "R3DI alt_init");
+               ca0132_gpio_init(codec);
+               ca0132_gpio_setup(codec);
+               r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADING);
+               r3di_pre_dsp_setup(codec);
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x6FF, 0xC4);
+               break;
+       case QUIRK_R3D:
+               r3d_pre_dsp_setup(codec);
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+               break;
+       case QUIRK_AE5:
+               ca0132_gpio_init(codec);
+               chipio_8051_write_pll_pmu(codec, 0x49, 0x88);
+               chipio_write(codec, 0x18b030, 0x00000020);
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+               ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+               break;
+       case QUIRK_AE7:
+               ca0132_gpio_init(codec);
+               chipio_8051_write_pll_pmu(codec, 0x49, 0x88);
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+               chipio_write(codec, 0x18b008, 0x000000f8);
+               chipio_write(codec, 0x18b008, 0x000000f0);
+               chipio_write(codec, 0x18b030, 0x00000020);
+               ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
+               break;
+       case QUIRK_ZXR:
+               chipio_8051_write_pll_pmu(codec, 0x49, 0x88);
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
+               zxr_pre_dsp_setup(codec);
+               break;
+       default:
+               break;
+       }
+}
+
+static int ca0132_init(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+       bool dsp_loaded;
+
+       /*
+        * If the DSP is already downloaded, and init has been entered again,
+        * there's only two reasons for it. One, the codec has awaken from a
+        * suspended state, and in that case dspload_is_loaded will return
+        * false, and the init will be ran again. The other reason it gets
+        * re entered is on startup for some reason it triggers a suspend and
+        * resume state. In this case, it will check if the DSP is downloaded,
+        * and not run the init function again. For codecs using alt_functions,
+        * it will check if the DSP is loaded properly.
+        */
+       if (spec->dsp_state == DSP_DOWNLOADED) {
+               dsp_loaded = dspload_is_loaded(codec);
+               if (!dsp_loaded) {
+                       spec->dsp_reload = true;
+                       spec->dsp_state = DSP_DOWNLOAD_INIT;
+               } else {
+                       if (ca0132_quirk(spec) == QUIRK_SBZ)
+                               sbz_dsp_startup_check(codec);
+                       return 0;
+               }
+       }
+
+       if (spec->dsp_state != DSP_DOWNLOAD_FAILED)
+               spec->dsp_state = DSP_DOWNLOAD_INIT;
+       spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
+
+       if (ca0132_use_pci_mmio(spec))
+               ca0132_mmio_init(codec);
+
+       snd_hda_power_up_pm(codec);
+
+       if (ca0132_quirk(spec) == QUIRK_AE5 || ca0132_quirk(spec) == QUIRK_AE7)
+               ae5_register_set(codec);
+
+       ca0132_init_params(codec);
+       ca0132_init_flags(codec);
+
+       snd_hda_sequence_write(codec, spec->base_init_verbs);
+
+       if (ca0132_use_alt_functions(spec))
+               ca0132_alt_init(codec);
+
+       ca0132_download_dsp(codec);
+
+       ca0132_refresh_widget_caps(codec);
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_R3DI:
+       case QUIRK_R3D:
+               r3d_setup_defaults(codec);
+               break;
+       case QUIRK_SBZ:
+       case QUIRK_ZXR:
+               sbz_setup_defaults(codec);
+               break;
+       case QUIRK_AE5:
+               ae5_setup_defaults(codec);
+               break;
+       case QUIRK_AE7:
+               ae7_setup_defaults(codec);
+               break;
+       default:
+               ca0132_setup_defaults(codec);
+               ca0132_init_analog_mic2(codec);
+               ca0132_init_dmic(codec);
+               break;
+       }
+
+       for (i = 0; i < spec->num_outputs; i++)
+               init_output(codec, spec->out_pins[i], spec->dacs[0]);
+
+       init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
+
+       for (i = 0; i < spec->num_inputs; i++)
+               init_input(codec, spec->input_pins[i], spec->adcs[i]);
+
+       init_input(codec, cfg->dig_in_pin, spec->dig_in);
+
+       if (!ca0132_use_alt_functions(spec)) {
+               snd_hda_sequence_write(codec, spec->chip_init_verbs);
+               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PARAM_EX_ID_SET, 0x0D);
+               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
+                           VENDOR_CHIPIO_PARAM_EX_VALUE_SET, 0x20);
+       }
+
+       if (ca0132_quirk(spec) == QUIRK_SBZ)
+               ca0132_gpio_setup(codec);
+
+       snd_hda_sequence_write(codec, spec->spec_init_verbs);
+       if (ca0132_use_alt_functions(spec)) {
+               ca0132_alt_select_out(codec);
+               ca0132_alt_select_in(codec);
+       } else {
+               ca0132_select_out(codec);
+               ca0132_select_mic(codec);
+       }
+
+       snd_hda_jack_report_sync(codec);
+
+       /*
+        * Re set the PlayEnhancement switch on a resume event, because the
+        * controls will not be reloaded.
+        */
+       if (spec->dsp_reload) {
+               spec->dsp_reload = false;
+               ca0132_pe_switch_set(codec);
+       }
+
+       snd_hda_power_down_pm(codec);
+
+       return 0;
+}
+
+static int dbpro_init(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int i;
+
+       init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
+       init_input(codec, cfg->dig_in_pin, spec->dig_in);
+
+       for (i = 0; i < spec->num_inputs; i++)
+               init_input(codec, spec->input_pins[i], spec->adcs[i]);
+
+       return 0;
+}
+
+static void ca0132_free(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       cancel_delayed_work_sync(&spec->unsol_hp_work);
+       snd_hda_power_up(codec);
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+               sbz_exit_chip(codec);
+               break;
+       case QUIRK_ZXR:
+               zxr_exit_chip(codec);
+               break;
+       case QUIRK_R3D:
+               r3d_exit_chip(codec);
+               break;
+       case QUIRK_AE5:
+               ae5_exit_chip(codec);
+               break;
+       case QUIRK_AE7:
+               ae7_exit_chip(codec);
+               break;
+       case QUIRK_R3DI:
+               r3di_gpio_shutdown(codec);
+               break;
+       default:
+               break;
+       }
+
+       snd_hda_sequence_write(codec, spec->base_exit_verbs);
+       ca0132_exit_chip(codec);
+
+       snd_hda_power_down(codec);
+#ifdef CONFIG_PCI
+       if (spec->mem_base)
+               pci_iounmap(codec->bus->pci, spec->mem_base);
+#endif
+       kfree(spec->spec_init_verbs);
+       kfree(codec->spec);
+}
+
+static void dbpro_free(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       zxr_dbpro_power_state_shutdown(codec);
+
+       kfree(spec->spec_init_verbs);
+       kfree(codec->spec);
+}
+
+static int ca0132_suspend(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       cancel_delayed_work_sync(&spec->unsol_hp_work);
+       return 0;
+}
+
+static const struct hda_codec_ops ca0132_patch_ops = {
+       .build_controls = ca0132_build_controls,
+       .build_pcms = ca0132_build_pcms,
+       .init = ca0132_init,
+       .free = ca0132_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .suspend = ca0132_suspend,
+};
+
+static const struct hda_codec_ops dbpro_patch_ops = {
+       .build_controls = dbpro_build_controls,
+       .build_pcms = dbpro_build_pcms,
+       .init = dbpro_init,
+       .free = dbpro_free,
+};
+
+static void ca0132_config(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec = codec->spec;
+
+       spec->dacs[0] = 0x2;
+       spec->dacs[1] = 0x3;
+       spec->dacs[2] = 0x4;
+
+       spec->multiout.dac_nids = spec->dacs;
+       spec->multiout.num_dacs = 3;
+
+       if (!ca0132_use_alt_functions(spec))
+               spec->multiout.max_channels = 2;
+       else
+               spec->multiout.max_channels = 6;
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_ALIENWARE:
+               codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, alienware_pincfgs);
+               break;
+       case QUIRK_SBZ:
+               codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, sbz_pincfgs);
+               break;
+       case QUIRK_ZXR:
+               codec_dbg(codec, "%s: QUIRK_ZXR applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, zxr_pincfgs);
+               break;
+       case QUIRK_R3D:
+               codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, r3d_pincfgs);
+               break;
+       case QUIRK_R3DI:
+               codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, r3di_pincfgs);
+               break;
+       case QUIRK_AE5:
+               codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, ae5_pincfgs);
+               break;
+       case QUIRK_AE7:
+               codec_dbg(codec, "%s: QUIRK_AE7 applied.\n", __func__);
+               snd_hda_apply_pincfgs(codec, ae7_pincfgs);
+               break;
+       default:
+               break;
+       }
+
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_ALIENWARE:
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0b; /* speaker out */
+               spec->out_pins[1] = 0x0f;
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = 0x0f;
+
+               spec->adcs[0] = 0x7; /* digital mic / analog mic1 */
+               spec->adcs[1] = 0x8; /* analog mic2 */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               spec->num_inputs = 3;
+               spec->input_pins[0] = 0x12;
+               spec->input_pins[1] = 0x11;
+               spec->input_pins[2] = 0x13;
+               spec->shared_mic_nid = 0x7;
+               spec->unsol_tag_amic1 = 0x11;
+               break;
+       case QUIRK_SBZ:
+       case QUIRK_R3D:
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0B; /* Line out */
+               spec->out_pins[1] = 0x0F; /* Rear headphone out */
+               spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
+               spec->out_pins[3] = 0x11; /* Rear surround */
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = spec->out_pins[1];
+               spec->unsol_tag_front_hp = spec->out_pins[2];
+
+               spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+               spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               spec->num_inputs = 2;
+               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+               spec->input_pins[1] = 0x13; /* What U Hear */
+               spec->shared_mic_nid = 0x7;
+               spec->unsol_tag_amic1 = spec->input_pins[0];
+
+               /* SPDIF I/O */
+               spec->dig_out = 0x05;
+               spec->multiout.dig_out_nid = spec->dig_out;
+               spec->dig_in = 0x09;
+               break;
+       case QUIRK_ZXR:
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0B; /* Line out */
+               spec->out_pins[1] = 0x0F; /* Rear headphone out */
+               spec->out_pins[2] = 0x10; /* Center/LFE */
+               spec->out_pins[3] = 0x11; /* Rear surround */
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = spec->out_pins[1];
+               spec->unsol_tag_front_hp = spec->out_pins[2];
+
+               spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+               spec->adcs[1] = 0x8; /* Not connected, no front mic */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               spec->num_inputs = 2;
+               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+               spec->input_pins[1] = 0x13; /* What U Hear */
+               spec->shared_mic_nid = 0x7;
+               spec->unsol_tag_amic1 = spec->input_pins[0];
+               break;
+       case QUIRK_ZXR_DBPRO:
+               spec->adcs[0] = 0x8; /* ZxR DBPro Aux In */
+
+               spec->num_inputs = 1;
+               spec->input_pins[0] = 0x11; /* RCA Line-in */
+
+               spec->dig_out = 0x05;
+               spec->multiout.dig_out_nid = spec->dig_out;
+
+               spec->dig_in = 0x09;
+               break;
+       case QUIRK_AE5:
+       case QUIRK_AE7:
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0B; /* Line out */
+               spec->out_pins[1] = 0x11; /* Rear headphone out */
+               spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
+               spec->out_pins[3] = 0x0F; /* Rear surround */
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = spec->out_pins[1];
+               spec->unsol_tag_front_hp = spec->out_pins[2];
+
+               spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
+               spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               spec->num_inputs = 2;
+               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+               spec->input_pins[1] = 0x13; /* What U Hear */
+               spec->shared_mic_nid = 0x7;
+               spec->unsol_tag_amic1 = spec->input_pins[0];
+
+               /* SPDIF I/O */
+               spec->dig_out = 0x05;
+               spec->multiout.dig_out_nid = spec->dig_out;
+               break;
+       case QUIRK_R3DI:
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0B; /* Line out */
+               spec->out_pins[1] = 0x0F; /* Rear headphone out */
+               spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
+               spec->out_pins[3] = 0x11; /* Rear surround */
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = spec->out_pins[1];
+               spec->unsol_tag_front_hp = spec->out_pins[2];
+
+               spec->adcs[0] = 0x07; /* Rear Mic / Line-in */
+               spec->adcs[1] = 0x08; /* Front Mic, but only if no DSP */
+               spec->adcs[2] = 0x0a; /* what u hear */
+
+               spec->num_inputs = 2;
+               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
+               spec->input_pins[1] = 0x13; /* What U Hear */
+               spec->shared_mic_nid = 0x7;
+               spec->unsol_tag_amic1 = spec->input_pins[0];
+
+               /* SPDIF I/O */
+               spec->dig_out = 0x05;
+               spec->multiout.dig_out_nid = spec->dig_out;
+               break;
+       default:
+               spec->num_outputs = 2;
+               spec->out_pins[0] = 0x0b; /* speaker out */
+               spec->out_pins[1] = 0x10; /* headphone out */
+               spec->shared_out_nid = 0x2;
+               spec->unsol_tag_hp = spec->out_pins[1];
+
+               spec->adcs[0] = 0x7; /* digital mic / analog mic1 */
+               spec->adcs[1] = 0x8; /* analog mic2 */
+               spec->adcs[2] = 0xa; /* what u hear */
+
+               spec->num_inputs = 3;
+               spec->input_pins[0] = 0x12;
+               spec->input_pins[1] = 0x11;
+               spec->input_pins[2] = 0x13;
+               spec->shared_mic_nid = 0x7;
+               spec->unsol_tag_amic1 = spec->input_pins[0];
+
+               /* SPDIF I/O */
+               spec->dig_out = 0x05;
+               spec->multiout.dig_out_nid = spec->dig_out;
+               spec->dig_in = 0x09;
+               break;
+       }
+}
+
+static int ca0132_prepare_verbs(struct hda_codec *codec)
+{
+/* Verbs + terminator (an empty element) */
+#define NUM_SPEC_VERBS 2
+       struct ca0132_spec *spec = codec->spec;
+
+       spec->chip_init_verbs = ca0132_init_verbs0;
+       /*
+        * Since desktop cards use pci_mmio, this can be used to determine
+        * whether or not to use these verbs instead of a separate bool.
+        */
+       if (ca0132_use_pci_mmio(spec))
+               spec->desktop_init_verbs = ca0132_init_verbs1;
+       spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
+                                       sizeof(struct hda_verb),
+                                       GFP_KERNEL);
+       if (!spec->spec_init_verbs)
+               return -ENOMEM;
+
+       /* config EAPD */
+       spec->spec_init_verbs[0].nid = 0x0b;
+       spec->spec_init_verbs[0].param = 0x78D;
+       spec->spec_init_verbs[0].verb = 0x00;
+
+       /* Previously commented configuration */
+       /*
+       spec->spec_init_verbs[2].nid = 0x0b;
+       spec->spec_init_verbs[2].param = AC_VERB_SET_EAPD_BTLENABLE;
+       spec->spec_init_verbs[2].verb = 0x02;
+
+       spec->spec_init_verbs[3].nid = 0x10;
+       spec->spec_init_verbs[3].param = 0x78D;
+       spec->spec_init_verbs[3].verb = 0x02;
+
+       spec->spec_init_verbs[4].nid = 0x10;
+       spec->spec_init_verbs[4].param = AC_VERB_SET_EAPD_BTLENABLE;
+       spec->spec_init_verbs[4].verb = 0x02;
+       */
+
+       /* Terminator: spec->spec_init_verbs[NUM_SPEC_VERBS-1] */
+       return 0;
+}
+
+/*
+ * The Sound Blaster ZxR shares the same PCI subsystem ID as some regular
+ * Sound Blaster Z cards. However, they have different HDA codec subsystem
+ * ID's. So, we check for the ZxR's subsystem ID, as well as the DBPro
+ * daughter boards ID.
+ */
+static void sbz_detect_quirk(struct hda_codec *codec)
+{
+       switch (codec->core.subsystem_id) {
+       case 0x11020033:
+               codec->fixup_id = QUIRK_ZXR;
+               break;
+       case 0x1102003f:
+               codec->fixup_id = QUIRK_ZXR_DBPRO;
+               break;
+       default:
+               codec->fixup_id = QUIRK_SBZ;
+               break;
+       }
+}
+
+static int patch_ca0132(struct hda_codec *codec)
+{
+       struct ca0132_spec *spec;
+       int err;
+
+       codec_dbg(codec, "patch_ca0132\n");
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+       spec->codec = codec;
+
+       /* Detect codec quirk */
+       snd_hda_pick_fixup(codec, ca0132_quirk_models, ca0132_quirks, NULL);
+       if (ca0132_quirk(spec) == QUIRK_SBZ)
+               sbz_detect_quirk(codec);
+
+       if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
+               codec->patch_ops = dbpro_patch_ops;
+       else
+               codec->patch_ops = ca0132_patch_ops;
+
+       codec->pcm_format_first = 1;
+       codec->no_sticky_stream = 1;
+
+
+       spec->dsp_state = DSP_DOWNLOAD_INIT;
+       spec->num_mixers = 1;
+
+       /* Set which mixers each quirk uses. */
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+               spec->mixers[0] = desktop_mixer;
+               snd_hda_codec_set_name(codec, "Sound Blaster Z");
+               break;
+       case QUIRK_ZXR:
+               spec->mixers[0] = desktop_mixer;
+               snd_hda_codec_set_name(codec, "Sound Blaster ZxR");
+               break;
+       case QUIRK_ZXR_DBPRO:
+               break;
+       case QUIRK_R3D:
+               spec->mixers[0] = desktop_mixer;
+               snd_hda_codec_set_name(codec, "Recon3D");
+               break;
+       case QUIRK_R3DI:
+               spec->mixers[0] = r3di_mixer;
+               snd_hda_codec_set_name(codec, "Recon3Di");
+               break;
+       case QUIRK_AE5:
+               spec->mixers[0] = desktop_mixer;
+               snd_hda_codec_set_name(codec, "Sound BlasterX AE-5");
+               break;
+       case QUIRK_AE7:
+               spec->mixers[0] = desktop_mixer;
+               snd_hda_codec_set_name(codec, "Sound Blaster AE-7");
+               break;
+       default:
+               spec->mixers[0] = ca0132_mixer;
+               break;
+       }
+
+       /* Setup whether or not to use alt functions/controls/pci_mmio */
+       switch (ca0132_quirk(spec)) {
+       case QUIRK_SBZ:
+       case QUIRK_R3D:
+       case QUIRK_AE5:
+       case QUIRK_AE7:
+       case QUIRK_ZXR:
+               spec->use_alt_controls = true;
+               spec->use_alt_functions = true;
+               spec->use_pci_mmio = true;
+               break;
+       case QUIRK_R3DI:
+               spec->use_alt_controls = true;
+               spec->use_alt_functions = true;
+               spec->use_pci_mmio = false;
+               break;
+       default:
+               spec->use_alt_controls = false;
+               spec->use_alt_functions = false;
+               spec->use_pci_mmio = false;
+               break;
+       }
+
+#ifdef CONFIG_PCI
+       if (spec->use_pci_mmio) {
+               spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
+               if (spec->mem_base == NULL) {
+                       codec_warn(codec, "pci_iomap failed! Setting quirk to QUIRK_NONE.");
+                       codec->fixup_id = QUIRK_NONE;
+               }
+       }
+#endif
+
+       spec->base_init_verbs = ca0132_base_init_verbs;
+       spec->base_exit_verbs = ca0132_base_exit_verbs;
+
+       INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed);
+
+       ca0132_init_chip(codec);
+
+       ca0132_config(codec);
+
+       err = ca0132_prepare_verbs(codec);
+       if (err < 0)
+               goto error;
+
+       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
+       if (err < 0)
+               goto error;
+
+       ca0132_setup_unsol(codec);
+
+       return 0;
+
+ error:
+       ca0132_free(codec);
+       return err;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_ca0132[] = {
+       HDA_CODEC_ENTRY(0x11020011, "CA0132", patch_ca0132),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0132);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Creative Sound Core3D codec");
+
+static struct hda_codec_driver ca0132_driver = {
+       .id = snd_hda_id_ca0132,
+};
+
+module_hda_codec_driver(ca0132_driver);
diff --git a/sound/hda/codecs/ca0132_regs.h b/sound/hda/codecs/ca0132_regs.h
new file mode 100644 (file)
index 0000000..0ead571
--- /dev/null
@@ -0,0 +1,396 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * HD audio interface patch for Creative CA0132 chip.
+ * CA0132 registers defines.
+ *
+ * Copyright (c) 2011, Creative Technology Ltd.
+ */
+
+#ifndef __CA0132_REGS_H
+#define __CA0132_REGS_H
+
+#define DSP_CHIP_OFFSET                0x100000
+#define DSP_DBGCNTL_MODULE_OFFSET      0xE30
+#define DSP_DBGCNTL_INST_OFFSET \
+       (DSP_CHIP_OFFSET + DSP_DBGCNTL_MODULE_OFFSET)
+
+#define DSP_DBGCNTL_EXEC_LOBIT         0x0
+#define DSP_DBGCNTL_EXEC_HIBIT         0x3
+#define DSP_DBGCNTL_EXEC_MASK          0xF
+
+#define DSP_DBGCNTL_SS_LOBIT           0x4
+#define DSP_DBGCNTL_SS_HIBIT           0x7
+#define DSP_DBGCNTL_SS_MASK            0xF0
+
+#define DSP_DBGCNTL_STATE_LOBIT        0xA
+#define DSP_DBGCNTL_STATE_HIBIT        0xD
+#define DSP_DBGCNTL_STATE_MASK         0x3C00
+
+#define XRAM_CHIP_OFFSET               0x0
+#define XRAM_XRAM_CHANNEL_COUNT        0xE000
+#define XRAM_XRAM_MODULE_OFFSET        0x0
+#define XRAM_XRAM_CHAN_INCR            4
+#define XRAM_XRAM_INST_OFFSET(_chan) \
+       (XRAM_CHIP_OFFSET + XRAM_XRAM_MODULE_OFFSET + \
+       (_chan * XRAM_XRAM_CHAN_INCR))
+
+#define YRAM_CHIP_OFFSET               0x40000
+#define YRAM_YRAM_CHANNEL_COUNT        0x8000
+#define YRAM_YRAM_MODULE_OFFSET        0x0
+#define YRAM_YRAM_CHAN_INCR            4
+#define YRAM_YRAM_INST_OFFSET(_chan) \
+       (YRAM_CHIP_OFFSET + YRAM_YRAM_MODULE_OFFSET + \
+       (_chan * YRAM_YRAM_CHAN_INCR))
+
+#define UC_CHIP_OFFSET                 0x80000
+#define UC_UC_CHANNEL_COUNT            0x10000
+#define UC_UC_MODULE_OFFSET            0x0
+#define UC_UC_CHAN_INCR                4
+#define UC_UC_INST_OFFSET(_chan) \
+       (UC_CHIP_OFFSET + UC_UC_MODULE_OFFSET + \
+       (_chan * UC_UC_CHAN_INCR))
+
+#define AXRAM_CHIP_OFFSET              0x3C000
+#define AXRAM_AXRAM_CHANNEL_COUNT      0x1000
+#define AXRAM_AXRAM_MODULE_OFFSET      0x0
+#define AXRAM_AXRAM_CHAN_INCR          4
+#define AXRAM_AXRAM_INST_OFFSET(_chan) \
+       (AXRAM_CHIP_OFFSET + AXRAM_AXRAM_MODULE_OFFSET + \
+       (_chan * AXRAM_AXRAM_CHAN_INCR))
+
+#define AYRAM_CHIP_OFFSET              0x78000
+#define AYRAM_AYRAM_CHANNEL_COUNT      0x1000
+#define AYRAM_AYRAM_MODULE_OFFSET      0x0
+#define AYRAM_AYRAM_CHAN_INCR          4
+#define AYRAM_AYRAM_INST_OFFSET(_chan) \
+       (AYRAM_CHIP_OFFSET + AYRAM_AYRAM_MODULE_OFFSET + \
+       (_chan * AYRAM_AYRAM_CHAN_INCR))
+
+#define DSPDMAC_CHIP_OFFSET            0x110000
+#define DSPDMAC_DMA_CFG_CHANNEL_COUNT  12
+#define DSPDMAC_DMACFG_MODULE_OFFSET   0xF00
+#define DSPDMAC_DMACFG_CHAN_INCR       0x10
+#define DSPDMAC_DMACFG_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DMACFG_MODULE_OFFSET + \
+       (_chan * DSPDMAC_DMACFG_CHAN_INCR))
+
+#define DSPDMAC_DMACFG_DBADR_LOBIT     0x0
+#define DSPDMAC_DMACFG_DBADR_HIBIT     0x10
+#define DSPDMAC_DMACFG_DBADR_MASK      0x1FFFF
+#define DSPDMAC_DMACFG_LP_LOBIT        0x11
+#define DSPDMAC_DMACFG_LP_HIBIT        0x11
+#define DSPDMAC_DMACFG_LP_MASK         0x20000
+
+#define DSPDMAC_DMACFG_AINCR_LOBIT     0x12
+#define DSPDMAC_DMACFG_AINCR_HIBIT     0x12
+#define DSPDMAC_DMACFG_AINCR_MASK      0x40000
+
+#define DSPDMAC_DMACFG_DWR_LOBIT       0x13
+#define DSPDMAC_DMACFG_DWR_HIBIT       0x13
+#define DSPDMAC_DMACFG_DWR_MASK        0x80000
+
+#define DSPDMAC_DMACFG_AJUMP_LOBIT     0x14
+#define DSPDMAC_DMACFG_AJUMP_HIBIT     0x17
+#define DSPDMAC_DMACFG_AJUMP_MASK      0xF00000
+
+#define DSPDMAC_DMACFG_AMODE_LOBIT     0x18
+#define DSPDMAC_DMACFG_AMODE_HIBIT     0x19
+#define DSPDMAC_DMACFG_AMODE_MASK      0x3000000
+
+#define DSPDMAC_DMACFG_LK_LOBIT        0x1A
+#define DSPDMAC_DMACFG_LK_HIBIT        0x1A
+#define DSPDMAC_DMACFG_LK_MASK         0x4000000
+
+#define DSPDMAC_DMACFG_AICS_LOBIT      0x1B
+#define DSPDMAC_DMACFG_AICS_HIBIT      0x1F
+#define DSPDMAC_DMACFG_AICS_MASK       0xF8000000
+
+#define DSPDMAC_DMACFG_LP_SINGLE                 0
+#define DSPDMAC_DMACFG_LP_LOOPING                1
+
+#define DSPDMAC_DMACFG_AINCR_XANDY               0
+#define DSPDMAC_DMACFG_AINCR_XORY                1
+
+#define DSPDMAC_DMACFG_DWR_DMA_RD                0
+#define DSPDMAC_DMACFG_DWR_DMA_WR                1
+
+#define DSPDMAC_DMACFG_AMODE_LINEAR              0
+#define DSPDMAC_DMACFG_AMODE_RSV1                1
+#define DSPDMAC_DMACFG_AMODE_WINTLV              2
+#define DSPDMAC_DMACFG_AMODE_GINTLV              3
+
+#define DSPDMAC_DSP_ADR_OFS_CHANNEL_COUNT 12
+#define DSPDMAC_DSPADROFS_MODULE_OFFSET 0xF04
+#define DSPDMAC_DSPADROFS_CHAN_INCR    0x10
+#define DSPDMAC_DSPADROFS_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADROFS_MODULE_OFFSET + \
+       (_chan * DSPDMAC_DSPADROFS_CHAN_INCR))
+
+#define DSPDMAC_DSPADROFS_COFS_LOBIT   0x0
+#define DSPDMAC_DSPADROFS_COFS_HIBIT   0xF
+#define DSPDMAC_DSPADROFS_COFS_MASK    0xFFFF
+
+#define DSPDMAC_DSPADROFS_BOFS_LOBIT   0x10
+#define DSPDMAC_DSPADROFS_BOFS_HIBIT   0x1F
+#define DSPDMAC_DSPADROFS_BOFS_MASK    0xFFFF0000
+
+#define DSPDMAC_DSP_ADR_WOFS_CHANNEL_COUNT 12
+#define DSPDMAC_DSPADRWOFS_MODULE_OFFSET 0xF04
+#define DSPDMAC_DSPADRWOFS_CHAN_INCR   0x10
+
+#define DSPDMAC_DSPADRWOFS_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRWOFS_MODULE_OFFSET + \
+       (_chan * DSPDMAC_DSPADRWOFS_CHAN_INCR))
+
+#define DSPDMAC_DSPADRWOFS_WCOFS_LOBIT 0x0
+#define DSPDMAC_DSPADRWOFS_WCOFS_HIBIT 0xA
+#define DSPDMAC_DSPADRWOFS_WCOFS_MASK  0x7FF
+
+#define DSPDMAC_DSPADRWOFS_WCBFR_LOBIT 0xB
+#define DSPDMAC_DSPADRWOFS_WCBFR_HIBIT 0xF
+#define DSPDMAC_DSPADRWOFS_WCBFR_MASK  0xF800
+
+#define DSPDMAC_DSPADRWOFS_WBOFS_LOBIT 0x10
+#define DSPDMAC_DSPADRWOFS_WBOFS_HIBIT 0x1A
+#define DSPDMAC_DSPADRWOFS_WBOFS_MASK  0x7FF0000
+
+#define DSPDMAC_DSPADRWOFS_WBBFR_LOBIT 0x1B
+#define DSPDMAC_DSPADRWOFS_WBBFR_HIBIT 0x1F
+#define DSPDMAC_DSPADRWOFS_WBBFR_MASK  0xF8000000
+
+#define DSPDMAC_DSP_ADR_GOFS_CHANNEL_COUNT 12
+#define DSPDMAC_DSPADRGOFS_MODULE_OFFSET 0xF04
+#define DSPDMAC_DSPADRGOFS_CHAN_INCR   0x10
+#define DSPDMAC_DSPADRGOFS_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRGOFS_MODULE_OFFSET + \
+       (_chan * DSPDMAC_DSPADRGOFS_CHAN_INCR))
+
+#define DSPDMAC_DSPADRGOFS_GCOFS_LOBIT 0x0
+#define DSPDMAC_DSPADRGOFS_GCOFS_HIBIT 0x9
+#define DSPDMAC_DSPADRGOFS_GCOFS_MASK  0x3FF
+
+#define DSPDMAC_DSPADRGOFS_GCS_LOBIT   0xA
+#define DSPDMAC_DSPADRGOFS_GCS_HIBIT   0xC
+#define DSPDMAC_DSPADRGOFS_GCS_MASK    0x1C00
+
+#define DSPDMAC_DSPADRGOFS_GCBFR_LOBIT 0xD
+#define DSPDMAC_DSPADRGOFS_GCBFR_HIBIT 0xF
+#define DSPDMAC_DSPADRGOFS_GCBFR_MASK  0xE000
+
+#define DSPDMAC_DSPADRGOFS_GBOFS_LOBIT 0x10
+#define DSPDMAC_DSPADRGOFS_GBOFS_HIBIT 0x19
+#define DSPDMAC_DSPADRGOFS_GBOFS_MASK  0x3FF0000
+
+#define DSPDMAC_DSPADRGOFS_GBS_LOBIT   0x1A
+#define DSPDMAC_DSPADRGOFS_GBS_HIBIT   0x1C
+#define DSPDMAC_DSPADRGOFS_GBS_MASK    0x1C000000
+
+#define DSPDMAC_DSPADRGOFS_GBBFR_LOBIT 0x1D
+#define DSPDMAC_DSPADRGOFS_GBBFR_HIBIT 0x1F
+#define DSPDMAC_DSPADRGOFS_GBBFR_MASK  0xE0000000
+
+#define DSPDMAC_XFR_CNT_CHANNEL_COUNT  12
+#define DSPDMAC_XFRCNT_MODULE_OFFSET   0xF08
+#define DSPDMAC_XFRCNT_CHAN_INCR       0x10
+
+#define DSPDMAC_XFRCNT_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_XFRCNT_MODULE_OFFSET + \
+       (_chan * DSPDMAC_XFRCNT_CHAN_INCR))
+
+#define DSPDMAC_XFRCNT_CCNT_LOBIT      0x0
+#define DSPDMAC_XFRCNT_CCNT_HIBIT      0xF
+#define DSPDMAC_XFRCNT_CCNT_MASK       0xFFFF
+
+#define DSPDMAC_XFRCNT_BCNT_LOBIT      0x10
+#define DSPDMAC_XFRCNT_BCNT_HIBIT      0x1F
+#define DSPDMAC_XFRCNT_BCNT_MASK       0xFFFF0000
+
+#define DSPDMAC_IRQ_CNT_CHANNEL_COUNT  12
+#define DSPDMAC_IRQCNT_MODULE_OFFSET   0xF0C
+#define DSPDMAC_IRQCNT_CHAN_INCR       0x10
+#define DSPDMAC_IRQCNT_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_IRQCNT_MODULE_OFFSET + \
+       (_chan * DSPDMAC_IRQCNT_CHAN_INCR))
+
+#define DSPDMAC_IRQCNT_CICNT_LOBIT     0x0
+#define DSPDMAC_IRQCNT_CICNT_HIBIT     0xF
+#define DSPDMAC_IRQCNT_CICNT_MASK      0xFFFF
+
+#define DSPDMAC_IRQCNT_BICNT_LOBIT     0x10
+#define DSPDMAC_IRQCNT_BICNT_HIBIT     0x1F
+#define DSPDMAC_IRQCNT_BICNT_MASK      0xFFFF0000
+
+#define DSPDMAC_AUD_CHSEL_CHANNEL_COUNT 12
+#define DSPDMAC_AUDCHSEL_MODULE_OFFSET 0xFC0
+#define DSPDMAC_AUDCHSEL_CHAN_INCR     0x4
+#define DSPDMAC_AUDCHSEL_INST_OFFSET(_chan) \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_AUDCHSEL_MODULE_OFFSET + \
+       (_chan * DSPDMAC_AUDCHSEL_CHAN_INCR))
+
+#define DSPDMAC_AUDCHSEL_ACS_LOBIT     0x0
+#define DSPDMAC_AUDCHSEL_ACS_HIBIT     0x1F
+#define DSPDMAC_AUDCHSEL_ACS_MASK      0xFFFFFFFF
+
+#define DSPDMAC_CHNLSTART_MODULE_OFFSET 0xFF0
+#define DSPDMAC_CHNLSTART_INST_OFFSET \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTART_MODULE_OFFSET)
+
+#define DSPDMAC_CHNLSTART_EN_LOBIT     0x0
+#define DSPDMAC_CHNLSTART_EN_HIBIT     0xB
+#define DSPDMAC_CHNLSTART_EN_MASK      0xFFF
+
+#define DSPDMAC_CHNLSTART_VAI1_LOBIT   0xC
+#define DSPDMAC_CHNLSTART_VAI1_HIBIT   0xF
+#define DSPDMAC_CHNLSTART_VAI1_MASK    0xF000
+
+#define DSPDMAC_CHNLSTART_DIS_LOBIT    0x10
+#define DSPDMAC_CHNLSTART_DIS_HIBIT    0x1B
+#define DSPDMAC_CHNLSTART_DIS_MASK     0xFFF0000
+
+#define DSPDMAC_CHNLSTART_VAI2_LOBIT   0x1C
+#define DSPDMAC_CHNLSTART_VAI2_HIBIT   0x1F
+#define DSPDMAC_CHNLSTART_VAI2_MASK    0xF0000000
+
+#define DSPDMAC_CHNLSTATUS_MODULE_OFFSET 0xFF4
+#define DSPDMAC_CHNLSTATUS_INST_OFFSET \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTATUS_MODULE_OFFSET)
+
+#define DSPDMAC_CHNLSTATUS_ISC_LOBIT   0x0
+#define DSPDMAC_CHNLSTATUS_ISC_HIBIT   0xB
+#define DSPDMAC_CHNLSTATUS_ISC_MASK    0xFFF
+
+#define DSPDMAC_CHNLSTATUS_AOO_LOBIT   0xC
+#define DSPDMAC_CHNLSTATUS_AOO_HIBIT   0xC
+#define DSPDMAC_CHNLSTATUS_AOO_MASK    0x1000
+
+#define DSPDMAC_CHNLSTATUS_AOU_LOBIT   0xD
+#define DSPDMAC_CHNLSTATUS_AOU_HIBIT   0xD
+#define DSPDMAC_CHNLSTATUS_AOU_MASK    0x2000
+
+#define DSPDMAC_CHNLSTATUS_AIO_LOBIT   0xE
+#define DSPDMAC_CHNLSTATUS_AIO_HIBIT   0xE
+#define DSPDMAC_CHNLSTATUS_AIO_MASK    0x4000
+
+#define DSPDMAC_CHNLSTATUS_AIU_LOBIT   0xF
+#define DSPDMAC_CHNLSTATUS_AIU_HIBIT   0xF
+#define DSPDMAC_CHNLSTATUS_AIU_MASK    0x8000
+
+#define DSPDMAC_CHNLSTATUS_IEN_LOBIT   0x10
+#define DSPDMAC_CHNLSTATUS_IEN_HIBIT   0x1B
+#define DSPDMAC_CHNLSTATUS_IEN_MASK    0xFFF0000
+
+#define DSPDMAC_CHNLSTATUS_VAI0_LOBIT  0x1C
+#define DSPDMAC_CHNLSTATUS_VAI0_HIBIT  0x1F
+#define DSPDMAC_CHNLSTATUS_VAI0_MASK   0xF0000000
+
+#define DSPDMAC_CHNLPROP_MODULE_OFFSET 0xFF8
+#define DSPDMAC_CHNLPROP_INST_OFFSET \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLPROP_MODULE_OFFSET)
+
+#define DSPDMAC_CHNLPROP_DCON_LOBIT    0x0
+#define DSPDMAC_CHNLPROP_DCON_HIBIT    0xB
+#define DSPDMAC_CHNLPROP_DCON_MASK     0xFFF
+
+#define DSPDMAC_CHNLPROP_FFS_LOBIT     0xC
+#define DSPDMAC_CHNLPROP_FFS_HIBIT     0xC
+#define DSPDMAC_CHNLPROP_FFS_MASK      0x1000
+
+#define DSPDMAC_CHNLPROP_NAJ_LOBIT     0xD
+#define DSPDMAC_CHNLPROP_NAJ_HIBIT     0xD
+#define DSPDMAC_CHNLPROP_NAJ_MASK      0x2000
+
+#define DSPDMAC_CHNLPROP_ENH_LOBIT     0xE
+#define DSPDMAC_CHNLPROP_ENH_HIBIT     0xE
+#define DSPDMAC_CHNLPROP_ENH_MASK      0x4000
+
+#define DSPDMAC_CHNLPROP_MSPCE_LOBIT   0x10
+#define DSPDMAC_CHNLPROP_MSPCE_HIBIT   0x1B
+#define DSPDMAC_CHNLPROP_MSPCE_MASK    0xFFF0000
+
+#define DSPDMAC_CHNLPROP_AC_LOBIT      0x1C
+#define DSPDMAC_CHNLPROP_AC_HIBIT      0x1F
+#define DSPDMAC_CHNLPROP_AC_MASK       0xF0000000
+
+#define DSPDMAC_ACTIVE_MODULE_OFFSET   0xFFC
+#define DSPDMAC_ACTIVE_INST_OFFSET \
+       (DSPDMAC_CHIP_OFFSET + DSPDMAC_ACTIVE_MODULE_OFFSET)
+
+#define DSPDMAC_ACTIVE_AAR_LOBIT       0x0
+#define DSPDMAC_ACTIVE_AAR_HIBIT       0xB
+#define DSPDMAC_ACTIVE_AAR_MASK        0xFFF
+
+#define DSPDMAC_ACTIVE_WFR_LOBIT       0xC
+#define DSPDMAC_ACTIVE_WFR_HIBIT       0x17
+#define DSPDMAC_ACTIVE_WFR_MASK        0xFFF000
+
+#define DSP_AUX_MEM_BASE            0xE000
+#define INVALID_CHIP_ADDRESS        (~0U)
+
+#define X_SIZE  (XRAM_XRAM_CHANNEL_COUNT   * XRAM_XRAM_CHAN_INCR)
+#define Y_SIZE  (YRAM_YRAM_CHANNEL_COUNT   * YRAM_YRAM_CHAN_INCR)
+#define AX_SIZE (AXRAM_AXRAM_CHANNEL_COUNT * AXRAM_AXRAM_CHAN_INCR)
+#define AY_SIZE (AYRAM_AYRAM_CHANNEL_COUNT * AYRAM_AYRAM_CHAN_INCR)
+#define UC_SIZE (UC_UC_CHANNEL_COUNT       * UC_UC_CHAN_INCR)
+
+#define XEXT_SIZE (X_SIZE + AX_SIZE)
+#define YEXT_SIZE (Y_SIZE + AY_SIZE)
+
+#define U64K 0x10000UL
+
+#define X_END  (XRAM_CHIP_OFFSET  + X_SIZE)
+#define X_EXT  (XRAM_CHIP_OFFSET  + XEXT_SIZE)
+#define AX_END (XRAM_CHIP_OFFSET  + U64K*4)
+
+#define Y_END  (YRAM_CHIP_OFFSET  + Y_SIZE)
+#define Y_EXT  (YRAM_CHIP_OFFSET  + YEXT_SIZE)
+#define AY_END (YRAM_CHIP_OFFSET  + U64K*4)
+
+#define UC_END (UC_CHIP_OFFSET    + UC_SIZE)
+
+#define X_RANGE_MAIN(a, s) \
+       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR <  X_END))
+#define X_RANGE_AUX(a, s)  \
+       (((a) >= X_END) && ((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
+#define X_RANGE_EXT(a, s)  \
+       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR <  X_EXT))
+#define X_RANGE_ALL(a, s)  \
+       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
+
+#define Y_RANGE_MAIN(a, s) \
+       (((a) >= YRAM_CHIP_OFFSET) && \
+       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR <  Y_END))
+#define Y_RANGE_AUX(a, s)  \
+       (((a) >= Y_END) && \
+       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
+#define Y_RANGE_EXT(a, s)  \
+       (((a) >= YRAM_CHIP_OFFSET) && \
+       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR <  Y_EXT))
+#define Y_RANGE_ALL(a, s)  \
+       (((a) >= YRAM_CHIP_OFFSET) && \
+       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
+
+#define UC_RANGE(a, s) \
+       (((a) >= UC_CHIP_OFFSET) && \
+       ((a)+((s)-1)*UC_UC_CHAN_INCR     < UC_END))
+
+#define X_OFF(a) \
+       (((a) - XRAM_CHIP_OFFSET) / XRAM_XRAM_CHAN_INCR)
+#define AX_OFF(a) \
+       (((a) % (AXRAM_AXRAM_CHANNEL_COUNT * \
+       AXRAM_AXRAM_CHAN_INCR)) / AXRAM_AXRAM_CHAN_INCR)
+
+#define Y_OFF(a) \
+       (((a) - YRAM_CHIP_OFFSET) / YRAM_YRAM_CHAN_INCR)
+#define AY_OFF(a) \
+       (((a) % (AYRAM_AYRAM_CHANNEL_COUNT * \
+       AYRAM_AYRAM_CHAN_INCR)) / AYRAM_AYRAM_CHAN_INCR)
+
+#define UC_OFF(a)  (((a) - UC_CHIP_OFFSET) / UC_UC_CHAN_INCR)
+
+#define X_EXT_MAIN_SIZE(a)  (XRAM_XRAM_CHANNEL_COUNT - X_OFF(a))
+#define X_EXT_AUX_SIZE(a, s) ((s) - X_EXT_MAIN_SIZE(a))
+
+#define Y_EXT_MAIN_SIZE(a)  (YRAM_YRAM_CHANNEL_COUNT - Y_OFF(a))
+#define Y_EXT_AUX_SIZE(a, s) ((s) - Y_EXT_MAIN_SIZE(a))
+
+#endif
diff --git a/sound/hda/codecs/cirrus/Kconfig b/sound/hda/codecs/cirrus/Kconfig
new file mode 100644 (file)
index 0000000..f6cefb6
--- /dev/null
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+config SND_HDA_CODEC_CIRRUS
+       tristate "Build Cirrus Logic codec support"
+       select SND_HDA_GENERIC
+       help
+         Say Y or M here to include Cirrus Logic codec support in
+         snd-hda-intel driver, such as CS4206.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m
+
+config SND_HDA_CODEC_CS8409
+       tristate "Build Cirrus Logic HDA bridge support"
+       select SND_HDA_GENERIC
+       help
+         Say Y or M here to include Cirrus Logic HDA bridge support in
+         snd-hda-intel driver, such as CS8409.
+
+comment "Set to Y if you want auto-loading the codec driver"
+       depends on SND_HDA=y && SND_HDA_CODEC_CS8409=m
diff --git a/sound/hda/codecs/cirrus/Makefile b/sound/hda/codecs/cirrus/Makefile
new file mode 100644 (file)
index 0000000..fa40c89
--- /dev/null
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-codec-cirrus-y :=      cirrus.o
+snd-hda-codec-cs8409-y :=      cs8409.o cs8409-tables.o
+
+obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o
+obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
diff --git a/sound/hda/codecs/cirrus/cirrus.c b/sound/hda/codecs/cirrus/cirrus.c
new file mode 100644 (file)
index 0000000..81ea66c
--- /dev/null
@@ -0,0 +1,1243 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio interface patch for Cirrus Logic CS420x chip
+ *
+ * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <linux/pci.h>
+#include <sound/tlv.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "../generic.h"
+
+/*
+ */
+
+struct cs_spec {
+       struct hda_gen_spec gen;
+
+       unsigned int gpio_mask;
+       unsigned int gpio_dir;
+       unsigned int gpio_data;
+       unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
+       unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
+
+       /* CS421x */
+       unsigned int spdif_detect:1;
+       unsigned int spdif_present:1;
+       unsigned int sense_b:1;
+       hda_nid_t vendor_nid;
+
+       /* for MBP SPDIF control */
+       int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol);
+};
+
+/* available models with CS420x */
+enum {
+       CS420X_MBP53,
+       CS420X_MBP55,
+       CS420X_IMAC27,
+       CS420X_GPIO_13,
+       CS420X_GPIO_23,
+       CS420X_MBP101,
+       CS420X_MBP81,
+       CS420X_MBA42,
+       CS420X_AUTO,
+       /* aliases */
+       CS420X_IMAC27_122 = CS420X_GPIO_23,
+       CS420X_APPLE = CS420X_GPIO_13,
+};
+
+/* CS421x boards */
+enum {
+       CS421X_CDB4210,
+       CS421X_SENSE_B,
+       CS421X_STUMPY,
+};
+
+/* Vendor-specific processing widget */
+#define CS420X_VENDOR_NID      0x11
+#define CS_DIG_OUT1_PIN_NID    0x10
+#define CS_DIG_OUT2_PIN_NID    0x15
+#define CS_DMIC1_PIN_NID       0x0e
+#define CS_DMIC2_PIN_NID       0x12
+
+/* coef indices */
+#define IDX_SPDIF_STAT         0x0000
+#define IDX_SPDIF_CTL          0x0001
+#define IDX_ADC_CFG            0x0002
+/* SZC bitmask, 4 modes below:
+ * 0 = immediate,
+ * 1 = digital immediate, analog zero-cross
+ * 2 = digtail & analog soft-ramp
+ * 3 = digital soft-ramp, analog zero-cross
+ */
+#define   CS_COEF_ADC_SZC_MASK         (3 << 0)
+#define   CS_COEF_ADC_MIC_SZC_MODE     (3 << 0) /* SZC setup for mic */
+#define   CS_COEF_ADC_LI_SZC_MODE      (3 << 0) /* SZC setup for line-in */
+/* PGA mode: 0 = differential, 1 = signle-ended */
+#define   CS_COEF_ADC_MIC_PGA_MODE     (1 << 5) /* PGA setup for mic */
+#define   CS_COEF_ADC_LI_PGA_MODE      (1 << 6) /* PGA setup for line-in */
+#define IDX_DAC_CFG            0x0003
+/* SZC bitmask, 4 modes below:
+ * 0 = Immediate
+ * 1 = zero-cross
+ * 2 = soft-ramp
+ * 3 = soft-ramp on zero-cross
+ */
+#define   CS_COEF_DAC_HP_SZC_MODE      (3 << 0) /* nid 0x02 */
+#define   CS_COEF_DAC_LO_SZC_MODE      (3 << 2) /* nid 0x03 */
+#define   CS_COEF_DAC_SPK_SZC_MODE     (3 << 4) /* nid 0x04 */
+
+#define IDX_BEEP_CFG           0x0004
+/* 0x0008 - test reg key */
+/* 0x0009 - 0x0014 -> 12 test regs */
+/* 0x0015 - visibility reg */
+
+/* Cirrus Logic CS4208 */
+#define CS4208_VENDOR_NID      0x24
+
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Trasmitter(sense)
+ */
+#define CS4210_DAC_NID         0x02
+#define CS4210_ADC_NID         0x03
+#define CS4210_VENDOR_NID      0x0B
+#define CS421X_DMIC_PIN_NID    0x09 /* Port E */
+#define CS421X_SPDIF_PIN_NID   0x0A /* Port H */
+
+#define CS421X_IDX_DEV_CFG     0x01
+#define CS421X_IDX_ADC_CFG     0x02
+#define CS421X_IDX_DAC_CFG     0x03
+#define CS421X_IDX_SPK_CTL     0x04
+
+/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
+#define CS4213_VENDOR_NID      0x09
+
+
+static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
+{
+       struct cs_spec *spec = codec->spec;
+
+       snd_hda_codec_write(codec, spec->vendor_nid, 0,
+                           AC_VERB_SET_COEF_INDEX, idx);
+       return snd_hda_codec_read(codec, spec->vendor_nid, 0,
+                                 AC_VERB_GET_PROC_COEF, 0);
+}
+
+static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
+                                     unsigned int coef)
+{
+       struct cs_spec *spec = codec->spec;
+
+       snd_hda_codec_write(codec, spec->vendor_nid, 0,
+                           AC_VERB_SET_COEF_INDEX, idx);
+       snd_hda_codec_write(codec, spec->vendor_nid, 0,
+                           AC_VERB_SET_PROC_COEF, coef);
+}
+
+/*
+ * auto-mute and auto-mic switching
+ * CS421x auto-output redirecting
+ * HP/SPK/SPDIF
+ */
+
+static void cs_automute(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+
+       /* mute HPs if spdif jack (SENSE_B) is present */
+       spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b);
+
+       snd_hda_gen_update_outputs(codec);
+
+       if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
+               if (spec->gen.automute_speaker)
+                       spec->gpio_data = spec->gen.hp_jack_present ?
+                               spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
+               else
+                       spec->gpio_data =
+                               spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+               snd_hda_codec_write(codec, 0x01, 0,
+                                   AC_VERB_SET_GPIO_DATA, spec->gpio_data);
+       }
+}
+
+static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int val;
+
+       val = snd_hda_codec_get_pincfg(codec, nid);
+       return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
+}
+
+static void init_input_coef(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       unsigned int coef;
+
+       /* CS420x has multiple ADC, CS421x has single ADC */
+       if (spec->vendor_nid == CS420X_VENDOR_NID) {
+               coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG);
+               if (is_active_pin(codec, CS_DMIC2_PIN_NID))
+                       coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */
+               if (is_active_pin(codec, CS_DMIC1_PIN_NID))
+                       coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
+                                        * No effect if SPDIF_OUT2 is
+                                        * selected in IDX_SPDIF_CTL.
+                                        */
+
+               cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
+       }
+}
+
+static const struct hda_verb cs_coef_init_verbs[] = {
+       {0x11, AC_VERB_SET_PROC_STATE, 1},
+       {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
+       {0x11, AC_VERB_SET_PROC_COEF,
+        (0x002a /* DAC1/2/3 SZCMode Soft Ramp */
+         | 0x0040 /* Mute DACs on FIFO error */
+         | 0x1000 /* Enable DACs High Pass Filter */
+         | 0x0400 /* Disable Coefficient Auto increment */
+         )},
+       /* ADC1/2 - Digital and Analog Soft Ramp */
+       {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x000a},
+       /* Beep */
+       {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */
+
+       {} /* terminator */
+};
+
+static const struct hda_verb cs4208_coef_init_verbs[] = {
+       {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
+       {0x24, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
+       {0x24, AC_VERB_SET_COEF_INDEX, 0x0033},
+       {0x24, AC_VERB_SET_PROC_COEF, 0x0001}, /* A1 ICS */
+       {0x24, AC_VERB_SET_COEF_INDEX, 0x0034},
+       {0x24, AC_VERB_SET_PROC_COEF, 0x1C01}, /* A1 Enable, A Thresh = 300mV */
+       {} /* terminator */
+};
+
+/* Errata: CS4207 rev C0/C1/C2 Silicon
+ *
+ * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf
+ *
+ * 6. At high temperature (TA > +85°C), the digital supply current (IVD)
+ * may be excessive (up to an additional 200 Î¼A), which is most easily
+ * observed while the part is being held in reset (RESET# active low).
+ *
+ * Root Cause: At initial powerup of the device, the logic that drives
+ * the clock and write enable to the S/PDIF SRC RAMs is not properly
+ * initialized.
+ * Certain random patterns will cause a steady leakage current in those
+ * RAM cells. The issue will resolve once the SRCs are used (turned on).
+ *
+ * Workaround: The following verb sequence briefly turns on the S/PDIF SRC
+ * blocks, which will alleviate the issue.
+ */
+
+static const struct hda_verb cs_errata_init_verbs[] = {
+       {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
+       {0x11, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
+
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x9999},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
+       {0x11, AC_VERB_SET_PROC_COEF, 0xa412},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x0009},
+
+       {0x07, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Rx: D0 */
+       {0x08, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Tx: D0 */
+
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x2412},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x0000},
+       {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
+       {0x11, AC_VERB_SET_PROC_COEF, 0x0008},
+       {0x11, AC_VERB_SET_PROC_STATE, 0x00},
+       {} /* terminator */
+};
+
+/* SPDIF setup */
+static void init_digital_coef(struct hda_codec *codec)
+{
+       unsigned int coef;
+
+       coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */
+       coef |= 0x0008; /* Replace with mute on error */
+       if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID))
+               coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2
+                                * SPDIF_OUT2 is shared with GPIO1 and
+                                * DMIC_SDA2.
+                                */
+       cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef);
+}
+
+static int cs_init(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+
+       if (spec->vendor_nid == CS420X_VENDOR_NID) {
+               /* init_verb sequence for C0/C1/C2 errata*/
+               snd_hda_sequence_write(codec, cs_errata_init_verbs);
+               snd_hda_sequence_write(codec, cs_coef_init_verbs);
+       } else if (spec->vendor_nid == CS4208_VENDOR_NID) {
+               snd_hda_sequence_write(codec, cs4208_coef_init_verbs);
+       }
+
+       snd_hda_gen_init(codec);
+
+       if (spec->gpio_mask) {
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+                                   spec->gpio_mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+                                   spec->gpio_dir);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_data);
+       }
+
+       if (spec->vendor_nid == CS420X_VENDOR_NID) {
+               init_input_coef(codec);
+               init_digital_coef(codec);
+       }
+
+       return 0;
+}
+
+static int cs_build_controls(struct hda_codec *codec)
+{
+       int err;
+
+       err = snd_hda_gen_build_controls(codec);
+       if (err < 0)
+               return err;
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+       return 0;
+}
+
+#define cs_free                snd_hda_gen_free
+
+static const struct hda_codec_ops cs_patch_ops = {
+       .build_controls = cs_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = cs_init,
+       .free = cs_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+};
+
+static int cs_parse_auto_config(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       int err;
+       int i;
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+       if (err < 0)
+               return err;
+
+       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+       if (err < 0)
+               return err;
+
+       /* keep the ADCs powered up when it's dynamically switchable */
+       if (spec->gen.dyn_adc_switch) {
+               unsigned int done = 0;
+
+               for (i = 0; i < spec->gen.input_mux.num_items; i++) {
+                       int idx = spec->gen.dyn_adc_idx[i];
+
+                       if (done & (1 << idx))
+                               continue;
+                       snd_hda_gen_fix_pin_power(codec,
+                                                 spec->gen.adc_nids[idx]);
+                       done |= 1 << idx;
+               }
+       }
+
+       return 0;
+}
+
+static const struct hda_model_fixup cs420x_models[] = {
+       { .id = CS420X_MBP53, .name = "mbp53" },
+       { .id = CS420X_MBP55, .name = "mbp55" },
+       { .id = CS420X_IMAC27, .name = "imac27" },
+       { .id = CS420X_IMAC27_122, .name = "imac27_122" },
+       { .id = CS420X_APPLE, .name = "apple" },
+       { .id = CS420X_MBP101, .name = "mbp101" },
+       { .id = CS420X_MBP81, .name = "mbp81" },
+       { .id = CS420X_MBA42, .name = "mba42" },
+       {}
+};
+
+static const struct hda_quirk cs420x_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
+       SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
+       SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
+       SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
+       /* this conflicts with too many other models */
+       /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
+
+       /* codec SSID */
+       SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122),
+       SND_PCI_QUIRK(0x106b, 0x0900, "iMac 12,1", CS420X_IMAC27_122),
+       SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
+       SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
+       SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
+       SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81),
+       SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
+       SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
+       {} /* terminator */
+};
+
+static const struct hda_pintbl mbp53_pincfgs[] = {
+       { 0x09, 0x012b4050 },
+       { 0x0a, 0x90100141 },
+       { 0x0b, 0x90100140 },
+       { 0x0c, 0x018b3020 },
+       { 0x0d, 0x90a00110 },
+       { 0x0e, 0x400000f0 },
+       { 0x0f, 0x01cbe030 },
+       { 0x10, 0x014be060 },
+       { 0x12, 0x400000f0 },
+       { 0x15, 0x400000f0 },
+       {} /* terminator */
+};
+
+static const struct hda_pintbl mbp55_pincfgs[] = {
+       { 0x09, 0x012b4030 },
+       { 0x0a, 0x90100121 },
+       { 0x0b, 0x90100120 },
+       { 0x0c, 0x400000f0 },
+       { 0x0d, 0x90a00110 },
+       { 0x0e, 0x400000f0 },
+       { 0x0f, 0x400000f0 },
+       { 0x10, 0x014be040 },
+       { 0x12, 0x400000f0 },
+       { 0x15, 0x400000f0 },
+       {} /* terminator */
+};
+
+static const struct hda_pintbl imac27_pincfgs[] = {
+       { 0x09, 0x012b4050 },
+       { 0x0a, 0x90100140 },
+       { 0x0b, 0x90100142 },
+       { 0x0c, 0x018b3020 },
+       { 0x0d, 0x90a00110 },
+       { 0x0e, 0x400000f0 },
+       { 0x0f, 0x01cbe030 },
+       { 0x10, 0x014be060 },
+       { 0x12, 0x01ab9070 },
+       { 0x15, 0x400000f0 },
+       {} /* terminator */
+};
+
+static const struct hda_pintbl mbp101_pincfgs[] = {
+       { 0x0d, 0x40ab90f0 },
+       { 0x0e, 0x90a600f0 },
+       { 0x12, 0x50a600f0 },
+       {} /* terminator */
+};
+
+static const struct hda_pintbl mba42_pincfgs[] = {
+       { 0x09, 0x012b4030 }, /* HP */
+       { 0x0a, 0x400000f0 },
+       { 0x0b, 0x90100120 }, /* speaker */
+       { 0x0c, 0x400000f0 },
+       { 0x0d, 0x90a00110 }, /* mic */
+       { 0x0e, 0x400000f0 },
+       { 0x0f, 0x400000f0 },
+       { 0x10, 0x400000f0 },
+       { 0x12, 0x400000f0 },
+       { 0x15, 0x400000f0 },
+       {} /* terminator */
+};
+
+static const struct hda_pintbl mba6_pincfgs[] = {
+       { 0x10, 0x032120f0 }, /* HP */
+       { 0x11, 0x500000f0 },
+       { 0x12, 0x90100010 }, /* Speaker */
+       { 0x13, 0x500000f0 },
+       { 0x14, 0x500000f0 },
+       { 0x15, 0x770000f0 },
+       { 0x16, 0x770000f0 },
+       { 0x17, 0x430000f0 },
+       { 0x18, 0x43ab9030 }, /* Mic */
+       { 0x19, 0x770000f0 },
+       { 0x1a, 0x770000f0 },
+       { 0x1b, 0x770000f0 },
+       { 0x1c, 0x90a00090 },
+       { 0x1d, 0x500000f0 },
+       { 0x1e, 0x500000f0 },
+       { 0x1f, 0x500000f0 },
+       { 0x20, 0x500000f0 },
+       { 0x21, 0x430000f0 },
+       { 0x22, 0x430000f0 },
+       {} /* terminator */
+};
+
+static void cs420x_fixup_gpio_13(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct cs_spec *spec = codec->spec;
+
+               spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
+               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+               spec->gpio_mask = spec->gpio_dir =
+                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+       }
+}
+
+static void cs420x_fixup_gpio_23(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct cs_spec *spec = codec->spec;
+
+               spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
+               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
+               spec->gpio_mask = spec->gpio_dir =
+                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+       }
+}
+
+static const struct hda_fixup cs420x_fixups[] = {
+       [CS420X_MBP53] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mbp53_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_APPLE,
+       },
+       [CS420X_MBP55] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mbp55_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_GPIO_13,
+       },
+       [CS420X_IMAC27] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = imac27_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_GPIO_13,
+       },
+       [CS420X_GPIO_13] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs420x_fixup_gpio_13,
+       },
+       [CS420X_GPIO_23] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs420x_fixup_gpio_23,
+       },
+       [CS420X_MBP101] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mbp101_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_GPIO_13,
+       },
+       [CS420X_MBP81] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* internal mic ADC2: right only, single ended */
+                       {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG},
+                       {0x11, AC_VERB_SET_PROC_COEF, 0x102a},
+                       {}
+               },
+               .chained = true,
+               .chain_id = CS420X_GPIO_13,
+       },
+       [CS420X_MBA42] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mba42_pincfgs,
+               .chained = true,
+               .chain_id = CS420X_GPIO_13,
+       },
+};
+
+static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
+{
+       struct cs_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return NULL;
+       codec->spec = spec;
+       spec->vendor_nid = vendor_nid;
+       codec->power_save_node = 1;
+       snd_hda_gen_spec_init(&spec->gen);
+
+       return spec;
+}
+
+static int patch_cs420x(struct hda_codec *codec)
+{
+       struct cs_spec *spec;
+       int err;
+
+       spec = cs_alloc_spec(codec, CS420X_VENDOR_NID);
+       if (!spec)
+               return -ENOMEM;
+
+       codec->patch_ops = cs_patch_ops;
+       spec->gen.automute_hook = cs_automute;
+       codec->single_adc_amp = 1;
+
+       snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
+                          cs420x_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = cs_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       cs_free(codec);
+       return err;
+}
+
+/*
+ * CS4208 support:
+ * Its layout is no longer compatible with CS4206/CS4207
+ */
+enum {
+       CS4208_MAC_AUTO,
+       CS4208_MBA6,
+       CS4208_MBP11,
+       CS4208_MACMINI,
+       CS4208_GPIO0,
+};
+
+static const struct hda_model_fixup cs4208_models[] = {
+       { .id = CS4208_GPIO0, .name = "gpio0" },
+       { .id = CS4208_MBA6, .name = "mba6" },
+       { .id = CS4208_MBP11, .name = "mbp11" },
+       { .id = CS4208_MACMINI, .name = "macmini" },
+       {}
+};
+
+static const struct hda_quirk cs4208_fixup_tbl[] = {
+       SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO),
+       {} /* terminator */
+};
+
+/* codec SSID matching */
+static const struct hda_quirk cs4208_mac_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
+       SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI),
+       SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
+       SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
+       SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11),
+       {} /* terminator */
+};
+
+static void cs4208_fixup_gpio0(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct cs_spec *spec = codec->spec;
+
+               spec->gpio_eapd_hp = 0;
+               spec->gpio_eapd_speaker = 1;
+               spec->gpio_mask = spec->gpio_dir =
+                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
+       }
+}
+
+static const struct hda_fixup cs4208_fixups[];
+
+/* remap the fixup from codec SSID and apply it */
+static void cs4208_fixup_mac(struct hda_codec *codec,
+                            const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
+       snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups);
+       if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET)
+               codec->fixup_id = CS4208_GPIO0; /* default fixup */
+       snd_hda_apply_fixup(codec, action);
+}
+
+/* MacMini 7,1 has the inverted jack detection */
+static void cs4208_fixup_macmini(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */
+               { 0x21, 0x004be140 }, /* SPDIF: disable detect */
+               { }
+       };
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* HP pin (0x10) has an inverted detection */
+               codec->inv_jack_detect = 1;
+               /* disable the bogus Mic and SPDIF jack detections */
+               snd_hda_apply_pincfgs(codec, pincfgs);
+       }
+}
+
+static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct cs_spec *spec = codec->spec;
+       hda_nid_t pin = spec->gen.autocfg.dig_out_pins[0];
+       int pinctl = ucontrol->value.integer.value[0] ? PIN_OUT : 0;
+
+       snd_hda_set_pin_ctl_cache(codec, pin, pinctl);
+       return spec->spdif_sw_put(kcontrol, ucontrol);
+}
+
+/* hook the SPDIF switch */
+static void cs4208_fixup_spdif_switch(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_BUILD) {
+               struct cs_spec *spec = codec->spec;
+               struct snd_kcontrol *kctl;
+
+               if (!spec->gen.autocfg.dig_out_pins[0])
+                       return;
+               kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch");
+               if (!kctl)
+                       return;
+               spec->spdif_sw_put = kctl->put;
+               kctl->put = cs4208_spdif_sw_put;
+       }
+}
+
+static const struct hda_fixup cs4208_fixups[] = {
+       [CS4208_MBA6] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = mba6_pincfgs,
+               .chained = true,
+               .chain_id = CS4208_GPIO0,
+       },
+       [CS4208_MBP11] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_spdif_switch,
+               .chained = true,
+               .chain_id = CS4208_GPIO0,
+       },
+       [CS4208_MACMINI] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_macmini,
+               .chained = true,
+               .chain_id = CS4208_GPIO0,
+       },
+       [CS4208_GPIO0] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_gpio0,
+       },
+       [CS4208_MAC_AUTO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_mac,
+       },
+};
+
+/* correct the 0dB offset of input pins */
+static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc)
+{
+       unsigned int caps;
+
+       caps = query_amp_caps(codec, adc, HDA_INPUT);
+       caps &= ~(AC_AMPCAP_OFFSET);
+       caps |= 0x02;
+       snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps);
+}
+
+static int patch_cs4208(struct hda_codec *codec)
+{
+       struct cs_spec *spec;
+       int err;
+
+       spec = cs_alloc_spec(codec, CS4208_VENDOR_NID);
+       if (!spec)
+               return -ENOMEM;
+
+       codec->patch_ops = cs_patch_ops;
+       spec->gen.automute_hook = cs_automute;
+       /* exclude NID 0x10 (HP) from output volumes due to different steps */
+       spec->gen.out_vol_mask = 1ULL << 0x10;
+
+       snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl,
+                          cs4208_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       snd_hda_override_wcaps(codec, 0x18,
+                              get_wcaps(codec, 0x18) | AC_WCAP_STEREO);
+       cs4208_fix_amp_caps(codec, 0x18);
+       cs4208_fix_amp_caps(codec, 0x1b);
+       cs4208_fix_amp_caps(codec, 0x1c);
+
+       err = cs_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       cs_free(codec);
+       return err;
+}
+
+/*
+ * Cirrus Logic CS4210
+ *
+ * 1 DAC => HP(sense) / Speakers,
+ * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
+ * 1 SPDIF OUT => SPDIF Trasmitter(sense)
+ */
+
+/* CS4210 board names */
+static const struct hda_model_fixup cs421x_models[] = {
+       { .id = CS421X_CDB4210, .name = "cdb4210" },
+       { .id = CS421X_STUMPY, .name = "stumpy" },
+       {}
+};
+
+static const struct hda_quirk cs421x_fixup_tbl[] = {
+       /* Test Intel board + CDB2410  */
+       SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
+       {} /* terminator */
+};
+
+/* CS4210 board pinconfigs */
+/* Default CS4210 (CDB4210)*/
+static const struct hda_pintbl cdb4210_pincfgs[] = {
+       { 0x05, 0x0321401f },
+       { 0x06, 0x90170010 },
+       { 0x07, 0x03813031 },
+       { 0x08, 0xb7a70037 },
+       { 0x09, 0xb7a6003e },
+       { 0x0a, 0x034510f0 },
+       {} /* terminator */
+};
+
+/* Stumpy ChromeBox */
+static const struct hda_pintbl stumpy_pincfgs[] = {
+       { 0x05, 0x022120f0 },
+       { 0x06, 0x901700f0 },
+       { 0x07, 0x02a120f0 },
+       { 0x08, 0x77a70037 },
+       { 0x09, 0x77a6003e },
+       { 0x0a, 0x434510f0 },
+       {} /* terminator */
+};
+
+/* Setup GPIO/SENSE for each board (if used) */
+static void cs421x_fixup_sense_b(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       struct cs_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->sense_b = 1;
+}
+
+static const struct hda_fixup cs421x_fixups[] = {
+       [CS421X_CDB4210] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cdb4210_pincfgs,
+               .chained = true,
+               .chain_id = CS421X_SENSE_B,
+       },
+       [CS421X_SENSE_B] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs421x_fixup_sense_b,
+       },
+       [CS421X_STUMPY] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stumpy_pincfgs,
+       },
+};
+
+static const struct hda_verb cs421x_coef_init_verbs[] = {
+       {0x0B, AC_VERB_SET_PROC_STATE, 1},
+       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
+       /*
+        *  Disable Coefficient Index Auto-Increment(DAI)=1,
+        *  PDREF=0
+        */
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
+       /* ADC SZCMode = Digital Soft Ramp */
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
+       {0x0B, AC_VERB_SET_PROC_COEF,
+        (0x0002 /* DAC SZCMode = Digital Soft Ramp */
+         | 0x0004 /* Mute DAC on FIFO error */
+         | 0x0008 /* Enable DAC High Pass Filter */
+         )},
+       {} /* terminator */
+};
+
+/* Errata: CS4210 rev A1 Silicon
+ *
+ * http://www.cirrus.com/en/pubs/errata/
+ *
+ * Description:
+ * 1. Performance degredation is present in the ADC.
+ * 2. Speaker output is not completely muted upon HP detect.
+ * 3. Noise is present when clipping occurs on the amplified
+ *    speaker outputs.
+ *
+ * Workaround:
+ * The following verb sequence written to the registers during
+ * initialization will correct the issues listed above.
+ */
+
+static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
+       {0x0B, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
+
+       {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
+       {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
+
+       {} /* terminator */
+};
+
+/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
+static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
+
+static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 3;
+       return 0;
+}
+
+static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] =
+               cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
+       return 0;
+}
+
+static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+
+       unsigned int vol = ucontrol->value.integer.value[0];
+       unsigned int coef =
+               cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
+       unsigned int original_coef = coef;
+
+       coef &= ~0x0003;
+       coef |= (vol & 0x0003);
+       if (original_coef != coef) {
+               cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
+               return 1;
+       }
+
+       return 0;
+}
+
+static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = {
+
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                       SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+       .name = "Speaker Boost Playback Volume",
+       .info = cs421x_boost_vol_info,
+       .get = cs421x_boost_vol_get,
+       .put = cs421x_boost_vol_put,
+       .tlv = { .p = cs421x_speaker_boost_db_scale },
+};
+
+static void cs4210_pinmux_init(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       unsigned int def_conf, coef;
+
+       /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
+       coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+
+       if (spec->gpio_mask)
+               coef |= 0x0008; /* B1,B2 are GPIOs */
+       else
+               coef &= ~0x0008;
+
+       if (spec->sense_b)
+               coef |= 0x0010; /* B2 is SENSE_B, not inverted  */
+       else
+               coef &= ~0x0010;
+
+       cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+
+       if ((spec->gpio_mask || spec->sense_b) &&
+           is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
+
+               /*
+                *  GPIO or SENSE_B forced - disconnect the DMIC pin.
+                */
+               def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
+               def_conf &= ~AC_DEFCFG_PORT_CONN;
+               def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
+               snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
+       }
+}
+
+static void cs4210_spdif_automute(struct hda_codec *codec,
+                                 struct hda_jack_callback *tbl)
+{
+       struct cs_spec *spec = codec->spec;
+       bool spdif_present = false;
+       hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0];
+
+       /* detect on spdif is specific to CS4210 */
+       if (!spec->spdif_detect ||
+           spec->vendor_nid != CS4210_VENDOR_NID)
+               return;
+
+       spdif_present = snd_hda_jack_detect(codec, spdif_pin);
+       if (spdif_present == spec->spdif_present)
+               return;
+
+       spec->spdif_present = spdif_present;
+       /* SPDIF TX on/off */
+       snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
+
+       cs_automute(codec);
+}
+
+static void parse_cs421x_digital(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+       int i;
+
+       for (i = 0; i < cfg->dig_outs; i++) {
+               hda_nid_t nid = cfg->dig_out_pins[i];
+
+               if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
+                       spec->spdif_detect = 1;
+                       snd_hda_jack_detect_enable_callback(codec, nid,
+                                                           cs4210_spdif_automute);
+               }
+       }
+}
+
+static int cs421x_init(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+
+       if (spec->vendor_nid == CS4210_VENDOR_NID) {
+               snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
+               snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
+               cs4210_pinmux_init(codec);
+       }
+
+       snd_hda_gen_init(codec);
+
+       if (spec->gpio_mask) {
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+                                   spec->gpio_mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+                                   spec->gpio_dir);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_data);
+       }
+
+       init_input_coef(codec);
+
+       cs4210_spdif_automute(codec, NULL);
+
+       return 0;
+}
+
+static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
+{
+       unsigned int caps;
+
+       /* set the upper-limit for mixer amp to 0dB */
+       caps = query_amp_caps(codec, dac, HDA_OUTPUT);
+       caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
+       caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
+               << AC_AMPCAP_NUM_STEPS_SHIFT;
+       snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
+}
+
+static int cs421x_parse_auto_config(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       hda_nid_t dac = CS4210_DAC_NID;
+       int err;
+
+       fix_volume_caps(codec, dac);
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+       if (err < 0)
+               return err;
+
+       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+       if (err < 0)
+               return err;
+
+       parse_cs421x_digital(codec);
+
+       if (spec->gen.autocfg.speaker_outs &&
+           spec->vendor_nid == CS4210_VENDOR_NID) {
+               if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+                                         &cs421x_speaker_boost_ctl))
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/*
+ *     Manage PDREF, when transitioning to D3hot
+ *     (DAC,ADC) -> D3, PDREF=1, AFG->D3
+ */
+static int cs421x_suspend(struct hda_codec *codec)
+{
+       struct cs_spec *spec = codec->spec;
+       unsigned int coef;
+
+       snd_hda_shutup_pins(codec);
+
+       snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
+                           AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
+       snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
+                           AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
+
+       if (spec->vendor_nid == CS4210_VENDOR_NID) {
+               coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
+               coef |= 0x0004; /* PDREF */
+               cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
+       }
+
+       return 0;
+}
+
+static const struct hda_codec_ops cs421x_patch_ops = {
+       .build_controls = snd_hda_gen_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = cs421x_init,
+       .free = cs_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .suspend = cs421x_suspend,
+};
+
+static int patch_cs4210(struct hda_codec *codec)
+{
+       struct cs_spec *spec;
+       int err;
+
+       spec = cs_alloc_spec(codec, CS4210_VENDOR_NID);
+       if (!spec)
+               return -ENOMEM;
+
+       codec->patch_ops = cs421x_patch_ops;
+       spec->gen.automute_hook = cs_automute;
+
+       snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
+                          cs421x_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       /*
+        *  Update the GPIO/DMIC/SENSE_B pinmux before the configuration
+        *   is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
+        *   is disabled.
+        */
+       cs4210_pinmux_init(codec);
+
+       err = cs421x_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       cs_free(codec);
+       return err;
+}
+
+static int patch_cs4213(struct hda_codec *codec)
+{
+       struct cs_spec *spec;
+       int err;
+
+       spec = cs_alloc_spec(codec, CS4213_VENDOR_NID);
+       if (!spec)
+               return -ENOMEM;
+
+       codec->patch_ops = cs421x_patch_ops;
+
+       err = cs421x_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       cs_free(codec);
+       return err;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_cirrus[] = {
+       HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x),
+       HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x),
+       HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
+       HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
+       HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
+
+static struct hda_codec_driver cirrus_driver = {
+       .id = snd_hda_id_cirrus,
+};
+
+module_hda_codec_driver(cirrus_driver);
diff --git a/sound/hda/codecs/cirrus/cs8409-tables.c b/sound/hda/codecs/cirrus/cs8409-tables.c
new file mode 100644 (file)
index 0000000..5fe49f1
--- /dev/null
@@ -0,0 +1,623 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * cs8409-tables.c  --  HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ *
+ * Copyright (C) 2021 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ *
+ * Author: Lucas Tanure <tanureal@opensource.cirrus.com>
+ */
+
+#include "cs8409.h"
+
+/******************************************************************************
+ *                          CS42L42 Specific Data
+ *
+ ******************************************************************************/
+
+static const DECLARE_TLV_DB_SCALE(cs42l42_dac_db_scale, CS42L42_HP_VOL_REAL_MIN * 100, 100, 1);
+
+static const DECLARE_TLV_DB_SCALE(cs42l42_adc_db_scale, CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1);
+
+const struct snd_kcontrol_new cs42l42_dac_volume_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .index = 0,
+       .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+       .info = cs42l42_volume_info,
+       .get = cs42l42_volume_get,
+       .put = cs42l42_volume_put,
+       .tlv = { .p = cs42l42_dac_db_scale },
+       .private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_TRANSMITTER_A, 3, CS8409_CODEC0,
+                        HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE
+};
+
+const struct snd_kcontrol_new cs42l42_adc_volume_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .index = 0,
+       .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
+       .info = cs42l42_volume_info,
+       .get = cs42l42_volume_get,
+       .put = cs42l42_volume_put,
+       .tlv = { .p = cs42l42_adc_db_scale },
+       .private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_RECEIVER_A, 1, CS8409_CODEC0,
+                        HDA_INPUT, CS42L42_VOL_ADC) | HDA_AMP_VAL_MIN_MUTE
+};
+
+const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback = {
+       .rates = SNDRV_PCM_RATE_48000, /* fixed rate */
+};
+
+const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture = {
+       .rates = SNDRV_PCM_RATE_48000, /* fixed rate */
+};
+
+/******************************************************************************
+ *                   BULLSEYE / WARLOCK / CYBORG Specific Arrays
+ *                               CS8409/CS42L42
+ ******************************************************************************/
+
+const struct hda_verb cs8409_cs42l42_init_verbs[] = {
+       { CS8409_PIN_AFG, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 },         /* WAKE from GPIO 3,4 */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_STATE, 0x0001 },   /* Enable VPW processing */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x0002 },   /* Configure GPIO 6,7 */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF,  0x0080 },   /* I2C mode */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x005b },   /* Set I2C bus speed */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF,  0x0200 },   /* 100kHz I2C_STO = 2 */
+       {} /* terminator */
+};
+
+static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
+       { CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 },  /* ASP-1-TX */
+       { CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 },     /* ASP-1-RX */
+       { CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 },  /* ASP-2-TX */
+       { CS8409_PIN_DMIC1_IN, 0x90a00090 },            /* DMIC-1 */
+       {} /* terminator */
+};
+
+static const struct hda_pintbl cs8409_cs42l42_pincfgs_no_dmic[] = {
+       { CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 },  /* ASP-1-TX */
+       { CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 },     /* ASP-1-RX */
+       { CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 },  /* ASP-2-TX */
+       {} /* terminator */
+};
+
+/* Vendor specific HW configuration for CS42L42 */
+static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
+       { CS42L42_I2C_TIMEOUT, 0xB0 },
+       { CS42L42_ADC_CTL, 0x00 },
+       { 0x1D02, 0x06 },
+       { CS42L42_ADC_VOLUME, 0x9F },
+       { CS42L42_OSC_SWITCH, 0x01 },
+       { CS42L42_MCLK_CTL, 0x02 },
+       { CS42L42_SRC_CTL, 0x03 },
+       { CS42L42_MCLK_SRC_SEL, 0x00 },
+       { CS42L42_ASP_FRM_CFG, 0x13 },
+       { CS42L42_FSYNC_P_LOWER, 0xFF },
+       { CS42L42_FSYNC_P_UPPER, 0x00 },
+       { CS42L42_ASP_CLK_CFG, 0x20 },
+       { CS42L42_SPDIF_CLK_CFG, 0x0D },
+       { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
+       { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
+       { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x20 },
+       { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x02 },
+       { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x80 },
+       { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x02 },
+       { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0xA0 },
+       { CS42L42_ASP_RX_DAI0_EN, 0x0C },
+       { CS42L42_ASP_TX_CH_EN, 0x01 },
+       { CS42L42_ASP_TX_CH_AP_RES, 0x02 },
+       { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
+       { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
+       { CS42L42_ASP_TX_SZ_EN, 0x01 },
+       { CS42L42_PWR_CTL1, 0x0A },
+       { CS42L42_PWR_CTL2, 0x84 },
+       { CS42L42_MIXER_CHA_VOL, 0x3F },
+       { CS42L42_MIXER_CHB_VOL, 0x3F },
+       { CS42L42_MIXER_ADC_VOL, 0x3f },
+       { CS42L42_HP_CTL, 0x0D },
+       { CS42L42_MIC_DET_CTL1, 0xB6 },
+       { CS42L42_TIPSENSE_CTL, 0xC2 },
+       { CS42L42_HS_CLAMP_DISABLE, 0x01 },
+       { CS42L42_HS_SWITCH_CTL, 0xF3 },
+       { CS42L42_PWR_CTL3, 0x20 },
+       { CS42L42_RSENSE_CTL2, 0x00 },
+       { CS42L42_RSENSE_CTL3, 0x00 },
+       { CS42L42_TSENSE_CTL, 0x80 },
+       { CS42L42_HS_BIAS_CTL, 0xC0 },
+       { CS42L42_PWR_CTL1, 0x02, 10000 },
+       { CS42L42_ADC_OVFL_INT_MASK, 0xff },
+       { CS42L42_MIXER_INT_MASK, 0xff },
+       { CS42L42_SRC_INT_MASK, 0xff },
+       { CS42L42_ASP_RX_INT_MASK, 0xff },
+       { CS42L42_ASP_TX_INT_MASK, 0xff },
+       { CS42L42_CODEC_INT_MASK, 0xff },
+       { CS42L42_SRCPL_INT_MASK, 0xff },
+       { CS42L42_VPMON_INT_MASK, 0xff },
+       { CS42L42_PLL_LOCK_INT_MASK, 0xff },
+       { CS42L42_TSRS_PLUG_INT_MASK, 0xff },
+       { CS42L42_DET_INT1_MASK, 0xff },
+       { CS42L42_DET_INT2_MASK, 0xff },
+};
+
+/* Vendor specific hw configuration for CS8409 */
+const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = {
+       /* +PLL1/2_EN, +I2C_EN */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0xb008 },
+       /* ASP1/2_EN=0, ASP1_STP=1 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0002 },
+       /* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG3, 0x0a80 },
+       /* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL1, 0x0800 },
+       /* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL2, 0x0820 },
+       /* ASP2.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP2_A_TX_CTRL1, 0x0800 },
+       /* ASP2.A: TX.RAP=1, TX.RSZ=24 bits, TX.RCS=0 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP2_A_TX_CTRL2, 0x2800 },
+       /* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL1, 0x0800 },
+       /* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL2, 0x0800 },
+       /* ASP1: LCHI = 00h */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL1, 0x8000 },
+       /* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL2, 0x28ff },
+       /* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL3, 0x0062 },
+       /* ASP2: LCHI=1Fh */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL1, 0x801f },
+       /* ASP2: MC/SC_SRCSEL=PLL1, LCPR=3Fh */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL2, 0x283f },
+       /* ASP2: 5050=1, MCEN=0, FSD=010, SCPOL_IN/OUT=1, SCDIV=1:16 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL3, 0x805c },
+       /* DMIC1_MO=10b, DMIC1/2_SR=1 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DMIC_CFG, 0x0023 },
+       /* ASP1/2_BEEP=0 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_BEEP_CFG, 0x0000 },
+       /* ASP1/2_EN=1, ASP1_STP=1 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0062 },
+       /* -PLL2_EN */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0x9008 },
+       /* TX2.A: pre-scale att.=0 dB */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PRE_SCALE_ATTN2, 0x0000 },
+       /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=1 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PAD_CFG_SLW_RATE_CTRL, 0xfc03 },
+       /* test mode on */
+       { CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x9999 },
+       /* GPIO hysteresis = 30 us */
+       { CS8409_PIN_VENDOR_WIDGET, 0xc5, 0x0000 },
+       /* test mode off */
+       { CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x0000 },
+       {} /* Terminator */
+};
+
+const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[] = {
+       /* EQ_SEL=1, EQ1/2_EN=0 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_CTRL1, 0x4000 },
+       /* +EQ_ACC */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0x4000 },
+       /* +EQ2_EN */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_CTRL1, 0x4010 },
+       /* EQ_DATA_HI=0x0647 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x0647 },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=0, EQ_DATA_LO=0x67 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc0c7 },
+       /* EQ_DATA_HI=0x0647 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x0647 },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=1, EQ_DATA_LO=0x67 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc1c7 },
+       /* EQ_DATA_HI=0xf370 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xf370 },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=2, EQ_DATA_LO=0x71 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc271 },
+       /* EQ_DATA_HI=0x1ef8 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1ef8 },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=3, EQ_DATA_LO=0x48 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc348 },
+       /* EQ_DATA_HI=0xc110 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc110 },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=4, EQ_DATA_LO=0x5a */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc45a },
+       /* EQ_DATA_HI=0x1f29 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1f29 },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=5, EQ_DATA_LO=0x74 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc574 },
+       /* EQ_DATA_HI=0x1d7a */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1d7a },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=6, EQ_DATA_LO=0x53 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc653 },
+       /* EQ_DATA_HI=0xc38c */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc38c },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=7, EQ_DATA_LO=0x14 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc714 },
+       /* EQ_DATA_HI=0x1ca3 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1ca3 },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=8, EQ_DATA_LO=0xc7 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc8c7 },
+       /* EQ_DATA_HI=0xc38c */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc38c },
+       /* +EQ_WRT, +EQ_ACC, EQ_ADR=9, EQ_DATA_LO=0x14 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc914 },
+       /* -EQ_ACC, -EQ_WRT */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0x0000 },
+       {} /* Terminator */
+};
+
+struct sub_codec cs8409_cs42l42_codec = {
+       .addr = CS42L42_I2C_ADDR,
+       .reset_gpio = CS8409_CS42L42_RESET,
+       .irq_mask = CS8409_CS42L42_INT,
+       .init_seq = cs42l42_init_reg_seq,
+       .init_seq_num = ARRAY_SIZE(cs42l42_init_reg_seq),
+       .hp_jack_in = 0,
+       .mic_jack_in = 0,
+       .paged = 1,
+       .suspended = 1,
+       .no_type_dect = 0,
+};
+
+/******************************************************************************
+ *                          Dolphin Specific Arrays
+ *                            CS8409/ 2 X CS42L42
+ ******************************************************************************/
+
+const struct hda_verb dolphin_init_verbs[] = {
+       { 0x01, AC_VERB_SET_GPIO_WAKE_MASK, DOLPHIN_WAKE }, /* WAKE from GPIO 0,4 */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing  */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x0002 }, /* Configure GPIO 6,7 */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF,  0x0080 }, /* I2C mode */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x005b }, /* Set I2C bus speed */
+       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF,  0x0200 }, /* 100kHz I2C_STO = 2 */
+       {} /* terminator */
+};
+
+static const struct hda_pintbl dolphin_pincfgs[] = {
+       { 0x24, 0x022210f0 }, /* ASP-1-TX-A */
+       { 0x25, 0x010240f0 }, /* ASP-1-TX-B */
+       { 0x34, 0x02a21050 }, /* ASP-1-RX */
+       {} /* terminator */
+};
+
+/* Vendor specific HW configuration for CS42L42 */
+static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = {
+       { CS42L42_I2C_TIMEOUT, 0xB0 },
+       { CS42L42_ADC_CTL, 0x00 },
+       { 0x1D02, 0x06 },
+       { CS42L42_ADC_VOLUME, 0x9F },
+       { CS42L42_OSC_SWITCH, 0x01 },
+       { CS42L42_MCLK_CTL, 0x02 },
+       { CS42L42_SRC_CTL, 0x03 },
+       { CS42L42_MCLK_SRC_SEL, 0x00 },
+       { CS42L42_ASP_FRM_CFG, 0x13 },
+       { CS42L42_FSYNC_P_LOWER, 0xFF },
+       { CS42L42_FSYNC_P_UPPER, 0x00 },
+       { CS42L42_ASP_CLK_CFG, 0x20 },
+       { CS42L42_SPDIF_CLK_CFG, 0x0D },
+       { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
+       { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
+       { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x20 },
+       { CS42L42_ASP_RX_DAI0_EN, 0x0C },
+       { CS42L42_ASP_TX_CH_EN, 0x01 },
+       { CS42L42_ASP_TX_CH_AP_RES, 0x02 },
+       { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
+       { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
+       { CS42L42_ASP_TX_SZ_EN, 0x01 },
+       { CS42L42_PWR_CTL1, 0x0A },
+       { CS42L42_PWR_CTL2, 0x84 },
+       { CS42L42_HP_CTL, 0x0D },
+       { CS42L42_MIXER_CHA_VOL, 0x3F },
+       { CS42L42_MIXER_CHB_VOL, 0x3F },
+       { CS42L42_MIXER_ADC_VOL, 0x3f },
+       { CS42L42_MIC_DET_CTL1, 0xB6 },
+       { CS42L42_TIPSENSE_CTL, 0xC2 },
+       { CS42L42_HS_CLAMP_DISABLE, 0x01 },
+       { CS42L42_HS_SWITCH_CTL, 0xF3 },
+       { CS42L42_PWR_CTL3, 0x20 },
+       { CS42L42_RSENSE_CTL2, 0x00 },
+       { CS42L42_RSENSE_CTL3, 0x00 },
+       { CS42L42_TSENSE_CTL, 0x80 },
+       { CS42L42_HS_BIAS_CTL, 0xC0 },
+       { CS42L42_PWR_CTL1, 0x02, 10000 },
+       { CS42L42_ADC_OVFL_INT_MASK, 0xff },
+       { CS42L42_MIXER_INT_MASK, 0xff },
+       { CS42L42_SRC_INT_MASK, 0xff },
+       { CS42L42_ASP_RX_INT_MASK, 0xff },
+       { CS42L42_ASP_TX_INT_MASK, 0xff },
+       { CS42L42_CODEC_INT_MASK, 0xff },
+       { CS42L42_SRCPL_INT_MASK, 0xff },
+       { CS42L42_VPMON_INT_MASK, 0xff },
+       { CS42L42_PLL_LOCK_INT_MASK, 0xff },
+       { CS42L42_TSRS_PLUG_INT_MASK, 0xff },
+       { CS42L42_DET_INT1_MASK, 0xff },
+       { CS42L42_DET_INT2_MASK, 0xff }
+};
+
+static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = {
+       { CS42L42_I2C_TIMEOUT, 0xB0 },
+       { CS42L42_ADC_CTL, 0x00 },
+       { 0x1D02, 0x06 },
+       { CS42L42_ADC_VOLUME, 0x9F },
+       { CS42L42_OSC_SWITCH, 0x01 },
+       { CS42L42_MCLK_CTL, 0x02 },
+       { CS42L42_SRC_CTL, 0x03 },
+       { CS42L42_MCLK_SRC_SEL, 0x00 },
+       { CS42L42_ASP_FRM_CFG, 0x13 },
+       { CS42L42_FSYNC_P_LOWER, 0xFF },
+       { CS42L42_FSYNC_P_UPPER, 0x00 },
+       { CS42L42_ASP_CLK_CFG, 0x20 },
+       { CS42L42_SPDIF_CLK_CFG, 0x0D },
+       { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
+       { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x80 },
+       { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
+       { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
+       { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0xA0 },
+       { CS42L42_ASP_RX_DAI0_EN, 0x0C },
+       { CS42L42_ASP_TX_CH_EN, 0x00 },
+       { CS42L42_ASP_TX_CH_AP_RES, 0x02 },
+       { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
+       { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
+       { CS42L42_ASP_TX_SZ_EN, 0x00 },
+       { CS42L42_PWR_CTL1, 0x0E },
+       { CS42L42_PWR_CTL2, 0x84 },
+       { CS42L42_HP_CTL, 0x0D },
+       { CS42L42_MIXER_CHA_VOL, 0x3F },
+       { CS42L42_MIXER_CHB_VOL, 0x3F },
+       { CS42L42_MIXER_ADC_VOL, 0x3f },
+       { CS42L42_MIC_DET_CTL1, 0xB6 },
+       { CS42L42_TIPSENSE_CTL, 0xC2 },
+       { CS42L42_HS_CLAMP_DISABLE, 0x01 },
+       { CS42L42_HS_SWITCH_CTL, 0xF3 },
+       { CS42L42_PWR_CTL3, 0x20 },
+       { CS42L42_RSENSE_CTL2, 0x00 },
+       { CS42L42_RSENSE_CTL3, 0x00 },
+       { CS42L42_TSENSE_CTL, 0x80 },
+       { CS42L42_HS_BIAS_CTL, 0xC0 },
+       { CS42L42_PWR_CTL1, 0x06, 10000 },
+       { CS42L42_ADC_OVFL_INT_MASK, 0xff },
+       { CS42L42_MIXER_INT_MASK, 0xff },
+       { CS42L42_SRC_INT_MASK, 0xff },
+       { CS42L42_ASP_RX_INT_MASK, 0xff },
+       { CS42L42_ASP_TX_INT_MASK, 0xff },
+       { CS42L42_CODEC_INT_MASK, 0xff },
+       { CS42L42_SRCPL_INT_MASK, 0xff },
+       { CS42L42_VPMON_INT_MASK, 0xff },
+       { CS42L42_PLL_LOCK_INT_MASK, 0xff },
+       { CS42L42_TSRS_PLUG_INT_MASK, 0xff },
+       { CS42L42_DET_INT1_MASK, 0xff },
+       { CS42L42_DET_INT2_MASK, 0xff }
+};
+
+/* Vendor specific hw configuration for CS8409 */
+const struct cs8409_cir_param dolphin_hw_cfg[] = {
+       /* +PLL1/2_EN, +I2C_EN */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0xb008 },
+       /* ASP1_EN=0, ASP1_STP=1 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0002 },
+       /* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG3, 0x0a80 },
+       /* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL1, 0x0800 },
+       /* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL2, 0x0820 },
+       /* ASP1.B: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=128 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_B_TX_CTRL1, 0x0880 },
+       /* ASP1.B: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=160 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_B_TX_CTRL2, 0x08a0 },
+       /* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL1, 0x0800 },
+       /* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */
+       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL2, 0x0800 },
+       /* ASP1: LCHI = 00h */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL1, 0x8000 },
+       /* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL2, 0x28ff },
+       /* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL3, 0x0062 },
+       /* ASP1/2_BEEP=0 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_BEEP_CFG, 0x0000 },
+       /* ASP1_EN=1, ASP1_STP=1 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0022 },
+       /* -PLL2_EN */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0x9008 },
+       /* ASP1_xxx_EN=1, ASP1_MCLK_EN=0 */
+       { CS8409_PIN_VENDOR_WIDGET, CS8409_PAD_CFG_SLW_RATE_CTRL, 0x5400 },
+       /* test mode on */
+       { CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x9999 },
+       /* GPIO hysteresis = 30 us */
+       { CS8409_PIN_VENDOR_WIDGET, 0xc5, 0x0000 },
+       /* test mode off */
+       { CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x0000 },
+       {} /* Terminator */
+};
+
+struct sub_codec dolphin_cs42l42_0 = {
+       .addr = DOLPHIN_C0_I2C_ADDR,
+       .reset_gpio = DOLPHIN_C0_RESET,
+       .irq_mask = DOLPHIN_C0_INT,
+       .init_seq = dolphin_c0_init_reg_seq,
+       .init_seq_num = ARRAY_SIZE(dolphin_c0_init_reg_seq),
+       .hp_jack_in = 0,
+       .mic_jack_in = 0,
+       .paged = 1,
+       .suspended = 1,
+       .no_type_dect = 0,
+};
+
+struct sub_codec dolphin_cs42l42_1 = {
+       .addr = DOLPHIN_C1_I2C_ADDR,
+       .reset_gpio = DOLPHIN_C1_RESET,
+       .irq_mask = DOLPHIN_C1_INT,
+       .init_seq = dolphin_c1_init_reg_seq,
+       .init_seq_num = ARRAY_SIZE(dolphin_c1_init_reg_seq),
+       .hp_jack_in = 0,
+       .mic_jack_in = 0,
+       .paged = 1,
+       .suspended = 1,
+       .no_type_dect = 1,
+};
+
+/******************************************************************************
+ *                         CS8409 Patch Driver Structs
+ *                    Arrays Used for all projects using CS8409
+ ******************************************************************************/
+
+const struct hda_quirk cs8409_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE),
+       SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE),
+       SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE),
+       SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE),
+       SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE),
+       SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE),
+       SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE),
+       SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE),
+       SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0ACF, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0AD0, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0AD1, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0AD2, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0AD3, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG),
+       SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0B92, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0B93, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0B94, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0B95, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0B96, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0B97, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0BA5, "Odin", CS8409_ODIN),
+       SND_PCI_QUIRK(0x1028, 0x0BA6, "Odin", CS8409_ODIN),
+       SND_PCI_QUIRK(0x1028, 0x0BA8, "Odin", CS8409_ODIN),
+       SND_PCI_QUIRK(0x1028, 0x0BAA, "Odin", CS8409_ODIN),
+       SND_PCI_QUIRK(0x1028, 0x0BAE, "Odin", CS8409_ODIN),
+       SND_PCI_QUIRK(0x1028, 0x0BB2, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0BB3, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0BB4, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0BB5, "Warlock N3 15 TGL-U Nuvoton EC", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0BB6, "Warlock V3 15 TGL-U Nuvoton EC", CS8409_WARLOCK),
+       SND_PCI_QUIRK(0x1028, 0x0BB8, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0BB9, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0BBA, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0BBB, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0BBC, "Warlock MLK", CS8409_WARLOCK_MLK),
+       SND_PCI_QUIRK(0x1028, 0x0BBD, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0BD4, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0BD5, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0BD6, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0BD7, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0BD8, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C43, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C50, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C51, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C52, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C73, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C75, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C7D, "Dolphin", CS8409_DOLPHIN),
+       SND_PCI_QUIRK(0x1028, 0x0C7F, "Dolphin", CS8409_DOLPHIN),
+       {} /* terminator */
+};
+
+/* Dell Inspiron models with cs8409/cs42l42 */
+const struct hda_model_fixup cs8409_models[] = {
+       { .id = CS8409_BULLSEYE, .name = "bullseye" },
+       { .id = CS8409_WARLOCK, .name = "warlock" },
+       { .id = CS8409_WARLOCK_MLK, .name = "warlock mlk" },
+       { .id = CS8409_WARLOCK_MLK_DUAL_MIC, .name = "warlock mlk dual mic" },
+       { .id = CS8409_CYBORG, .name = "cyborg" },
+       { .id = CS8409_DOLPHIN, .name = "dolphin" },
+       { .id = CS8409_ODIN, .name = "odin" },
+       {}
+};
+
+const struct hda_fixup cs8409_fixups[] = {
+       [CS8409_BULLSEYE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cs8409_cs42l42_pincfgs,
+               .chained = true,
+               .chain_id = CS8409_FIXUPS,
+       },
+       [CS8409_WARLOCK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cs8409_cs42l42_pincfgs,
+               .chained = true,
+               .chain_id = CS8409_FIXUPS,
+       },
+       [CS8409_WARLOCK_MLK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cs8409_cs42l42_pincfgs,
+               .chained = true,
+               .chain_id = CS8409_FIXUPS,
+       },
+       [CS8409_WARLOCK_MLK_DUAL_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cs8409_cs42l42_pincfgs,
+               .chained = true,
+               .chain_id = CS8409_FIXUPS,
+       },
+       [CS8409_CYBORG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cs8409_cs42l42_pincfgs,
+               .chained = true,
+               .chain_id = CS8409_FIXUPS,
+       },
+       [CS8409_FIXUPS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs8409_cs42l42_fixups,
+       },
+       [CS8409_DOLPHIN] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dolphin_pincfgs,
+               .chained = true,
+               .chain_id = CS8409_DOLPHIN_FIXUPS,
+       },
+       [CS8409_DOLPHIN_FIXUPS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = dolphin_fixups,
+       },
+       [CS8409_ODIN] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cs8409_cs42l42_pincfgs_no_dmic,
+               .chained = true,
+               .chain_id = CS8409_FIXUPS,
+       },
+};
diff --git a/sound/hda/codecs/cirrus/cs8409.c b/sound/hda/codecs/cirrus/cs8409.c
new file mode 100644 (file)
index 0000000..5ec1126
--- /dev/null
@@ -0,0 +1,1484 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ *
+ * Copyright (C) 2021 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <linux/mutex.h>
+#include <linux/iopoll.h>
+
+#include "cs8409.h"
+
+/******************************************************************************
+ *                        CS8409 Specific Functions
+ ******************************************************************************/
+
+static int cs8409_parse_auto_config(struct hda_codec *codec)
+{
+       struct cs8409_spec *spec = codec->spec;
+       int err;
+       int i;
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+       if (err < 0)
+               return err;
+
+       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+       if (err < 0)
+               return err;
+
+       /* keep the ADCs powered up when it's dynamically switchable */
+       if (spec->gen.dyn_adc_switch) {
+               unsigned int done = 0;
+
+               for (i = 0; i < spec->gen.input_mux.num_items; i++) {
+                       int idx = spec->gen.dyn_adc_idx[i];
+
+                       if (done & (1 << idx))
+                               continue;
+                       snd_hda_gen_fix_pin_power(codec, spec->gen.adc_nids[idx]);
+                       done |= 1 << idx;
+               }
+       }
+
+       return 0;
+}
+
+static void cs8409_disable_i2c_clock_worker(struct work_struct *work);
+
+static struct cs8409_spec *cs8409_alloc_spec(struct hda_codec *codec)
+{
+       struct cs8409_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return NULL;
+       codec->spec = spec;
+       spec->codec = codec;
+       codec->power_save_node = 1;
+       mutex_init(&spec->i2c_mux);
+       INIT_DELAYED_WORK(&spec->i2c_clk_work, cs8409_disable_i2c_clock_worker);
+       snd_hda_gen_spec_init(&spec->gen);
+
+       return spec;
+}
+
+static inline int cs8409_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
+{
+       snd_hda_codec_write(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_SET_COEF_INDEX, idx);
+       return snd_hda_codec_read(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_GET_PROC_COEF, 0);
+}
+
+static inline void cs8409_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
+                                         unsigned int coef)
+{
+       snd_hda_codec_write(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_SET_COEF_INDEX, idx);
+       snd_hda_codec_write(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_SET_PROC_COEF, coef);
+}
+
+/*
+ * cs8409_enable_i2c_clock - Disable I2C clocks
+ * @codec: the codec instance
+ * Disable I2C clocks.
+ * This must be called when the i2c mutex is unlocked.
+ */
+static void cs8409_disable_i2c_clock(struct hda_codec *codec)
+{
+       struct cs8409_spec *spec = codec->spec;
+
+       mutex_lock(&spec->i2c_mux);
+       if (spec->i2c_clck_enabled) {
+               cs8409_vendor_coef_set(spec->codec, 0x0,
+                              cs8409_vendor_coef_get(spec->codec, 0x0) & 0xfffffff7);
+               spec->i2c_clck_enabled = 0;
+       }
+       mutex_unlock(&spec->i2c_mux);
+}
+
+/*
+ * cs8409_disable_i2c_clock_worker - Worker that disable the I2C Clock after 25ms without use
+ */
+static void cs8409_disable_i2c_clock_worker(struct work_struct *work)
+{
+       struct cs8409_spec *spec = container_of(work, struct cs8409_spec, i2c_clk_work.work);
+
+       cs8409_disable_i2c_clock(spec->codec);
+}
+
+/*
+ * cs8409_enable_i2c_clock - Enable I2C clocks
+ * @codec: the codec instance
+ * Enable I2C clocks.
+ * This must be called when the i2c mutex is locked.
+ */
+static void cs8409_enable_i2c_clock(struct hda_codec *codec)
+{
+       struct cs8409_spec *spec = codec->spec;
+
+       /* Cancel the disable timer, but do not wait for any running disable functions to finish.
+        * If the disable timer runs out before cancel, the delayed work thread will be blocked,
+        * waiting for the mutex to become unlocked. This mutex will be locked for the duration of
+        * any i2c transaction, so the disable function will run to completion immediately
+        * afterwards in the scenario. The next enable call will re-enable the clock, regardless.
+        */
+       cancel_delayed_work(&spec->i2c_clk_work);
+
+       if (!spec->i2c_clck_enabled) {
+               cs8409_vendor_coef_set(codec, 0x0, cs8409_vendor_coef_get(codec, 0x0) | 0x8);
+               spec->i2c_clck_enabled = 1;
+       }
+       queue_delayed_work(system_power_efficient_wq, &spec->i2c_clk_work, msecs_to_jiffies(25));
+}
+
+/**
+ * cs8409_i2c_wait_complete - Wait for I2C transaction
+ * @codec: the codec instance
+ *
+ * Wait for I2C transaction to complete.
+ * Return -ETIMEDOUT if transaction wait times out.
+ */
+static int cs8409_i2c_wait_complete(struct hda_codec *codec)
+{
+       unsigned int retval;
+
+       return read_poll_timeout(cs8409_vendor_coef_get, retval, retval & 0x18,
+               CS42L42_I2C_SLEEP_US, CS42L42_I2C_TIMEOUT_US, false, codec, CS8409_I2C_STS);
+}
+
+/**
+ * cs8409_set_i2c_dev_addr - Set i2c address for transaction
+ * @codec: the codec instance
+ * @addr: I2C Address
+ */
+static void cs8409_set_i2c_dev_addr(struct hda_codec *codec, unsigned int addr)
+{
+       struct cs8409_spec *spec = codec->spec;
+
+       if (spec->dev_addr != addr) {
+               cs8409_vendor_coef_set(codec, CS8409_I2C_ADDR, addr);
+               spec->dev_addr = addr;
+       }
+}
+
+/**
+ * cs8409_i2c_set_page - CS8409 I2C set page register.
+ * @scodec: the codec instance
+ * @i2c_reg: Page register
+ *
+ * Returns negative on error.
+ */
+static int cs8409_i2c_set_page(struct sub_codec *scodec, unsigned int i2c_reg)
+{
+       struct hda_codec *codec = scodec->codec;
+
+       if (scodec->paged && (scodec->last_page != (i2c_reg >> 8))) {
+               cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg >> 8);
+               if (cs8409_i2c_wait_complete(codec) < 0)
+                       return -EIO;
+               scodec->last_page = i2c_reg >> 8;
+       }
+
+       return 0;
+}
+
+/**
+ * cs8409_i2c_read - CS8409 I2C Read.
+ * @scodec: the codec instance
+ * @addr: Register to read
+ *
+ * Returns negative on error, otherwise returns read value in bits 0-7.
+ */
+static int cs8409_i2c_read(struct sub_codec *scodec, unsigned int addr)
+{
+       struct hda_codec *codec = scodec->codec;
+       struct cs8409_spec *spec = codec->spec;
+       unsigned int i2c_reg_data;
+       unsigned int read_data;
+
+       if (scodec->suspended)
+               return -EPERM;
+
+       mutex_lock(&spec->i2c_mux);
+       cs8409_enable_i2c_clock(codec);
+       cs8409_set_i2c_dev_addr(codec, scodec->addr);
+
+       if (cs8409_i2c_set_page(scodec, addr))
+               goto error;
+
+       i2c_reg_data = (addr << 8) & 0x0ffff;
+       cs8409_vendor_coef_set(codec, CS8409_I2C_QREAD, i2c_reg_data);
+       if (cs8409_i2c_wait_complete(codec) < 0)
+               goto error;
+
+       /* Register in bits 15-8 and the data in 7-0 */
+       read_data = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD);
+
+       mutex_unlock(&spec->i2c_mux);
+
+       return read_data & 0x0ff;
+
+error:
+       mutex_unlock(&spec->i2c_mux);
+       codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr);
+       return -EIO;
+}
+
+/**
+ * cs8409_i2c_bulk_read - CS8409 I2C Read Sequence.
+ * @scodec: the codec instance
+ * @seq: Register Sequence to read
+ * @count: Number of registeres to read
+ *
+ * Returns negative on error, values are read into value element of cs8409_i2c_param sequence.
+ */
+static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_param *seq, int count)
+{
+       struct hda_codec *codec = scodec->codec;
+       struct cs8409_spec *spec = codec->spec;
+       unsigned int i2c_reg_data;
+       int i;
+
+       if (scodec->suspended)
+               return -EPERM;
+
+       mutex_lock(&spec->i2c_mux);
+       cs8409_set_i2c_dev_addr(codec, scodec->addr);
+
+       for (i = 0; i < count; i++) {
+               cs8409_enable_i2c_clock(codec);
+               if (cs8409_i2c_set_page(scodec, seq[i].addr))
+                       goto error;
+
+               i2c_reg_data = (seq[i].addr << 8) & 0x0ffff;
+               cs8409_vendor_coef_set(codec, CS8409_I2C_QREAD, i2c_reg_data);
+
+               if (cs8409_i2c_wait_complete(codec) < 0)
+                       goto error;
+
+               seq[i].value = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD) & 0xff;
+       }
+
+       mutex_unlock(&spec->i2c_mux);
+
+       return 0;
+
+error:
+       mutex_unlock(&spec->i2c_mux);
+       codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
+       return -EIO;
+}
+
+/**
+ * cs8409_i2c_write - CS8409 I2C Write.
+ * @scodec: the codec instance
+ * @addr: Register to write to
+ * @value: Data to write
+ *
+ * Returns negative on error, otherwise returns 0.
+ */
+static int cs8409_i2c_write(struct sub_codec *scodec, unsigned int addr, unsigned int value)
+{
+       struct hda_codec *codec = scodec->codec;
+       struct cs8409_spec *spec = codec->spec;
+       unsigned int i2c_reg_data;
+
+       if (scodec->suspended)
+               return -EPERM;
+
+       mutex_lock(&spec->i2c_mux);
+
+       cs8409_enable_i2c_clock(codec);
+       cs8409_set_i2c_dev_addr(codec, scodec->addr);
+
+       if (cs8409_i2c_set_page(scodec, addr))
+               goto error;
+
+       i2c_reg_data = ((addr << 8) & 0x0ff00) | (value & 0x0ff);
+       cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg_data);
+
+       if (cs8409_i2c_wait_complete(codec) < 0)
+               goto error;
+
+       mutex_unlock(&spec->i2c_mux);
+       return 0;
+
+error:
+       mutex_unlock(&spec->i2c_mux);
+       codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr);
+       return -EIO;
+}
+
+/**
+ * cs8409_i2c_bulk_write - CS8409 I2C Write Sequence.
+ * @scodec: the codec instance
+ * @seq: Register Sequence to write
+ * @count: Number of registeres to write
+ *
+ * Returns negative on error.
+ */
+static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i2c_param *seq,
+                                int count)
+{
+       struct hda_codec *codec = scodec->codec;
+       struct cs8409_spec *spec = codec->spec;
+       unsigned int i2c_reg_data;
+       int i;
+
+       if (scodec->suspended)
+               return -EPERM;
+
+       mutex_lock(&spec->i2c_mux);
+       cs8409_set_i2c_dev_addr(codec, scodec->addr);
+
+       for (i = 0; i < count; i++) {
+               cs8409_enable_i2c_clock(codec);
+               if (cs8409_i2c_set_page(scodec, seq[i].addr))
+                       goto error;
+
+               i2c_reg_data = ((seq[i].addr << 8) & 0x0ff00) | (seq[i].value & 0x0ff);
+               cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg_data);
+
+               if (cs8409_i2c_wait_complete(codec) < 0)
+                       goto error;
+               /* Certain use cases may require a delay
+                * after a write operation before proceeding.
+                */
+               if (seq[i].delay)
+                       fsleep(seq[i].delay);
+       }
+
+       mutex_unlock(&spec->i2c_mux);
+
+       return 0;
+
+error:
+       mutex_unlock(&spec->i2c_mux);
+       codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
+       return -EIO;
+}
+
+static int cs8409_init(struct hda_codec *codec)
+{
+       int ret = snd_hda_gen_init(codec);
+
+       if (!ret)
+               snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+       return ret;
+}
+
+static int cs8409_build_controls(struct hda_codec *codec)
+{
+       int err;
+
+       err = snd_hda_gen_build_controls(codec);
+       if (err < 0)
+               return err;
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+
+       return 0;
+}
+
+/* Enable/Disable Unsolicited Response */
+static void cs8409_enable_ur(struct hda_codec *codec, int flag)
+{
+       struct cs8409_spec *spec = codec->spec;
+       unsigned int ur_gpios = 0;
+       int i;
+
+       for (i = 0; i < spec->num_scodecs; i++)
+               ur_gpios |= spec->scodecs[i]->irq_mask;
+
+       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK,
+                           flag ? ur_gpios : 0);
+
+       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_UNSOLICITED_ENABLE,
+                           flag ? AC_UNSOL_ENABLED : 0);
+}
+
+static void cs8409_fix_caps(struct hda_codec *codec, unsigned int nid)
+{
+       int caps;
+
+       /* CS8409 is simple HDA bridge and intended to be used with a remote
+        * companion codec. Most of input/output PIN(s) have only basic
+        * capabilities. Receive and Transmit NID(s) have only OUTC and INC
+        * capabilities and no presence detect capable (PDC) and call to
+        * snd_hda_gen_build_controls() will mark them as non detectable
+        * phantom jacks. However, a companion codec may be
+        * connected to these pins which supports jack detect
+        * capabilities. We have to override pin capabilities,
+        * otherwise they will not be created as input devices.
+        */
+       caps = snd_hdac_read_parm(&codec->core, nid, AC_PAR_PIN_CAP);
+       if (caps >= 0)
+               snd_hdac_override_parm(&codec->core, nid, AC_PAR_PIN_CAP,
+                                      (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT)));
+
+       snd_hda_override_wcaps(codec, nid, (get_wcaps(codec, nid) | AC_WCAP_UNSOL_CAP));
+}
+
+static int cs8409_spk_sw_gpio_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct cs8409_spec *spec = codec->spec;
+
+       ucontrol->value.integer.value[0] = !!(spec->gpio_data & spec->speaker_pdn_gpio);
+       return 0;
+}
+
+static int cs8409_spk_sw_gpio_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct cs8409_spec *spec = codec->spec;
+       unsigned int gpio_data;
+
+       gpio_data = (spec->gpio_data & ~spec->speaker_pdn_gpio) |
+               (ucontrol->value.integer.value[0] ? spec->speaker_pdn_gpio : 0);
+       if (gpio_data == spec->gpio_data)
+               return 0;
+       spec->gpio_data = gpio_data;
+       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
+       return 1;
+}
+
+static const struct snd_kcontrol_new cs8409_spk_sw_ctrl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = snd_ctl_boolean_mono_info,
+       .get = cs8409_spk_sw_gpio_get,
+       .put = cs8409_spk_sw_gpio_put,
+};
+
+/******************************************************************************
+ *                        CS42L42 Specific Functions
+ ******************************************************************************/
+
+int cs42l42_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo)
+{
+       unsigned int ofs = get_amp_offset(kctrl);
+       u8 chs = get_amp_channels(kctrl);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->value.integer.step = 1;
+       uinfo->count = chs == 3 ? 2 : 1;
+
+       switch (ofs) {
+       case CS42L42_VOL_DAC:
+               uinfo->value.integer.min = CS42L42_HP_VOL_REAL_MIN;
+               uinfo->value.integer.max = CS42L42_HP_VOL_REAL_MAX;
+               break;
+       case CS42L42_VOL_ADC:
+               uinfo->value.integer.min = CS42L42_AMIC_VOL_REAL_MIN;
+               uinfo->value.integer.max = CS42L42_AMIC_VOL_REAL_MAX;
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kctrl);
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42 = spec->scodecs[get_amp_index(kctrl)];
+       int chs = get_amp_channels(kctrl);
+       unsigned int ofs = get_amp_offset(kctrl);
+       long *valp = uctrl->value.integer.value;
+
+       switch (ofs) {
+       case CS42L42_VOL_DAC:
+               if (chs & BIT(0))
+                       *valp++ = cs42l42->vol[ofs];
+               if (chs & BIT(1))
+                       *valp = cs42l42->vol[ofs+1];
+               break;
+       case CS42L42_VOL_ADC:
+               if (chs & BIT(0))
+                       *valp = cs42l42->vol[ofs];
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void cs42l42_mute(struct sub_codec *cs42l42, int vol_type,
+       unsigned int chs, bool mute)
+{
+       if (mute) {
+               if (vol_type == CS42L42_VOL_DAC) {
+                       if (chs & BIT(0))
+                               cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHA_VOL, 0x3f);
+                       if (chs & BIT(1))
+                               cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHB_VOL, 0x3f);
+               } else if (vol_type == CS42L42_VOL_ADC) {
+                       if (chs & BIT(0))
+                               cs8409_i2c_write(cs42l42, CS42L42_ADC_VOLUME, 0x9f);
+               }
+       } else {
+               if (vol_type == CS42L42_VOL_DAC) {
+                       if (chs & BIT(0))
+                               cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHA_VOL,
+                                       -(cs42l42->vol[CS42L42_DAC_CH0_VOL_OFFSET])
+                                       & CS42L42_MIXER_CH_VOL_MASK);
+                       if (chs & BIT(1))
+                               cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHB_VOL,
+                                       -(cs42l42->vol[CS42L42_DAC_CH1_VOL_OFFSET])
+                                       & CS42L42_MIXER_CH_VOL_MASK);
+               } else if (vol_type == CS42L42_VOL_ADC) {
+                       if (chs & BIT(0))
+                               cs8409_i2c_write(cs42l42, CS42L42_ADC_VOLUME,
+                                       cs42l42->vol[CS42L42_ADC_VOL_OFFSET]
+                                       & CS42L42_REG_AMIC_VOL_MASK);
+               }
+       }
+}
+
+int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kctrl);
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42 = spec->scodecs[get_amp_index(kctrl)];
+       int chs = get_amp_channels(kctrl);
+       unsigned int ofs = get_amp_offset(kctrl);
+       long *valp = uctrl->value.integer.value;
+
+       switch (ofs) {
+       case CS42L42_VOL_DAC:
+               if (chs & BIT(0))
+                       cs42l42->vol[ofs] = *valp;
+               if (chs & BIT(1)) {
+                       valp++;
+                       cs42l42->vol[ofs + 1] = *valp;
+               }
+               if (spec->playback_started)
+                       cs42l42_mute(cs42l42, CS42L42_VOL_DAC, chs, false);
+               break;
+       case CS42L42_VOL_ADC:
+               if (chs & BIT(0))
+                       cs42l42->vol[ofs] = *valp;
+               if (spec->capture_started)
+                       cs42l42_mute(cs42l42, CS42L42_VOL_ADC, chs, false);
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void cs42l42_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream,
+                                  int action)
+{
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42;
+       int i;
+       bool mute;
+
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               mute = false;
+               spec->playback_started = 1;
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               mute = true;
+               spec->playback_started = 0;
+               break;
+       default:
+               return;
+       }
+
+       for (i = 0; i < spec->num_scodecs; i++) {
+               cs42l42 = spec->scodecs[i];
+               cs42l42_mute(cs42l42, CS42L42_VOL_DAC, 0x3, mute);
+       }
+}
+
+static void cs42l42_capture_pcm_hook(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream,
+                                  int action)
+{
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42;
+       int i;
+       bool mute;
+
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               mute = false;
+               spec->capture_started = 1;
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               mute = true;
+               spec->capture_started = 0;
+               break;
+       default:
+               return;
+       }
+
+       for (i = 0; i < spec->num_scodecs; i++) {
+               cs42l42 = spec->scodecs[i];
+               cs42l42_mute(cs42l42, CS42L42_VOL_ADC, 0x3, mute);
+       }
+}
+
+/* Configure CS42L42 slave codec for jack autodetect */
+static void cs42l42_enable_jack_detect(struct sub_codec *cs42l42)
+{
+       cs8409_i2c_write(cs42l42, CS42L42_HSBIAS_SC_AUTOCTL, cs42l42->hsbias_hiz);
+       /* Clear WAKE# */
+       cs8409_i2c_write(cs42l42, CS42L42_WAKE_CTL, 0x00C1);
+       /* Wait ~2.5ms */
+       usleep_range(2500, 3000);
+       /* Set mode WAKE# output follows the combination logic directly */
+       cs8409_i2c_write(cs42l42, CS42L42_WAKE_CTL, 0x00C0);
+       /* Clear interrupts status */
+       cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS);
+       /* Enable interrupt */
+       cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xF3);
+}
+
+/* Enable and run CS42L42 slave codec jack auto detect */
+static void cs42l42_run_jack_detect(struct sub_codec *cs42l42)
+{
+       /* Clear interrupts */
+       cs8409_i2c_read(cs42l42, CS42L42_CODEC_STATUS);
+       cs8409_i2c_read(cs42l42, CS42L42_DET_STATUS1);
+       cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xFF);
+       cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS);
+
+       cs8409_i2c_write(cs42l42, CS42L42_PWR_CTL2, 0x87);
+       cs8409_i2c_write(cs42l42, CS42L42_DAC_CTL2, 0x86);
+       cs8409_i2c_write(cs42l42, CS42L42_MISC_DET_CTL, 0x07);
+       cs8409_i2c_write(cs42l42, CS42L42_CODEC_INT_MASK, 0xFD);
+       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0x80);
+       /* Wait ~20ms*/
+       usleep_range(20000, 25000);
+       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1, 0x77);
+       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0xc0);
+}
+
+static int cs42l42_manual_hs_det(struct sub_codec *cs42l42)
+{
+       unsigned int hs_det_status;
+       unsigned int hs_det_comp1;
+       unsigned int hs_det_comp2;
+       unsigned int hs_det_sw;
+       unsigned int hs_type;
+
+       /* Set hs detect to manual, active mode */
+       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2,
+                        (1 << CS42L42_HSDET_CTRL_SHIFT) |
+                        (0 << CS42L42_HSDET_SET_SHIFT) |
+                        (0 << CS42L42_HSBIAS_REF_SHIFT) |
+                        (0 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+       /* Configure HS DET comparator reference levels. */
+       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1,
+                        (CS42L42_HSDET_COMP1_LVL_VAL << CS42L42_HSDET_COMP1_LVL_SHIFT) |
+                        (CS42L42_HSDET_COMP2_LVL_VAL << CS42L42_HSDET_COMP2_LVL_SHIFT));
+
+       /* Open the SW_HSB_HS3 switch and close SW_HSB_HS4 for a Type 1 headset. */
+       cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP1);
+
+       msleep(100);
+
+       hs_det_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS);
+
+       hs_det_comp1 = (hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >>
+                       CS42L42_HSDET_COMP1_OUT_SHIFT;
+       hs_det_comp2 = (hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >>
+                       CS42L42_HSDET_COMP2_OUT_SHIFT;
+
+       /* Close the SW_HSB_HS3 switch for a Type 2 headset. */
+       cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP2);
+
+       msleep(100);
+
+       hs_det_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS);
+
+       hs_det_comp1 |= ((hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >>
+                       CS42L42_HSDET_COMP1_OUT_SHIFT) << 1;
+       hs_det_comp2 |= ((hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >>
+                       CS42L42_HSDET_COMP2_OUT_SHIFT) << 1;
+
+       /* Use Comparator 1 with 1.25V Threshold. */
+       switch (hs_det_comp1) {
+       case CS42L42_HSDET_COMP_TYPE1:
+               hs_type = CS42L42_PLUG_CTIA;
+               hs_det_sw = CS42L42_HSDET_SW_TYPE1;
+               break;
+       case CS42L42_HSDET_COMP_TYPE2:
+               hs_type = CS42L42_PLUG_OMTP;
+               hs_det_sw = CS42L42_HSDET_SW_TYPE2;
+               break;
+       default:
+               /* Fallback to Comparator 2 with 1.75V Threshold. */
+               switch (hs_det_comp2) {
+               case CS42L42_HSDET_COMP_TYPE1:
+                       hs_type = CS42L42_PLUG_CTIA;
+                       hs_det_sw = CS42L42_HSDET_SW_TYPE1;
+                       break;
+               case CS42L42_HSDET_COMP_TYPE2:
+                       hs_type = CS42L42_PLUG_OMTP;
+                       hs_det_sw = CS42L42_HSDET_SW_TYPE2;
+                       break;
+               case CS42L42_HSDET_COMP_TYPE3:
+                       hs_type = CS42L42_PLUG_HEADPHONE;
+                       hs_det_sw = CS42L42_HSDET_SW_TYPE3;
+                       break;
+               default:
+                       hs_type = CS42L42_PLUG_INVALID;
+                       hs_det_sw = CS42L42_HSDET_SW_TYPE4;
+                       break;
+               }
+       }
+
+       /* Set Switches */
+       cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, hs_det_sw);
+
+       /* Set HSDET mode to Manual—Disabled */
+       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2,
+                        (0 << CS42L42_HSDET_CTRL_SHIFT) |
+                        (0 << CS42L42_HSDET_SET_SHIFT) |
+                        (0 << CS42L42_HSBIAS_REF_SHIFT) |
+                        (0 << CS42L42_HSDET_AUTO_TIME_SHIFT));
+
+       /* Configure HS DET comparator reference levels. */
+       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1,
+                        (CS42L42_HSDET_COMP1_LVL_DEFAULT << CS42L42_HSDET_COMP1_LVL_SHIFT) |
+                        (CS42L42_HSDET_COMP2_LVL_DEFAULT << CS42L42_HSDET_COMP2_LVL_SHIFT));
+
+       return hs_type;
+}
+
+static int cs42l42_handle_tip_sense(struct sub_codec *cs42l42, unsigned int reg_ts_status)
+{
+       int status_changed = 0;
+
+       /* TIP_SENSE INSERT/REMOVE */
+       switch (reg_ts_status) {
+       case CS42L42_TS_PLUG:
+               if (cs42l42->no_type_dect) {
+                       status_changed = 1;
+                       cs42l42->hp_jack_in = 1;
+                       cs42l42->mic_jack_in = 0;
+               } else {
+                       cs42l42_run_jack_detect(cs42l42);
+               }
+               break;
+
+       case CS42L42_TS_UNPLUG:
+               status_changed = 1;
+               cs42l42->hp_jack_in = 0;
+               cs42l42->mic_jack_in = 0;
+               break;
+       default:
+               /* jack in transition */
+               break;
+       }
+
+       codec_dbg(cs42l42->codec, "Tip Sense Detection: (%d)\n", reg_ts_status);
+
+       return status_changed;
+}
+
+static int cs42l42_jack_unsol_event(struct sub_codec *cs42l42)
+{
+       int current_plug_status;
+       int status_changed = 0;
+       int reg_cdc_status;
+       int reg_hs_status;
+       int reg_ts_status;
+       int type;
+
+       /* Read jack detect status registers */
+       reg_cdc_status = cs8409_i2c_read(cs42l42, CS42L42_CODEC_STATUS);
+       reg_hs_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS);
+       reg_ts_status = cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS);
+
+       /* If status values are < 0, read error has occurred. */
+       if (reg_cdc_status < 0 || reg_hs_status < 0 || reg_ts_status < 0)
+               return -EIO;
+
+       current_plug_status = (reg_ts_status & (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK))
+                               >> CS42L42_TS_PLUG_SHIFT;
+
+       /* HSDET_AUTO_DONE */
+       if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE_MASK) {
+
+               /* Disable HSDET_AUTO_DONE */
+               cs8409_i2c_write(cs42l42, CS42L42_CODEC_INT_MASK, 0xFF);
+
+               type = (reg_hs_status & CS42L42_HSDET_TYPE_MASK) >> CS42L42_HSDET_TYPE_SHIFT;
+
+               /* Configure the HSDET mode. */
+               cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0x80);
+
+               if (cs42l42->no_type_dect) {
+                       status_changed = cs42l42_handle_tip_sense(cs42l42, current_plug_status);
+               } else {
+                       if (type == CS42L42_PLUG_INVALID || type == CS42L42_PLUG_HEADPHONE) {
+                               codec_dbg(cs42l42->codec,
+                                         "Auto detect value not valid (%d), running manual det\n",
+                                         type);
+                               type = cs42l42_manual_hs_det(cs42l42);
+                       }
+
+                       switch (type) {
+                       case CS42L42_PLUG_CTIA:
+                       case CS42L42_PLUG_OMTP:
+                               status_changed = 1;
+                               cs42l42->hp_jack_in = 1;
+                               cs42l42->mic_jack_in = 1;
+                               break;
+                       case CS42L42_PLUG_HEADPHONE:
+                               status_changed = 1;
+                               cs42l42->hp_jack_in = 1;
+                               cs42l42->mic_jack_in = 0;
+                               break;
+                       default:
+                               status_changed = 1;
+                               cs42l42->hp_jack_in = 0;
+                               cs42l42->mic_jack_in = 0;
+                               break;
+                       }
+                       codec_dbg(cs42l42->codec, "Detection done (%d)\n", type);
+               }
+
+               /* Enable the HPOUT ground clamp and configure the HP pull-down */
+               cs8409_i2c_write(cs42l42, CS42L42_DAC_CTL2, 0x02);
+               /* Re-Enable Tip Sense Interrupt */
+               cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xF3);
+       } else {
+               status_changed = cs42l42_handle_tip_sense(cs42l42, current_plug_status);
+       }
+
+       return status_changed;
+}
+
+static void cs42l42_resume(struct sub_codec *cs42l42)
+{
+       struct hda_codec *codec = cs42l42->codec;
+       struct cs8409_spec *spec = codec->spec;
+       struct cs8409_i2c_param irq_regs[] = {
+               { CS42L42_CODEC_STATUS, 0x00 },
+               { CS42L42_DET_INT_STATUS1, 0x00 },
+               { CS42L42_DET_INT_STATUS2, 0x00 },
+               { CS42L42_TSRS_PLUG_STATUS, 0x00 },
+       };
+       unsigned int fsv;
+
+       /* Bring CS42L42 out of Reset */
+       spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
+       spec->gpio_data |= cs42l42->reset_gpio;
+       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
+       usleep_range(10000, 15000);
+
+       cs42l42->suspended = 0;
+
+       /* Initialize CS42L42 companion codec */
+       cs8409_i2c_bulk_write(cs42l42, cs42l42->init_seq, cs42l42->init_seq_num);
+
+       /* Clear interrupts, by reading interrupt status registers */
+       cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs));
+
+       fsv = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL);
+       if (cs42l42->full_scale_vol) {
+               // Set the full scale volume bit
+               fsv |= CS42L42_FULL_SCALE_VOL_MASK;
+               cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv);
+       }
+       // Unmute analog channels A and B
+       fsv = (fsv & ~CS42L42_ANA_MUTE_AB);
+       cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv);
+
+       /* we have to explicitly allow unsol event handling even during the
+        * resume phase so that the jack event is processed properly
+        */
+       snd_hda_codec_allow_unsol_events(cs42l42->codec);
+
+       cs42l42_enable_jack_detect(cs42l42);
+}
+
+static void cs42l42_suspend(struct sub_codec *cs42l42)
+{
+       struct hda_codec *codec = cs42l42->codec;
+       struct cs8409_spec *spec = codec->spec;
+       int reg_cdc_status = 0;
+       const struct cs8409_i2c_param cs42l42_pwr_down_seq[] = {
+               { CS42L42_DAC_CTL2, 0x02 },
+               { CS42L42_HS_CLAMP_DISABLE, 0x00 },
+               { CS42L42_MIXER_CHA_VOL, 0x3F },
+               { CS42L42_MIXER_ADC_VOL, 0x3F },
+               { CS42L42_MIXER_CHB_VOL, 0x3F },
+               { CS42L42_HP_CTL, 0x0D },
+               { CS42L42_ASP_RX_DAI0_EN, 0x00 },
+               { CS42L42_ASP_CLK_CFG, 0x00 },
+               { CS42L42_PWR_CTL1, 0xFE },
+               { CS42L42_PWR_CTL2, 0x8C },
+               { CS42L42_PWR_CTL1, 0xFF },
+       };
+
+       cs8409_i2c_bulk_write(cs42l42, cs42l42_pwr_down_seq, ARRAY_SIZE(cs42l42_pwr_down_seq));
+
+       if (read_poll_timeout(cs8409_i2c_read, reg_cdc_status,
+                       (reg_cdc_status & 0x1), CS42L42_PDN_SLEEP_US, CS42L42_PDN_TIMEOUT_US,
+                       true, cs42l42, CS42L42_CODEC_STATUS) < 0)
+               codec_warn(codec, "Timeout waiting for PDN_DONE for CS42L42\n");
+
+       /* Power down CS42L42 ASP/EQ/MIX/HP */
+       cs8409_i2c_write(cs42l42, CS42L42_PWR_CTL2, 0x9C);
+       cs42l42->suspended = 1;
+       cs42l42->last_page = 0;
+       cs42l42->hp_jack_in = 0;
+       cs42l42->mic_jack_in = 0;
+
+       /* Put CS42L42 into Reset */
+       spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
+       spec->gpio_data &= ~cs42l42->reset_gpio;
+       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
+}
+
+static void cs8409_free(struct hda_codec *codec)
+{
+       struct cs8409_spec *spec = codec->spec;
+
+       /* Cancel i2c clock disable timer, and disable clock if left enabled */
+       cancel_delayed_work_sync(&spec->i2c_clk_work);
+       cs8409_disable_i2c_clock(codec);
+
+       snd_hda_gen_free(codec);
+}
+
+/******************************************************************************
+ *                   BULLSEYE / WARLOCK / CYBORG Specific Functions
+ *                               CS8409/CS42L42
+ ******************************************************************************/
+
+/*
+ * In the case of CS8409 we do not have unsolicited events from NID's 0x24
+ * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
+ * generate interrupt via gpio 4 to notify jack events. We have to overwrite
+ * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
+ * and then notify status via generic snd_hda_jack_unsol_event() call.
+ */
+static void cs8409_cs42l42_jack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
+       struct hda_jack_tbl *jk;
+
+       /* jack_unsol_event() will be called every time gpio line changing state.
+        * In this case gpio4 line goes up as a result of reading interrupt status
+        * registers in previous cs8409_jack_unsol_event() call.
+        * We don't need to handle this event, ignoring...
+        */
+       if (res & cs42l42->irq_mask)
+               return;
+
+       if (cs42l42_jack_unsol_event(cs42l42)) {
+               snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
+                                   cs42l42->hp_jack_in ? 0 : PIN_OUT);
+               /* Report jack*/
+               jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
+               if (jk)
+                       snd_hda_jack_unsol_event(codec, (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
+                                                       AC_UNSOL_RES_TAG);
+               /* Report jack*/
+               jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
+               if (jk)
+                       snd_hda_jack_unsol_event(codec, (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
+                                                        AC_UNSOL_RES_TAG);
+       }
+}
+
+/* Manage PDREF, when transition to D3hot */
+static int cs8409_cs42l42_suspend(struct hda_codec *codec)
+{
+       struct cs8409_spec *spec = codec->spec;
+       int i;
+
+       spec->init_done = 0;
+
+       cs8409_enable_ur(codec, 0);
+
+       for (i = 0; i < spec->num_scodecs; i++)
+               cs42l42_suspend(spec->scodecs[i]);
+
+       /* Cancel i2c clock disable timer, and disable clock if left enabled */
+       cancel_delayed_work_sync(&spec->i2c_clk_work);
+       cs8409_disable_i2c_clock(codec);
+
+       snd_hda_shutup_pins(codec);
+
+       return 0;
+}
+
+/* Vendor specific HW configuration
+ * PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
+ */
+static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
+{
+       const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg;
+       const struct cs8409_cir_param *seq_bullseye = cs8409_cs42l42_bullseye_atn;
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
+
+       if (spec->gpio_mask) {
+               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_MASK,
+                       spec->gpio_mask);
+               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DIRECTION,
+                       spec->gpio_dir);
+               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA,
+                       spec->gpio_data);
+       }
+
+       for (; seq->nid; seq++)
+               cs8409_vendor_coef_set(codec, seq->cir, seq->coeff);
+
+       if (codec->fixup_id == CS8409_BULLSEYE) {
+               for (; seq_bullseye->nid; seq_bullseye++)
+                       cs8409_vendor_coef_set(codec, seq_bullseye->cir, seq_bullseye->coeff);
+       }
+
+       switch (codec->fixup_id) {
+       case CS8409_CYBORG:
+       case CS8409_WARLOCK_MLK_DUAL_MIC:
+               /* DMIC1_MO=00b, DMIC1/2_SR=1 */
+               cs8409_vendor_coef_set(codec, CS8409_DMIC_CFG, 0x0003);
+               break;
+       case CS8409_ODIN:
+               /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=0 */
+               cs8409_vendor_coef_set(codec, CS8409_PAD_CFG_SLW_RATE_CTRL, 0xfc00);
+               break;
+       default:
+               break;
+       }
+
+       cs42l42_resume(cs42l42);
+
+       /* Enable Unsolicited Response */
+       cs8409_enable_ur(codec, 1);
+}
+
+static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
+       .build_controls = cs8409_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = cs8409_init,
+       .free = cs8409_free,
+       .unsol_event = cs8409_cs42l42_jack_unsol_event,
+       .suspend = cs8409_cs42l42_suspend,
+};
+
+static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
+                                   unsigned int *res)
+{
+       struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
+
+       unsigned int nid = ((cmd >> 20) & 0x07f);
+       unsigned int verb = ((cmd >> 8) & 0x0fff);
+
+       /* CS8409 pins have no AC_PINSENSE_PRESENCE
+        * capabilities. We have to intercept 2 calls for pins 0x24 and 0x34
+        * and return correct pin sense values for read_pin_sense() call from
+        * hda_jack based on CS42L42 jack detect status.
+        */
+       switch (nid) {
+       case CS8409_CS42L42_HP_PIN_NID:
+               if (verb == AC_VERB_GET_PIN_SENSE) {
+                       *res = (cs42l42->hp_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+                       return 0;
+               }
+               break;
+       case CS8409_CS42L42_AMIC_PIN_NID:
+               if (verb == AC_VERB_GET_PIN_SENSE) {
+                       *res = (cs42l42->mic_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+                       return 0;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return spec->exec_verb(dev, cmd, flags, res);
+}
+
+void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action)
+{
+       struct cs8409_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_add_verbs(codec, cs8409_cs42l42_init_verbs);
+               /* verb exec op override */
+               spec->exec_verb = codec->core.exec_verb;
+               codec->core.exec_verb = cs8409_cs42l42_exec_verb;
+
+               spec->scodecs[CS8409_CODEC0] = &cs8409_cs42l42_codec;
+               spec->num_scodecs = 1;
+               spec->scodecs[CS8409_CODEC0]->codec = codec;
+               codec->patch_ops = cs8409_cs42l42_patch_ops;
+
+               spec->gen.suppress_auto_mute = 1;
+               spec->gen.no_primary_hp = 1;
+               spec->gen.suppress_vmaster = 1;
+
+               spec->speaker_pdn_gpio = 0;
+
+               /* GPIO 5 out, 3,4 in */
+               spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio;
+               spec->gpio_data = 0;
+               spec->gpio_mask = 0x03f;
+
+               /* Basic initial sequence for specific hw configuration */
+               snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
+
+               cs8409_fix_caps(codec, CS8409_CS42L42_HP_PIN_NID);
+               cs8409_fix_caps(codec, CS8409_CS42L42_AMIC_PIN_NID);
+
+               spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020;
+
+               switch (codec->fixup_id) {
+               case CS8409_CYBORG:
+                       spec->scodecs[CS8409_CODEC0]->full_scale_vol =
+                               CS42L42_FULL_SCALE_VOL_MINUS6DB;
+                       spec->speaker_pdn_gpio = CS8409_CYBORG_SPEAKER_PDN;
+                       break;
+               case CS8409_ODIN:
+                       spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_0DB;
+                       spec->speaker_pdn_gpio = CS8409_CYBORG_SPEAKER_PDN;
+                       break;
+               case CS8409_WARLOCK_MLK:
+               case CS8409_WARLOCK_MLK_DUAL_MIC:
+                       spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_0DB;
+                       spec->speaker_pdn_gpio = CS8409_WARLOCK_SPEAKER_PDN;
+                       break;
+               default:
+                       spec->scodecs[CS8409_CODEC0]->full_scale_vol =
+                               CS42L42_FULL_SCALE_VOL_MINUS6DB;
+                       spec->speaker_pdn_gpio = CS8409_WARLOCK_SPEAKER_PDN;
+                       break;
+               }
+
+               if (spec->speaker_pdn_gpio > 0) {
+                       spec->gpio_dir |= spec->speaker_pdn_gpio;
+                       spec->gpio_data |= spec->speaker_pdn_gpio;
+               }
+
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               /* Fix Sample Rate to 48kHz */
+               spec->gen.stream_analog_playback = &cs42l42_48k_pcm_analog_playback;
+               spec->gen.stream_analog_capture = &cs42l42_48k_pcm_analog_capture;
+               /* add hooks */
+               spec->gen.pcm_playback_hook = cs42l42_playback_pcm_hook;
+               spec->gen.pcm_capture_hook = cs42l42_capture_pcm_hook;
+               if (codec->fixup_id != CS8409_ODIN)
+                       /* Set initial DMIC volume to -26 dB */
+                       snd_hda_codec_amp_init_stereo(codec, CS8409_CS42L42_DMIC_ADC_PIN_NID,
+                                                     HDA_INPUT, 0, 0xff, 0x19);
+               snd_hda_gen_add_kctl(&spec->gen, "Headphone Playback Volume",
+                               &cs42l42_dac_volume_mixer);
+               snd_hda_gen_add_kctl(&spec->gen, "Mic Capture Volume",
+                               &cs42l42_adc_volume_mixer);
+               if (spec->speaker_pdn_gpio > 0)
+                       snd_hda_gen_add_kctl(&spec->gen, "Speaker Playback Switch",
+                                            &cs8409_spk_sw_ctrl);
+               /* Disable Unsolicited Response during boot */
+               cs8409_enable_ur(codec, 0);
+               snd_hda_codec_set_name(codec, "CS8409/CS42L42");
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               cs8409_cs42l42_hw_init(codec);
+               spec->init_done = 1;
+               if (spec->init_done && spec->build_ctrl_done
+                       && !spec->scodecs[CS8409_CODEC0]->hp_jack_in)
+                       cs42l42_run_jack_detect(spec->scodecs[CS8409_CODEC0]);
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               spec->build_ctrl_done = 1;
+               /* Run jack auto detect first time on boot
+                * after controls have been added, to check if jack has
+                * been already plugged in.
+                * Run immediately after init.
+                */
+               if (spec->init_done && spec->build_ctrl_done
+                       && !spec->scodecs[CS8409_CODEC0]->hp_jack_in)
+                       cs42l42_run_jack_detect(spec->scodecs[CS8409_CODEC0]);
+               break;
+       default:
+               break;
+       }
+}
+
+/******************************************************************************
+ *                          Dolphin Specific Functions
+ *                               CS8409/ 2 X CS42L42
+ ******************************************************************************/
+
+/*
+ * In the case of CS8409 we do not have unsolicited events when
+ * hs mic and hp are connected. Companion codec CS42L42 will
+ * generate interrupt via irq_mask to notify jack events. We have to overwrite
+ * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
+ * and then notify status via generic snd_hda_jack_unsol_event() call.
+ */
+static void dolphin_jack_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42;
+       struct hda_jack_tbl *jk;
+
+       cs42l42 = spec->scodecs[CS8409_CODEC0];
+       if (!cs42l42->suspended && (~res & cs42l42->irq_mask) &&
+           cs42l42_jack_unsol_event(cs42l42)) {
+               jk = snd_hda_jack_tbl_get_mst(codec, DOLPHIN_HP_PIN_NID, 0);
+               if (jk)
+                       snd_hda_jack_unsol_event(codec,
+                                                (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
+                                                 AC_UNSOL_RES_TAG);
+
+               jk = snd_hda_jack_tbl_get_mst(codec, DOLPHIN_AMIC_PIN_NID, 0);
+               if (jk)
+                       snd_hda_jack_unsol_event(codec,
+                                                (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
+                                                 AC_UNSOL_RES_TAG);
+       }
+
+       cs42l42 = spec->scodecs[CS8409_CODEC1];
+       if (!cs42l42->suspended && (~res & cs42l42->irq_mask) &&
+           cs42l42_jack_unsol_event(cs42l42)) {
+               jk = snd_hda_jack_tbl_get_mst(codec, DOLPHIN_LO_PIN_NID, 0);
+               if (jk)
+                       snd_hda_jack_unsol_event(codec,
+                                                (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
+                                                 AC_UNSOL_RES_TAG);
+       }
+}
+
+/* Vendor specific HW configuration
+ * PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
+ */
+static void dolphin_hw_init(struct hda_codec *codec)
+{
+       const struct cs8409_cir_param *seq = dolphin_hw_cfg;
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42;
+       int i;
+
+       if (spec->gpio_mask) {
+               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_MASK,
+                                   spec->gpio_mask);
+               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DIRECTION,
+                                   spec->gpio_dir);
+               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_data);
+       }
+
+       for (; seq->nid; seq++)
+               cs8409_vendor_coef_set(codec, seq->cir, seq->coeff);
+
+       for (i = 0; i < spec->num_scodecs; i++) {
+               cs42l42 = spec->scodecs[i];
+               cs42l42_resume(cs42l42);
+       }
+
+       /* Enable Unsolicited Response */
+       cs8409_enable_ur(codec, 1);
+}
+
+static const struct hda_codec_ops cs8409_dolphin_patch_ops = {
+       .build_controls = cs8409_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = cs8409_init,
+       .free = cs8409_free,
+       .unsol_event = dolphin_jack_unsol_event,
+       .suspend = cs8409_cs42l42_suspend,
+};
+
+static int dolphin_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
+                            unsigned int *res)
+{
+       struct hda_codec *codec = container_of(dev, struct hda_codec, core);
+       struct cs8409_spec *spec = codec->spec;
+       struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
+
+       unsigned int nid = ((cmd >> 20) & 0x07f);
+       unsigned int verb = ((cmd >> 8) & 0x0fff);
+
+       /* CS8409 pins have no AC_PINSENSE_PRESENCE
+        * capabilities. We have to intercept calls for CS42L42 pins
+        * and return correct pin sense values for read_pin_sense() call from
+        * hda_jack based on CS42L42 jack detect status.
+        */
+       switch (nid) {
+       case DOLPHIN_HP_PIN_NID:
+       case DOLPHIN_LO_PIN_NID:
+               if (nid == DOLPHIN_LO_PIN_NID)
+                       cs42l42 = spec->scodecs[CS8409_CODEC1];
+               if (verb == AC_VERB_GET_PIN_SENSE) {
+                       *res = (cs42l42->hp_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+                       return 0;
+               }
+               break;
+       case DOLPHIN_AMIC_PIN_NID:
+               if (verb == AC_VERB_GET_PIN_SENSE) {
+                       *res = (cs42l42->mic_jack_in) ? AC_PINSENSE_PRESENCE : 0;
+                       return 0;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return spec->exec_verb(dev, cmd, flags, res);
+}
+
+void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action)
+{
+       struct cs8409_spec *spec = codec->spec;
+       struct snd_kcontrol_new *kctrl;
+       int i;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_add_verbs(codec, dolphin_init_verbs);
+               /* verb exec op override */
+               spec->exec_verb = codec->core.exec_verb;
+               codec->core.exec_verb = dolphin_exec_verb;
+
+               spec->scodecs[CS8409_CODEC0] = &dolphin_cs42l42_0;
+               spec->scodecs[CS8409_CODEC0]->codec = codec;
+               spec->scodecs[CS8409_CODEC1] = &dolphin_cs42l42_1;
+               spec->scodecs[CS8409_CODEC1]->codec = codec;
+               spec->num_scodecs = 2;
+               spec->gen.suppress_vmaster = 1;
+
+               codec->patch_ops = cs8409_dolphin_patch_ops;
+
+               /* GPIO 1,5 out, 0,4 in */
+               spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio |
+                                spec->scodecs[CS8409_CODEC1]->reset_gpio;
+               spec->gpio_data = 0;
+               spec->gpio_mask = 0x03f;
+
+               /* Basic initial sequence for specific hw configuration */
+               snd_hda_sequence_write(codec, dolphin_init_verbs);
+
+               snd_hda_jack_add_kctl(codec, DOLPHIN_LO_PIN_NID, "Line Out", true,
+                                     SND_JACK_HEADPHONE, NULL);
+
+               snd_hda_jack_add_kctl(codec, DOLPHIN_AMIC_PIN_NID, "Microphone", true,
+                                     SND_JACK_MICROPHONE, NULL);
+
+               cs8409_fix_caps(codec, DOLPHIN_HP_PIN_NID);
+               cs8409_fix_caps(codec, DOLPHIN_LO_PIN_NID);
+               cs8409_fix_caps(codec, DOLPHIN_AMIC_PIN_NID);
+
+               spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_MINUS6DB;
+               spec->scodecs[CS8409_CODEC1]->full_scale_vol = CS42L42_FULL_SCALE_VOL_MINUS6DB;
+
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               /* Fix Sample Rate to 48kHz */
+               spec->gen.stream_analog_playback = &cs42l42_48k_pcm_analog_playback;
+               spec->gen.stream_analog_capture = &cs42l42_48k_pcm_analog_capture;
+               /* add hooks */
+               spec->gen.pcm_playback_hook = cs42l42_playback_pcm_hook;
+               spec->gen.pcm_capture_hook = cs42l42_capture_pcm_hook;
+               snd_hda_gen_add_kctl(&spec->gen, "Headphone Playback Volume",
+                                    &cs42l42_dac_volume_mixer);
+               snd_hda_gen_add_kctl(&spec->gen, "Mic Capture Volume", &cs42l42_adc_volume_mixer);
+               kctrl = snd_hda_gen_add_kctl(&spec->gen, "Line Out Playback Volume",
+                                            &cs42l42_dac_volume_mixer);
+               /* Update Line Out kcontrol template */
+               if (kctrl)
+                       kctrl->private_value = HDA_COMPOSE_AMP_VAL_OFS(DOLPHIN_HP_PIN_NID, 3, CS8409_CODEC1,
+                                              HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE;
+               cs8409_enable_ur(codec, 0);
+               snd_hda_codec_set_name(codec, "CS8409/CS42L42");
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               dolphin_hw_init(codec);
+               spec->init_done = 1;
+               if (spec->init_done && spec->build_ctrl_done) {
+                       for (i = 0; i < spec->num_scodecs; i++) {
+                               if (!spec->scodecs[i]->hp_jack_in)
+                                       cs42l42_run_jack_detect(spec->scodecs[i]);
+                       }
+               }
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               spec->build_ctrl_done = 1;
+               /* Run jack auto detect first time on boot
+                * after controls have been added, to check if jack has
+                * been already plugged in.
+                * Run immediately after init.
+                */
+               if (spec->init_done && spec->build_ctrl_done) {
+                       for (i = 0; i < spec->num_scodecs; i++) {
+                               if (!spec->scodecs[i]->hp_jack_in)
+                                       cs42l42_run_jack_detect(spec->scodecs[i]);
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static int patch_cs8409(struct hda_codec *codec)
+{
+       int err;
+
+       if (!cs8409_alloc_spec(codec))
+               return -ENOMEM;
+
+       snd_hda_pick_fixup(codec, cs8409_models, cs8409_fixup_tbl, cs8409_fixups);
+
+       codec_dbg(codec, "Picked ID=%d, VID=%08x, DEV=%08x\n", codec->fixup_id,
+                        codec->bus->pci->subsystem_vendor,
+                        codec->bus->pci->subsystem_device);
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = cs8409_parse_auto_config(codec);
+       if (err < 0) {
+               cs8409_free(codec);
+               return err;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+       return 0;
+}
+
+static const struct hda_device_id snd_hda_id_cs8409[] = {
+       HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs8409);
+
+static struct hda_codec_driver cs8409_driver = {
+       .id = snd_hda_id_cs8409,
+};
+module_hda_codec_driver(cs8409_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Cirrus Logic HDA bridge");
diff --git a/sound/hda/codecs/cirrus/cs8409.h b/sound/hda/codecs/cirrus/cs8409.h
new file mode 100644 (file)
index 0000000..35072cd
--- /dev/null
@@ -0,0 +1,375 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
+ *
+ * Copyright (C) 2021 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __CS8409_PATCH_H
+#define __CS8409_PATCH_H
+
+#include <linux/pci.h>
+#include <sound/tlv.h>
+#include <linux/workqueue.h>
+#include <sound/cs42l42.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "../generic.h"
+
+/* CS8409 Specific Definitions */
+
+enum cs8409_pins {
+       CS8409_PIN_ROOT,
+       CS8409_PIN_AFG,
+       CS8409_PIN_ASP1_OUT_A,
+       CS8409_PIN_ASP1_OUT_B,
+       CS8409_PIN_ASP1_OUT_C,
+       CS8409_PIN_ASP1_OUT_D,
+       CS8409_PIN_ASP1_OUT_E,
+       CS8409_PIN_ASP1_OUT_F,
+       CS8409_PIN_ASP1_OUT_G,
+       CS8409_PIN_ASP1_OUT_H,
+       CS8409_PIN_ASP2_OUT_A,
+       CS8409_PIN_ASP2_OUT_B,
+       CS8409_PIN_ASP2_OUT_C,
+       CS8409_PIN_ASP2_OUT_D,
+       CS8409_PIN_ASP2_OUT_E,
+       CS8409_PIN_ASP2_OUT_F,
+       CS8409_PIN_ASP2_OUT_G,
+       CS8409_PIN_ASP2_OUT_H,
+       CS8409_PIN_ASP1_IN_A,
+       CS8409_PIN_ASP1_IN_B,
+       CS8409_PIN_ASP1_IN_C,
+       CS8409_PIN_ASP1_IN_D,
+       CS8409_PIN_ASP1_IN_E,
+       CS8409_PIN_ASP1_IN_F,
+       CS8409_PIN_ASP1_IN_G,
+       CS8409_PIN_ASP1_IN_H,
+       CS8409_PIN_ASP2_IN_A,
+       CS8409_PIN_ASP2_IN_B,
+       CS8409_PIN_ASP2_IN_C,
+       CS8409_PIN_ASP2_IN_D,
+       CS8409_PIN_ASP2_IN_E,
+       CS8409_PIN_ASP2_IN_F,
+       CS8409_PIN_ASP2_IN_G,
+       CS8409_PIN_ASP2_IN_H,
+       CS8409_PIN_DMIC1,
+       CS8409_PIN_DMIC2,
+       CS8409_PIN_ASP1_TRANSMITTER_A,
+       CS8409_PIN_ASP1_TRANSMITTER_B,
+       CS8409_PIN_ASP1_TRANSMITTER_C,
+       CS8409_PIN_ASP1_TRANSMITTER_D,
+       CS8409_PIN_ASP1_TRANSMITTER_E,
+       CS8409_PIN_ASP1_TRANSMITTER_F,
+       CS8409_PIN_ASP1_TRANSMITTER_G,
+       CS8409_PIN_ASP1_TRANSMITTER_H,
+       CS8409_PIN_ASP2_TRANSMITTER_A,
+       CS8409_PIN_ASP2_TRANSMITTER_B,
+       CS8409_PIN_ASP2_TRANSMITTER_C,
+       CS8409_PIN_ASP2_TRANSMITTER_D,
+       CS8409_PIN_ASP2_TRANSMITTER_E,
+       CS8409_PIN_ASP2_TRANSMITTER_F,
+       CS8409_PIN_ASP2_TRANSMITTER_G,
+       CS8409_PIN_ASP2_TRANSMITTER_H,
+       CS8409_PIN_ASP1_RECEIVER_A,
+       CS8409_PIN_ASP1_RECEIVER_B,
+       CS8409_PIN_ASP1_RECEIVER_C,
+       CS8409_PIN_ASP1_RECEIVER_D,
+       CS8409_PIN_ASP1_RECEIVER_E,
+       CS8409_PIN_ASP1_RECEIVER_F,
+       CS8409_PIN_ASP1_RECEIVER_G,
+       CS8409_PIN_ASP1_RECEIVER_H,
+       CS8409_PIN_ASP2_RECEIVER_A,
+       CS8409_PIN_ASP2_RECEIVER_B,
+       CS8409_PIN_ASP2_RECEIVER_C,
+       CS8409_PIN_ASP2_RECEIVER_D,
+       CS8409_PIN_ASP2_RECEIVER_E,
+       CS8409_PIN_ASP2_RECEIVER_F,
+       CS8409_PIN_ASP2_RECEIVER_G,
+       CS8409_PIN_ASP2_RECEIVER_H,
+       CS8409_PIN_DMIC1_IN,
+       CS8409_PIN_DMIC2_IN,
+       CS8409_PIN_BEEP_GEN,
+       CS8409_PIN_VENDOR_WIDGET
+};
+
+enum cs8409_coefficient_index_registers {
+       CS8409_DEV_CFG1,
+       CS8409_DEV_CFG2,
+       CS8409_DEV_CFG3,
+       CS8409_ASP1_CLK_CTRL1,
+       CS8409_ASP1_CLK_CTRL2,
+       CS8409_ASP1_CLK_CTRL3,
+       CS8409_ASP2_CLK_CTRL1,
+       CS8409_ASP2_CLK_CTRL2,
+       CS8409_ASP2_CLK_CTRL3,
+       CS8409_DMIC_CFG,
+       CS8409_BEEP_CFG,
+       ASP1_RX_NULL_INS_RMV,
+       ASP1_Rx_RATE1,
+       ASP1_Rx_RATE2,
+       ASP1_Tx_NULL_INS_RMV,
+       ASP1_Tx_RATE1,
+       ASP1_Tx_RATE2,
+       ASP2_Rx_NULL_INS_RMV,
+       ASP2_Rx_RATE1,
+       ASP2_Rx_RATE2,
+       ASP2_Tx_NULL_INS_RMV,
+       ASP2_Tx_RATE1,
+       ASP2_Tx_RATE2,
+       ASP1_SYNC_CTRL,
+       ASP2_SYNC_CTRL,
+       ASP1_A_TX_CTRL1,
+       ASP1_A_TX_CTRL2,
+       ASP1_B_TX_CTRL1,
+       ASP1_B_TX_CTRL2,
+       ASP1_C_TX_CTRL1,
+       ASP1_C_TX_CTRL2,
+       ASP1_D_TX_CTRL1,
+       ASP1_D_TX_CTRL2,
+       ASP1_E_TX_CTRL1,
+       ASP1_E_TX_CTRL2,
+       ASP1_F_TX_CTRL1,
+       ASP1_F_TX_CTRL2,
+       ASP1_G_TX_CTRL1,
+       ASP1_G_TX_CTRL2,
+       ASP1_H_TX_CTRL1,
+       ASP1_H_TX_CTRL2,
+       ASP2_A_TX_CTRL1,
+       ASP2_A_TX_CTRL2,
+       ASP2_B_TX_CTRL1,
+       ASP2_B_TX_CTRL2,
+       ASP2_C_TX_CTRL1,
+       ASP2_C_TX_CTRL2,
+       ASP2_D_TX_CTRL1,
+       ASP2_D_TX_CTRL2,
+       ASP2_E_TX_CTRL1,
+       ASP2_E_TX_CTRL2,
+       ASP2_F_TX_CTRL1,
+       ASP2_F_TX_CTRL2,
+       ASP2_G_TX_CTRL1,
+       ASP2_G_TX_CTRL2,
+       ASP2_H_TX_CTRL1,
+       ASP2_H_TX_CTRL2,
+       ASP1_A_RX_CTRL1,
+       ASP1_A_RX_CTRL2,
+       ASP1_B_RX_CTRL1,
+       ASP1_B_RX_CTRL2,
+       ASP1_C_RX_CTRL1,
+       ASP1_C_RX_CTRL2,
+       ASP1_D_RX_CTRL1,
+       ASP1_D_RX_CTRL2,
+       ASP1_E_RX_CTRL1,
+       ASP1_E_RX_CTRL2,
+       ASP1_F_RX_CTRL1,
+       ASP1_F_RX_CTRL2,
+       ASP1_G_RX_CTRL1,
+       ASP1_G_RX_CTRL2,
+       ASP1_H_RX_CTRL1,
+       ASP1_H_RX_CTRL2,
+       ASP2_A_RX_CTRL1,
+       ASP2_A_RX_CTRL2,
+       ASP2_B_RX_CTRL1,
+       ASP2_B_RX_CTRL2,
+       ASP2_C_RX_CTRL1,
+       ASP2_C_RX_CTRL2,
+       ASP2_D_RX_CTRL1,
+       ASP2_D_RX_CTRL2,
+       ASP2_E_RX_CTRL1,
+       ASP2_E_RX_CTRL2,
+       ASP2_F_RX_CTRL1,
+       ASP2_F_RX_CTRL2,
+       ASP2_G_RX_CTRL1,
+       ASP2_G_RX_CTRL2,
+       ASP2_H_RX_CTRL1,
+       ASP2_H_RX_CTRL2,
+       CS8409_I2C_ADDR,
+       CS8409_I2C_DATA,
+       CS8409_I2C_CTRL,
+       CS8409_I2C_STS,
+       CS8409_I2C_QWRITE,
+       CS8409_I2C_QREAD,
+       CS8409_SPI_CTRL,
+       CS8409_SPI_TX_DATA,
+       CS8409_SPI_RX_DATA,
+       CS8409_SPI_STS,
+       CS8409_PFE_COEF_W1, /* Parametric filter engine coefficient write 1*/
+       CS8409_PFE_COEF_W2,
+       CS8409_PFE_CTRL1,
+       CS8409_PFE_CTRL2,
+       CS8409_PRE_SCALE_ATTN1,
+       CS8409_PRE_SCALE_ATTN2,
+       CS8409_PFE_COEF_MON1, /* Parametric filter engine coefficient monitor 1*/
+       CS8409_PFE_COEF_MON2,
+       CS8409_ASP1_INTRN_STS,
+       CS8409_ASP2_INTRN_STS,
+       CS8409_ASP1_RX_SCLK_COUNT,
+       CS8409_ASP1_TX_SCLK_COUNT,
+       CS8409_ASP2_RX_SCLK_COUNT,
+       CS8409_ASP2_TX_SCLK_COUNT,
+       CS8409_ASP_UNS_RESP_MASK,
+       CS8409_LOOPBACK_CTRL = 0x80,
+       CS8409_PAD_CFG_SLW_RATE_CTRL = 0x82, /* Pad Config and Slew Rate Control (CIR = 0x0082) */
+};
+
+/* CS42L42 Specific Definitions */
+
+#define CS8409_MAX_CODECS                      8
+#define CS42L42_VOLUMES                                (4U)
+#define CS42L42_HP_VOL_REAL_MIN                        (-63)
+#define CS42L42_HP_VOL_REAL_MAX                        (0)
+#define CS42L42_AMIC_VOL_REAL_MIN              (-97)
+#define CS42L42_AMIC_VOL_REAL_MAX              (12)
+#define CS42L42_REG_AMIC_VOL_MASK              (0x00FF)
+#define CS42L42_HSTYPE_MASK                    (0x03)
+#define CS42L42_I2C_TIMEOUT_US                 (20000)
+#define CS42L42_I2C_SLEEP_US                   (2000)
+#define CS42L42_PDN_TIMEOUT_US                 (250000)
+#define CS42L42_PDN_SLEEP_US                   (2000)
+#define CS42L42_ANA_MUTE_AB                    (0x0C)
+#define CS42L42_FULL_SCALE_VOL_MASK            (2)
+#define CS42L42_FULL_SCALE_VOL_0DB             (0)
+#define CS42L42_FULL_SCALE_VOL_MINUS6DB                (1)
+
+/* Dell BULLSEYE / WARLOCK / CYBORG Specific Definitions */
+
+#define CS42L42_I2C_ADDR                       (0x48 << 1)
+#define CS8409_CS42L42_RESET                   GENMASK(5, 5) /* CS8409_GPIO5 */
+#define CS8409_CS42L42_INT                     GENMASK(4, 4) /* CS8409_GPIO4 */
+#define CS8409_CYBORG_SPEAKER_PDN              GENMASK(2, 2) /* CS8409_GPIO2 */
+#define CS8409_WARLOCK_SPEAKER_PDN             GENMASK(1, 1) /* CS8409_GPIO1 */
+#define CS8409_CS42L42_HP_PIN_NID              CS8409_PIN_ASP1_TRANSMITTER_A
+#define CS8409_CS42L42_SPK_PIN_NID             CS8409_PIN_ASP2_TRANSMITTER_A
+#define CS8409_CS42L42_AMIC_PIN_NID            CS8409_PIN_ASP1_RECEIVER_A
+#define CS8409_CS42L42_DMIC_PIN_NID            CS8409_PIN_DMIC1_IN
+#define CS8409_CS42L42_DMIC_ADC_PIN_NID                CS8409_PIN_DMIC1
+
+/* Dolphin */
+
+#define DOLPHIN_C0_I2C_ADDR                    (0x48 << 1)
+#define DOLPHIN_C1_I2C_ADDR                    (0x49 << 1)
+#define DOLPHIN_HP_PIN_NID                     CS8409_PIN_ASP1_TRANSMITTER_A
+#define DOLPHIN_LO_PIN_NID                     CS8409_PIN_ASP1_TRANSMITTER_B
+#define DOLPHIN_AMIC_PIN_NID                   CS8409_PIN_ASP1_RECEIVER_A
+
+#define DOLPHIN_C0_INT                         GENMASK(4, 4)
+#define DOLPHIN_C1_INT                         GENMASK(0, 0)
+#define DOLPHIN_C0_RESET                       GENMASK(5, 5)
+#define DOLPHIN_C1_RESET                       GENMASK(1, 1)
+#define DOLPHIN_WAKE                           (DOLPHIN_C0_INT | DOLPHIN_C1_INT)
+
+enum {
+       CS8409_BULLSEYE,
+       CS8409_WARLOCK,
+       CS8409_WARLOCK_MLK,
+       CS8409_WARLOCK_MLK_DUAL_MIC,
+       CS8409_CYBORG,
+       CS8409_FIXUPS,
+       CS8409_DOLPHIN,
+       CS8409_DOLPHIN_FIXUPS,
+       CS8409_ODIN,
+};
+
+enum {
+       CS8409_CODEC0,
+       CS8409_CODEC1
+};
+
+enum {
+       CS42L42_VOL_ADC,
+       CS42L42_VOL_DAC,
+};
+
+#define CS42L42_ADC_VOL_OFFSET                 (CS42L42_VOL_ADC)
+#define CS42L42_DAC_CH0_VOL_OFFSET             (CS42L42_VOL_DAC)
+#define CS42L42_DAC_CH1_VOL_OFFSET             (CS42L42_VOL_DAC + 1)
+
+struct cs8409_i2c_param {
+       unsigned int addr;
+       unsigned int value;
+       unsigned int delay;
+};
+
+struct cs8409_cir_param {
+       unsigned int nid;
+       unsigned int cir;
+       unsigned int coeff;
+};
+
+struct sub_codec {
+       struct hda_codec *codec;
+       unsigned int addr;
+       unsigned int reset_gpio;
+       unsigned int irq_mask;
+       const struct cs8409_i2c_param *init_seq;
+       unsigned int init_seq_num;
+
+       unsigned int hp_jack_in:1;
+       unsigned int mic_jack_in:1;
+       unsigned int suspended:1;
+       unsigned int paged:1;
+       unsigned int last_page;
+       unsigned int hsbias_hiz;
+       unsigned int full_scale_vol:1;
+       unsigned int no_type_dect:1;
+
+       s8 vol[CS42L42_VOLUMES];
+};
+
+struct cs8409_spec {
+       struct hda_gen_spec gen;
+       struct hda_codec *codec;
+
+       struct sub_codec *scodecs[CS8409_MAX_CODECS];
+       unsigned int num_scodecs;
+
+       unsigned int gpio_mask;
+       unsigned int gpio_dir;
+       unsigned int gpio_data;
+
+       int speaker_pdn_gpio;
+
+       struct mutex i2c_mux;
+       unsigned int i2c_clck_enabled;
+       unsigned int dev_addr;
+       struct delayed_work i2c_clk_work;
+
+       unsigned int playback_started:1;
+       unsigned int capture_started:1;
+       unsigned int init_done:1;
+       unsigned int build_ctrl_done:1;
+
+       /* verb exec op override */
+       int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
+                        unsigned int *res);
+};
+
+extern const struct snd_kcontrol_new cs42l42_dac_volume_mixer;
+extern const struct snd_kcontrol_new cs42l42_adc_volume_mixer;
+
+int cs42l42_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo);
+int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl);
+int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl);
+
+extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback;
+extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture;
+extern const struct hda_quirk cs8409_fixup_tbl[];
+extern const struct hda_model_fixup cs8409_models[];
+extern const struct hda_fixup cs8409_fixups[];
+extern const struct hda_verb cs8409_cs42l42_init_verbs[];
+extern const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[];
+extern const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[];
+extern struct sub_codec cs8409_cs42l42_codec;
+
+extern const struct hda_verb dolphin_init_verbs[];
+extern const struct cs8409_cir_param dolphin_hw_cfg[];
+extern struct sub_codec dolphin_cs42l42_0;
+extern struct sub_codec dolphin_cs42l42_1;
+
+void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
+void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
+
+#endif
diff --git a/sound/hda/codecs/cmedia.c b/sound/hda/codecs/cmedia.c
new file mode 100644 (file)
index 0000000..c88da2f
--- /dev/null
@@ -0,0 +1,396 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for C-Media CMI9880
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+/* CM9825 Offset Definitions */
+
+#define CM9825_VERB_SET_HPF_1 0x781
+#define CM9825_VERB_SET_HPF_2 0x785
+#define CM9825_VERB_SET_PLL 0x7a0
+#define CM9825_VERB_SET_NEG 0x7a1
+#define CM9825_VERB_SET_ADCL 0x7a2
+#define CM9825_VERB_SET_DACL 0x7a3
+#define CM9825_VERB_SET_MBIAS 0x7a4
+#define CM9825_VERB_SET_VNEG 0x7a8
+#define CM9825_VERB_SET_D2S 0x7a9
+#define CM9825_VERB_SET_DACTRL 0x7aa
+#define CM9825_VERB_SET_PDNEG 0x7ac
+#define CM9825_VERB_SET_VDO 0x7ad
+#define CM9825_VERB_SET_CDALR 0x7b0
+#define CM9825_VERB_SET_MTCBA 0x7b1
+#define CM9825_VERB_SET_OTP 0x7b2
+#define CM9825_VERB_SET_OCP 0x7b3
+#define CM9825_VERB_SET_GAD 0x7b4
+#define CM9825_VERB_SET_TMOD 0x7b5
+#define CM9825_VERB_SET_SNR 0x7b6
+
+struct cmi_spec {
+       struct hda_gen_spec gen;
+       const struct hda_verb *chip_d0_verbs;
+       const struct hda_verb *chip_d3_verbs;
+       const struct hda_verb *chip_hp_present_verbs;
+       const struct hda_verb *chip_hp_remove_verbs;
+       struct hda_codec *codec;
+       struct delayed_work unsol_hp_work;
+       int quirk;
+};
+
+static const struct hda_verb cm9825_std_d3_verbs[] = {
+       /* chip sleep verbs */
+       {0x43, CM9825_VERB_SET_D2S, 0x62},      /* depop */
+       {0x43, CM9825_VERB_SET_PLL, 0x01},      /* PLL set */
+       {0x43, CM9825_VERB_SET_NEG, 0xc2},      /* NEG set */
+       {0x43, CM9825_VERB_SET_ADCL, 0x00},     /* ADC */
+       {0x43, CM9825_VERB_SET_DACL, 0x02},     /* DACL */
+       {0x43, CM9825_VERB_SET_VNEG, 0x50},     /* VOL NEG */
+       {0x43, CM9825_VERB_SET_MBIAS, 0x00},    /* MBIAS */
+       {0x43, CM9825_VERB_SET_PDNEG, 0x04},    /* SEL OSC */
+       {0x43, CM9825_VERB_SET_CDALR, 0xf6},    /* Class D */
+       {0x43, CM9825_VERB_SET_OTP, 0xcd},      /* OTP set */
+       {}
+};
+
+static const struct hda_verb cm9825_std_d0_verbs[] = {
+       /* chip init verbs */
+       {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},       /* EAPD set */
+       {0x43, CM9825_VERB_SET_SNR, 0x30},      /* SNR set */
+       {0x43, CM9825_VERB_SET_PLL, 0x00},      /* PLL set */
+       {0x43, CM9825_VERB_SET_ADCL, 0x00},     /* ADC */
+       {0x43, CM9825_VERB_SET_DACL, 0x02},     /* DACL */
+       {0x43, CM9825_VERB_SET_MBIAS, 0x00},    /* MBIAS */
+       {0x43, CM9825_VERB_SET_VNEG, 0x56},     /* VOL NEG */
+       {0x43, CM9825_VERB_SET_D2S, 0x62},      /* depop */
+       {0x43, CM9825_VERB_SET_DACTRL, 0x00},   /* DACTRL set */
+       {0x43, CM9825_VERB_SET_PDNEG, 0x0c},    /* SEL OSC */
+       {0x43, CM9825_VERB_SET_VDO, 0x80},      /* VDO set */
+       {0x43, CM9825_VERB_SET_CDALR, 0xf4},    /* Class D */
+       {0x43, CM9825_VERB_SET_OTP, 0xcd},      /* OTP set */
+       {0x43, CM9825_VERB_SET_MTCBA, 0x61},    /* SR set */
+       {0x43, CM9825_VERB_SET_OCP, 0x33},      /* OTP set */
+       {0x43, CM9825_VERB_SET_GAD, 0x07},      /* ADC -3db */
+       {0x43, CM9825_VERB_SET_TMOD, 0x26},     /* Class D clk */
+       {0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
+               AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d},    /* Gain set */
+       {0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
+               AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d},     /* Gain set */
+       {0x43, CM9825_VERB_SET_HPF_1, 0x40},    /* HPF set */
+       {0x43, CM9825_VERB_SET_HPF_2, 0x40},    /* HPF set */
+       {}
+};
+
+static const struct hda_verb cm9825_hp_present_verbs[] = {
+       {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},   /* PIN off */
+       {0x43, CM9825_VERB_SET_ADCL, 0x88},     /* ADC */
+       {0x43, CM9825_VERB_SET_DACL, 0xaa},     /* DACL */
+       {0x43, CM9825_VERB_SET_MBIAS, 0x10},    /* MBIAS */
+       {0x43, CM9825_VERB_SET_D2S, 0xf2},      /* depop */
+       {0x43, CM9825_VERB_SET_DACTRL, 0x00},   /* DACTRL set */
+       {0x43, CM9825_VERB_SET_VDO, 0xc4},      /* VDO set */
+       {}
+};
+
+static const struct hda_verb cm9825_hp_remove_verbs[] = {
+       {0x43, CM9825_VERB_SET_ADCL, 0x00},     /* ADC */
+       {0x43, CM9825_VERB_SET_DACL, 0x56},     /* DACL */
+       {0x43, CM9825_VERB_SET_MBIAS, 0x00},    /* MBIAS */
+       {0x43, CM9825_VERB_SET_D2S, 0x62},      /* depop */
+       {0x43, CM9825_VERB_SET_DACTRL, 0xe0},   /* DACTRL set */
+       {0x43, CM9825_VERB_SET_VDO, 0x80},      /* VDO set */
+       {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},   /* PIN on */
+       {}
+};
+
+static void cm9825_unsol_hp_delayed(struct work_struct *work)
+{
+       struct cmi_spec *spec =
+           container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work);
+       struct hda_jack_tbl *jack;
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+       bool hp_jack_plugin = false;
+       int err = 0;
+
+       hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
+
+       codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
+                 (int)hp_jack_plugin, hp_pin);
+
+       if (!hp_jack_plugin) {
+               err =
+                   snd_hda_codec_write(spec->codec, 0x42, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
+               if (err)
+                       codec_dbg(spec->codec, "codec_write err %d\n", err);
+
+               snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs);
+       } else {
+               snd_hda_sequence_write(spec->codec,
+                                      spec->chip_hp_present_verbs);
+       }
+
+       jack = snd_hda_jack_tbl_get(spec->codec, hp_pin);
+       if (jack) {
+               jack->block_report = 0;
+               snd_hda_jack_report_sync(spec->codec);
+       }
+}
+
+static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
+{
+       struct cmi_spec *spec = codec->spec;
+       struct hda_jack_tbl *tbl;
+
+       /* Delay enabling the HP amp, to let the mic-detection
+        * state machine run.
+        */
+
+       codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid);
+
+       tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+       if (tbl)
+               tbl->block_report = 1;
+       schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200));
+}
+
+static void cm9825_setup_unsol(struct hda_codec *codec)
+{
+       struct cmi_spec *spec = codec->spec;
+
+       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
+
+       snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
+}
+
+static int cm9825_init(struct hda_codec *codec)
+{
+       snd_hda_gen_init(codec);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+       return 0;
+}
+
+static void cm9825_free(struct hda_codec *codec)
+{
+       struct cmi_spec *spec = codec->spec;
+
+       cancel_delayed_work_sync(&spec->unsol_hp_work);
+       snd_hda_gen_free(codec);
+}
+
+static int cm9825_suspend(struct hda_codec *codec)
+{
+       struct cmi_spec *spec = codec->spec;
+
+       cancel_delayed_work_sync(&spec->unsol_hp_work);
+
+       snd_hda_sequence_write(codec, spec->chip_d3_verbs);
+
+       return 0;
+}
+
+static int cm9825_resume(struct hda_codec *codec)
+{
+       struct cmi_spec *spec = codec->spec;
+       hda_nid_t hp_pin = 0;
+       bool hp_jack_plugin = false;
+       int err;
+
+       err =
+           snd_hda_codec_write(spec->codec, 0x42, 0,
+                               AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
+       if (err)
+               codec_dbg(codec, "codec_write err %d\n", err);
+
+       msleep(150);            /* for depop noise */
+
+       codec->patch_ops.init(codec);
+
+       hp_pin = spec->gen.autocfg.hp_pins[0];
+       hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
+
+       codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
+                 (int)hp_jack_plugin, hp_pin);
+
+       if (!hp_jack_plugin) {
+               err =
+                   snd_hda_codec_write(spec->codec, 0x42, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
+
+               if (err)
+                       codec_dbg(codec, "codec_write err %d\n", err);
+
+               snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
+       }
+
+       snd_hda_regmap_sync(codec);
+       hda_call_check_power_status(codec, 0x01);
+
+       return 0;
+}
+
+/*
+ * stuff for auto-parser
+ */
+static const struct hda_codec_ops cmi_auto_patch_ops = {
+       .build_controls = snd_hda_gen_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = snd_hda_gen_init,
+       .free = snd_hda_gen_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+};
+
+static int patch_cm9825(struct hda_codec *codec)
+{
+       struct cmi_spec *spec;
+       struct auto_pin_cfg *cfg;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed);
+       codec->spec = spec;
+       spec->codec = codec;
+       codec->patch_ops = cmi_auto_patch_ops;
+       codec->patch_ops.init = cm9825_init;
+       codec->patch_ops.suspend = cm9825_suspend;
+       codec->patch_ops.resume = cm9825_resume;
+       codec->patch_ops.free = cm9825_free;
+       codec->patch_ops.check_power_status = snd_hda_gen_check_power_status;
+       cfg = &spec->gen.autocfg;
+       snd_hda_gen_spec_init(&spec->gen);
+       spec->chip_d0_verbs = cm9825_std_d0_verbs;
+       spec->chip_d3_verbs = cm9825_std_d3_verbs;
+       spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
+       spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
+
+       snd_hda_sequence_write(codec, spec->chip_d0_verbs);
+
+       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+       if (err < 0)
+               goto error;
+       err = snd_hda_gen_parse_auto_config(codec, cfg);
+       if (err < 0)
+               goto error;
+
+       cm9825_setup_unsol(codec);
+
+       return 0;
+
+ error:
+       cm9825_free(codec);
+
+       codec_info(codec, "Enter err %d\n", err);
+
+       return err;
+}
+
+static int patch_cmi9880(struct hda_codec *codec)
+{
+       struct cmi_spec *spec;
+       struct auto_pin_cfg *cfg;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       codec->patch_ops = cmi_auto_patch_ops;
+       cfg = &spec->gen.autocfg;
+       snd_hda_gen_spec_init(&spec->gen);
+
+       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+       if (err < 0)
+               goto error;
+       err = snd_hda_gen_parse_auto_config(codec, cfg);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+static int patch_cmi8888(struct hda_codec *codec)
+{
+       struct cmi_spec *spec;
+       struct auto_pin_cfg *cfg;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+
+       codec->spec = spec;
+       codec->patch_ops = cmi_auto_patch_ops;
+       cfg = &spec->gen.autocfg;
+       snd_hda_gen_spec_init(&spec->gen);
+
+       /* mask NID 0x10 from the playback volume selection;
+        * it's a headphone boost volume handled manually below
+        */
+       spec->gen.out_vol_mask = (1ULL << 0x10);
+
+       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+       if (err < 0)
+               goto error;
+       err = snd_hda_gen_parse_auto_config(codec, cfg);
+       if (err < 0)
+               goto error;
+
+       if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
+           AC_JACK_HP_OUT) {
+               static const struct snd_kcontrol_new amp_kctl =
+                       HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
+                                        0x10, 0, HDA_OUTPUT);
+               if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &amp_kctl)) {
+                       err = -ENOMEM;
+                       goto error;
+               }
+       }
+
+       return 0;
+
+ error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_cmedia[] = {
+       HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888),
+       HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880),
+       HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880),
+       HDA_CODEC_ENTRY(0x13f69825, "CM9825", patch_cm9825),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("C-Media HD-audio codec");
+
+static struct hda_codec_driver cmedia_driver = {
+       .id = snd_hda_id_cmedia,
+};
+
+module_hda_codec_driver(cmedia_driver);
diff --git a/sound/hda/codecs/conexant.c b/sound/hda/codecs/conexant.c
new file mode 100644 (file)
index 0000000..b7710a8
--- /dev/null
@@ -0,0 +1,1331 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio interface patch for Conexant HDA audio codec
+ *
+ * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
+ *                   Takashi Iwai <tiwai@suse.de>
+ *                   Tobin Davis  <tdavis@dsl-only.net>
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+struct conexant_spec {
+       struct hda_gen_spec gen;
+
+       /* extra EAPD pins */
+       unsigned int num_eapds;
+       hda_nid_t eapds[4];
+       bool dynamic_eapd;
+       hda_nid_t mute_led_eapd;
+
+       unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
+       /* OPLC XO specific */
+       bool recording;
+       bool dc_enable;
+       unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
+       struct nid_path *dc_mode_path;
+
+       int mute_led_polarity;
+       unsigned int gpio_led;
+       unsigned int gpio_mute_led_mask;
+       unsigned int gpio_mic_led_mask;
+       bool is_cx11880_sn6140;
+};
+
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new cxt_beep_mixer[] = {
+       HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
+};
+
+static int set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
+                       int idx, int dir)
+{
+       struct snd_kcontrol_new *knew;
+       unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+       int i;
+
+       spec->gen.beep_nid = nid;
+       for (i = 0; i < ARRAY_SIZE(cxt_beep_mixer); i++) {
+               knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+                                           &cxt_beep_mixer[i]);
+               if (!knew)
+                       return -ENOMEM;
+               knew->private_value = beep_amp;
+       }
+       return 0;
+}
+
+static int cx_auto_parse_beep(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       hda_nid_t nid;
+
+       for_each_hda_codec_node(nid, codec)
+               if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
+                       return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+       return 0;
+}
+#else
+#define cx_auto_parse_beep(codec)      0
+#endif
+
+/*
+ * Automatic parser for CX20641 & co
+ */
+
+/* parse EAPDs */
+static void cx_auto_parse_eapd(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       hda_nid_t nid;
+
+       for_each_hda_codec_node(nid, codec) {
+               if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+                       continue;
+               if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
+                       continue;
+               spec->eapds[spec->num_eapds++] = nid;
+               if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
+                       break;
+       }
+
+       /* NOTE: below is a wild guess; if we have more than two EAPDs,
+        * it's a new chip, where EAPDs are supposed to be associated to
+        * pins, and we can control EAPD per pin.
+        * OTOH, if only one or two EAPDs are found, it's an old chip,
+        * thus it might control over all pins.
+        */
+       if (spec->num_eapds > 2)
+               spec->dynamic_eapd = 1;
+}
+
+static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
+                             const hda_nid_t *pins, bool on)
+{
+       int i;
+       for (i = 0; i < num_pins; i++) {
+               if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
+                       snd_hda_codec_write(codec, pins[i], 0,
+                                           AC_VERB_SET_EAPD_BTLENABLE,
+                                           on ? 0x02 : 0);
+       }
+}
+
+/* turn on/off EAPD according to Master switch */
+static void cx_auto_vmaster_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct conexant_spec *spec = codec->spec;
+
+       cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
+}
+
+/* turn on/off EAPD according to Master switch (inversely!) for mute LED */
+static int cx_auto_vmaster_mute_led(struct led_classdev *led_cdev,
+                                   enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct conexant_spec *spec = codec->spec;
+
+       snd_hda_codec_write(codec, spec->mute_led_eapd, 0,
+                           AC_VERB_SET_EAPD_BTLENABLE,
+                           brightness ? 0x02 : 0x00);
+       return 0;
+}
+
+static void cxt_init_gpio_led(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
+
+       if (mask) {
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+                                   mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+                                   mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_led);
+       }
+}
+
+static void cx_fixup_headset_recog(struct hda_codec *codec)
+{
+       unsigned int mic_present;
+
+       /* fix some headset type recognize fail issue, such as EDIFIER headset */
+       /* set micbias output current comparator threshold from 66% to 55%. */
+       snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010);
+       /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register
+        * value adjustment trim from 2.2K ohms to 2.0K ohms.
+        */
+       snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10);
+       /* fix reboot headset type recognize fail issue */
+       mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0);
+       if (mic_present & AC_PINSENSE_PRESENCE)
+               /* enable headset mic VREF */
+               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
+       else
+               /* disable headset mic VREF */
+               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
+}
+
+static int cx_auto_init(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       snd_hda_gen_init(codec);
+       if (!spec->dynamic_eapd)
+               cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
+
+       cxt_init_gpio_led(codec);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+       if (spec->is_cx11880_sn6140)
+               cx_fixup_headset_recog(codec);
+
+       return 0;
+}
+
+static void cx_auto_shutdown(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       /* Turn the problematic codec into D3 to avoid spurious noises
+          from the internal speaker during (and after) reboot */
+       cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
+}
+
+static void cx_auto_free(struct hda_codec *codec)
+{
+       cx_auto_shutdown(codec);
+       snd_hda_gen_free(codec);
+}
+
+static void cx_process_headset_plugin(struct hda_codec *codec)
+{
+       unsigned int val;
+       unsigned int count = 0;
+
+       /* Wait headset detect done. */
+       do {
+               val = snd_hda_codec_read(codec, 0x1c, 0, 0xca0, 0x0);
+               if (val & 0x080) {
+                       codec_dbg(codec, "headset type detect done!\n");
+                       break;
+               }
+               msleep(20);
+               count++;
+       } while (count < 3);
+       val = snd_hda_codec_read(codec, 0x1c, 0, 0xcb0, 0x0);
+       if (val & 0x800) {
+               codec_dbg(codec, "headset plugin, type is CTIA\n");
+               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
+       } else if (val & 0x400) {
+               codec_dbg(codec, "headset plugin, type is OMTP\n");
+               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
+       } else {
+               codec_dbg(codec, "headphone plugin\n");
+       }
+}
+
+static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_callback *event)
+{
+       unsigned int mic_present;
+
+       /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled,
+        * the node 19 can only be configured to microphone or disabled.
+        * Check hp&mic tag to process headset plugin & plugout.
+        */
+       mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0);
+       if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */
+               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
+       else
+               cx_process_headset_plugin(codec);
+}
+
+static int cx_auto_suspend(struct hda_codec *codec)
+{
+       cx_auto_shutdown(codec);
+       return 0;
+}
+
+static const struct hda_codec_ops cx_auto_patch_ops = {
+       .build_controls = snd_hda_gen_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = cx_auto_init,
+       .free = cx_auto_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .suspend = cx_auto_suspend,
+       .check_power_status = snd_hda_gen_check_power_status,
+};
+
+/*
+ * pin fix-up
+ */
+enum {
+       CXT_PINCFG_LENOVO_X200,
+       CXT_PINCFG_LENOVO_TP410,
+       CXT_PINCFG_LEMOTE_A1004,
+       CXT_PINCFG_LEMOTE_A1205,
+       CXT_PINCFG_COMPAQ_CQ60,
+       CXT_FIXUP_STEREO_DMIC,
+       CXT_PINCFG_LENOVO_NOTEBOOK,
+       CXT_FIXUP_INC_MIC_BOOST,
+       CXT_FIXUP_HEADPHONE_MIC_PIN,
+       CXT_FIXUP_HEADPHONE_MIC,
+       CXT_FIXUP_GPIO1,
+       CXT_FIXUP_ASPIRE_DMIC,
+       CXT_FIXUP_THINKPAD_ACPI,
+       CXT_FIXUP_LENOVO_XPAD_ACPI,
+       CXT_FIXUP_OLPC_XO,
+       CXT_FIXUP_CAP_MIX_AMP,
+       CXT_FIXUP_TOSHIBA_P105,
+       CXT_FIXUP_HP_530,
+       CXT_FIXUP_CAP_MIX_AMP_5047,
+       CXT_FIXUP_MUTE_LED_EAPD,
+       CXT_FIXUP_HP_DOCK,
+       CXT_FIXUP_HP_SPECTRE,
+       CXT_FIXUP_HP_GATE_MIC,
+       CXT_FIXUP_MUTE_LED_GPIO,
+       CXT_FIXUP_HP_ELITEONE_OUT_DIS,
+       CXT_FIXUP_HP_ZBOOK_MUTE_LED,
+       CXT_FIXUP_HEADSET_MIC,
+       CXT_FIXUP_HP_MIC_NO_PRESENCE,
+       CXT_PINCFG_SWS_JS201D,
+       CXT_PINCFG_TOP_SPEAKER,
+       CXT_FIXUP_HP_A_U,
+};
+
+/* for hda_fixup_thinkpad_acpi() */
+#include "helpers/thinkpad.c"
+
+/* for hda_fixup_ideapad_acpi() */
+#include "helpers/ideapad_hotkey_led.c"
+
+static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+       spec->gen.inv_dmic_split = 1;
+}
+
+/* fix widget control pin settings */
+static void cxt_fixup_update_pinctl(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PROBE) {
+               /* Unset OUT_EN for this Node pin, leaving only HP_EN.
+                * This is the value stored in the codec register after
+                * the correct initialization of the previous windows boot.
+                */
+               snd_hda_set_pin_ctl_cache(codec, 0x1d, AC_PINCTL_HP_EN);
+       }
+}
+
+static void cxt5066_increase_mic_boost(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       snd_hda_override_amp_caps(codec, 0x17, HDA_OUTPUT,
+                                 (0x3 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x4 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (0 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+static void cxt_update_headset_mode(struct hda_codec *codec)
+{
+       /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
+       int i;
+       bool mic_mode = false;
+       struct conexant_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+
+       hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+
+       for (i = 0; i < cfg->num_inputs; i++)
+               if (cfg->inputs[i].pin == mux_pin) {
+                       mic_mode = !!cfg->inputs[i].is_headphone_mic;
+                       break;
+               }
+
+       if (mic_mode) {
+               snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
+               spec->gen.hp_jack_present = false;
+       } else {
+               snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
+               spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
+       }
+
+       snd_hda_gen_update_outputs(codec);
+}
+
+static void cxt_update_headset_mode_hook(struct hda_codec *codec,
+                                        struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       cxt_update_headset_mode(codec);
+}
+
+static void cxt_fixup_headphone_mic(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
+               snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410);
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               WARN_ON(spec->gen.cap_sync_hook);
+               spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
+               spec->gen.automute_hook = cxt_update_headset_mode;
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               cxt_update_headset_mode(codec);
+               break;
+       }
+}
+
+static void cxt_fixup_headset_mic(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               break;
+       }
+}
+
+/* OPLC XO 1.5 fixup */
+
+/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
+ * through the microphone jack.
+ * When the user enables this through a mixer switch, both internal and
+ * external microphones are disabled. Gain is fixed at 0dB. In this mode,
+ * we also allow the bias to be configured through a separate mixer
+ * control. */
+
+#define update_mic_pin(codec, nid, val)                                        \
+       snd_hda_codec_write_cache(codec, nid, 0,                        \
+                                  AC_VERB_SET_PIN_WIDGET_CONTROL, val)
+
+static const struct hda_input_mux olpc_xo_dc_bias = {
+       .num_items = 3,
+       .items = {
+               { "Off", PIN_IN },
+               { "50%", PIN_VREF50 },
+               { "80%", PIN_VREF80 },
+       },
+};
+
+static void olpc_xo_update_mic_boost(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int ch, val;
+
+       for (ch = 0; ch < 2; ch++) {
+               val = AC_AMP_SET_OUTPUT |
+                       (ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT);
+               if (!spec->dc_enable)
+                       val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0);
+               snd_hda_codec_write(codec, 0x17, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, val);
+       }
+}
+
+static void olpc_xo_update_mic_pins(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       int cur_input, val;
+       struct nid_path *path;
+
+       cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]];
+
+       /* Set up mic pins for port-B, C and F dynamically as the recording
+        * LED is turned on/off by these pin controls
+        */
+       if (!spec->dc_enable) {
+               /* disable DC bias path and pin for port F */
+               update_mic_pin(codec, 0x1e, 0);
+               snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
+
+               /* update port B (ext mic) and C (int mic) */
+               /* OLPC defers mic widget control until when capture is
+                * started because the microphone LED comes on as soon as
+                * these settings are put in place. if we did this before
+                * recording, it would give the false indication that
+                * recording is happening when it is not.
+                */
+               update_mic_pin(codec, 0x1a, spec->recording ?
+                              snd_hda_codec_get_pin_target(codec, 0x1a) : 0);
+               update_mic_pin(codec, 0x1b, spec->recording ?
+                              snd_hda_codec_get_pin_target(codec, 0x1b) : 0);
+               /* enable normal mic path */
+               path = snd_hda_get_path_from_idx(codec, cur_input);
+               if (path)
+                       snd_hda_activate_path(codec, path, true, false);
+       } else {
+               /* disable normal mic path */
+               path = snd_hda_get_path_from_idx(codec, cur_input);
+               if (path)
+                       snd_hda_activate_path(codec, path, false, false);
+
+               /* Even though port F is the DC input, the bias is controlled
+                * on port B.  We also leave that port as an active input (but
+                * unselected) in DC mode just in case that is necessary to
+                * make the bias setting take effect.
+                */
+               if (spec->recording)
+                       val = olpc_xo_dc_bias.items[spec->dc_input_bias].index;
+               else
+                       val = 0;
+               update_mic_pin(codec, 0x1a, val);
+               update_mic_pin(codec, 0x1b, 0);
+               /* enable DC bias path and pin */
+               update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
+               snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
+       }
+}
+
+/* mic_autoswitch hook */
+static void olpc_xo_automic(struct hda_codec *codec,
+                           struct hda_jack_callback *jack)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       /* in DC mode, we don't handle automic */
+       if (!spec->dc_enable)
+               snd_hda_gen_mic_autoswitch(codec, jack);
+       olpc_xo_update_mic_pins(codec);
+       if (spec->dc_enable)
+               olpc_xo_update_mic_boost(codec);
+}
+
+/* pcm_capture hook */
+static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo,
+                                struct hda_codec *codec,
+                                struct snd_pcm_substream *substream,
+                                int action)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       /* toggle spec->recording flag and update mic pins accordingly
+        * for turning on/off LED
+        */
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               spec->recording = 1;
+               olpc_xo_update_mic_pins(codec);
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               spec->recording = 0;
+               olpc_xo_update_mic_pins(codec);
+               break;
+       }
+}
+
+static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.integer.value[0] = spec->dc_enable;
+       return 0;
+}
+
+static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       int dc_enable = !!ucontrol->value.integer.value[0];
+
+       if (dc_enable == spec->dc_enable)
+               return 0;
+
+       spec->dc_enable = dc_enable;
+       olpc_xo_update_mic_pins(codec);
+       olpc_xo_update_mic_boost(codec);
+       return 1;
+}
+
+static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
+       return 0;
+}
+
+static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_info *uinfo)
+{
+       return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo);
+}
+
+static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       const struct hda_input_mux *imux = &olpc_xo_dc_bias;
+       unsigned int idx;
+
+       idx = ucontrol->value.enumerated.item[0];
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+       if (spec->dc_input_bias == idx)
+               return 0;
+
+       spec->dc_input_bias = idx;
+       if (spec->dc_enable)
+               olpc_xo_update_mic_pins(codec);
+       return 1;
+}
+
+static const struct snd_kcontrol_new olpc_xo_mixers[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DC Mode Enable Switch",
+               .info = snd_ctl_boolean_mono_info,
+               .get = olpc_xo_dc_mode_get,
+               .put = olpc_xo_dc_mode_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "DC Input Bias Enum",
+               .info = olpc_xo_dc_bias_enum_info,
+               .get = olpc_xo_dc_bias_enum_get,
+               .put = olpc_xo_dc_bias_enum_put,
+       },
+       {}
+};
+
+/* overriding mic boost put callback; update mic boost volume only when
+ * DC mode is disabled
+ */
+static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct conexant_spec *spec = codec->spec;
+       int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
+       if (ret > 0 && spec->dc_enable)
+               olpc_xo_update_mic_boost(codec);
+       return ret;
+}
+
+static void cxt_fixup_olpc_xo(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+       struct snd_kcontrol_new *kctl;
+       int i;
+
+       if (action != HDA_FIXUP_ACT_PROBE)
+               return;
+
+       spec->gen.mic_autoswitch_hook = olpc_xo_automic;
+       spec->gen.pcm_capture_hook = olpc_xo_capture_hook;
+       spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0);
+
+       snd_hda_add_new_ctls(codec, olpc_xo_mixers);
+
+       /* OLPC's microphone port is DC coupled for use with external sensors,
+        * therefore we use a 50% mic bias in order to center the input signal
+        * with the DC input range of the codec.
+        */
+       snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50);
+
+       /* override mic boost control */
+       snd_array_for_each(&spec->gen.kctls, i, kctl) {
+               if (!strcmp(kctl->name, "Mic Boost Volume")) {
+                       kctl->put = olpc_xo_mic_boost_put;
+                       break;
+               }
+       }
+}
+
+static void cxt_fixup_mute_led_eapd(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_eapd = 0x1b;
+               spec->dynamic_eapd = true;
+               snd_hda_gen_add_mute_led_cdev(codec, cx_auto_vmaster_mute_led);
+       }
+}
+
+/*
+ * Fix max input level on mixer widget to 0dB
+ * (originally it has 0x2b steps with 0dB offset 0x14)
+ */
+static void cxt_fixup_cap_mix_amp(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
+                                 (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+/*
+ * Fix max input level on mixer widget to 0dB
+ * (originally it has 0x1e steps with 0 dB offset 0x17)
+ */
+static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
+                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
+                                      const struct hda_fixup *fix,
+                                      int action)
+{
+       /* the mic pin (0x19) doesn't give an unsolicited event;
+        * probe the mic pin together with the headphone pin (0x16)
+        */
+       if (action == HDA_FIXUP_ACT_PROBE)
+               snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
+}
+
+/* update LED status via GPIO */
+static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+                               bool led_on)
+{
+       struct conexant_spec *spec = codec->spec;
+       unsigned int oldval = spec->gpio_led;
+
+       if (spec->mute_led_polarity)
+               led_on = !led_on;
+
+       if (led_on)
+               spec->gpio_led |= mask;
+       else
+               spec->gpio_led &= ~mask;
+       codec_dbg(codec, "mask:%d enabled:%d gpio_led:%d\n",
+                       mask, led_on, spec->gpio_led);
+       if (spec->gpio_led != oldval)
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_led);
+}
+
+/* turn on/off mute LED via GPIO per vmaster hook */
+static int cxt_gpio_mute_update(struct led_classdev *led_cdev,
+                               enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct conexant_spec *spec = codec->spec;
+
+       cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, brightness);
+       return 0;
+}
+
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static int cxt_gpio_micmute_update(struct led_classdev *led_cdev,
+                                  enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct conexant_spec *spec = codec->spec;
+
+       cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, brightness);
+       return 0;
+}
+
+static void cxt_setup_mute_led(struct hda_codec *codec,
+                              unsigned int mute, unsigned int mic_mute)
+{
+       struct conexant_spec *spec = codec->spec;
+
+       spec->gpio_led = 0;
+       spec->mute_led_polarity = 0;
+       if (mute) {
+               snd_hda_gen_add_mute_led_cdev(codec, cxt_gpio_mute_update);
+               spec->gpio_mute_led_mask = mute;
+       }
+       if (mic_mute) {
+               snd_hda_gen_add_micmute_led_cdev(codec, cxt_gpio_micmute_update);
+               spec->gpio_mic_led_mask = mic_mute;
+       }
+}
+
+static void cxt_setup_gpio_unmute(struct hda_codec *codec,
+                                 unsigned int gpio_mute_mask)
+{
+       if (gpio_mute_mask) {
+               // set gpio data to 0.
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, gpio_mute_mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, gpio_mute_mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_STICKY_MASK, 0);
+       }
+}
+
+static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               cxt_setup_mute_led(codec, 0x01, 0x02);
+}
+
+static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               cxt_setup_mute_led(codec, 0x10, 0x20);
+}
+
+static void cxt_fixup_hp_a_u(struct hda_codec *codec,
+                            const struct hda_fixup *fix, int action)
+{
+       // Init vers in BIOS mute the spk/hp by set gpio high to avoid pop noise,
+       // so need to unmute once by clearing the gpio data when runs into the system.
+       if (action == HDA_FIXUP_ACT_INIT)
+               cxt_setup_gpio_unmute(codec, 0x2);
+}
+
+/* ThinkPad X200 & co with cxt5051 */
+static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
+       { 0x16, 0x042140ff }, /* HP (seq# overridden) */
+       { 0x17, 0x21a11000 }, /* dock-mic */
+       { 0x19, 0x2121103f }, /* dock-HP */
+       { 0x1c, 0x21440100 }, /* dock SPDIF out */
+       {}
+};
+
+/* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
+static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = {
+       { 0x19, 0x042110ff }, /* HP (seq# overridden) */
+       { 0x1a, 0x21a190f0 }, /* dock-mic */
+       { 0x1c, 0x212140ff }, /* dock-HP */
+       {}
+};
+
+/* Lemote A1004/A1205 with cxt5066 */
+static const struct hda_pintbl cxt_pincfg_lemote[] = {
+       { 0x1a, 0x90a10020 }, /* Internal mic */
+       { 0x1b, 0x03a11020 }, /* External mic */
+       { 0x1d, 0x400101f0 }, /* Not used */
+       { 0x1e, 0x40a701f0 }, /* Not used */
+       { 0x20, 0x404501f0 }, /* Not used */
+       { 0x22, 0x404401f0 }, /* Not used */
+       { 0x23, 0x40a701f0 }, /* Not used */
+       {}
+};
+
+/* SuoWoSi/South-holding JS201D with sn6140 */
+static const struct hda_pintbl cxt_pincfg_sws_js201d[] = {
+       { 0x16, 0x03211040 }, /* hp out */
+       { 0x17, 0x91170110 }, /* SPK/Class_D */
+       { 0x18, 0x95a70130 }, /* Internal mic */
+       { 0x19, 0x03a11020 }, /* Headset Mic */
+       { 0x1a, 0x40f001f0 }, /* Not used */
+       { 0x21, 0x40f001f0 }, /* Not used */
+       {}
+};
+
+static const struct hda_fixup cxt_fixups[] = {
+       [CXT_PINCFG_LENOVO_X200] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cxt_pincfg_lenovo_x200,
+       },
+       [CXT_PINCFG_LENOVO_TP410] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cxt_pincfg_lenovo_tp410,
+               .chained = true,
+               .chain_id = CXT_FIXUP_THINKPAD_ACPI,
+       },
+       [CXT_PINCFG_LEMOTE_A1004] = {
+               .type = HDA_FIXUP_PINS,
+               .chained = true,
+               .chain_id = CXT_FIXUP_INC_MIC_BOOST,
+               .v.pins = cxt_pincfg_lemote,
+       },
+       [CXT_PINCFG_LEMOTE_A1205] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cxt_pincfg_lemote,
+       },
+       [CXT_PINCFG_COMPAQ_CQ60] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* 0x17 was falsely set up as a mic, it should 0x1d */
+                       { 0x17, 0x400001f0 },
+                       { 0x1d, 0x97a70120 },
+                       { }
+               }
+       },
+       [CXT_FIXUP_STEREO_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_stereo_dmic,
+       },
+       [CXT_PINCFG_LENOVO_NOTEBOOK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x05d71030 },
+                       { }
+               },
+               .chain_id = CXT_FIXUP_STEREO_DMIC,
+       },
+       [CXT_FIXUP_INC_MIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt5066_increase_mic_boost,
+       },
+       [CXT_FIXUP_HEADPHONE_MIC_PIN] = {
+               .type = HDA_FIXUP_PINS,
+               .chained = true,
+               .chain_id = CXT_FIXUP_HEADPHONE_MIC,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               }
+       },
+       [CXT_FIXUP_HEADPHONE_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_headphone_mic,
+       },
+       [CXT_FIXUP_GPIO1] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
+                       { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
+                       { 0x01, AC_VERB_SET_GPIO_DATA, 0x01 },
+                       { }
+               },
+       },
+       [CXT_FIXUP_ASPIRE_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_stereo_dmic,
+               .chained = true,
+               .chain_id = CXT_FIXUP_GPIO1,
+       },
+       [CXT_FIXUP_THINKPAD_ACPI] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = hda_fixup_thinkpad_acpi,
+       },
+       [CXT_FIXUP_LENOVO_XPAD_ACPI] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = hda_fixup_ideapad_acpi,
+               .chained = true,
+               .chain_id = CXT_FIXUP_THINKPAD_ACPI,
+       },
+       [CXT_FIXUP_OLPC_XO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_olpc_xo,
+       },
+       [CXT_FIXUP_CAP_MIX_AMP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_cap_mix_amp,
+       },
+       [CXT_FIXUP_TOSHIBA_P105] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x10, 0x961701f0 }, /* speaker/hp */
+                       { 0x12, 0x02a1901e }, /* ext mic */
+                       { 0x14, 0x95a70110 }, /* int mic */
+                       {}
+               },
+       },
+       [CXT_FIXUP_HP_530] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x90a60160 }, /* int mic */
+                       {}
+               },
+               .chained = true,
+               .chain_id = CXT_FIXUP_CAP_MIX_AMP,
+       },
+       [CXT_FIXUP_CAP_MIX_AMP_5047] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_cap_mix_amp_5047,
+       },
+       [CXT_FIXUP_MUTE_LED_EAPD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_mute_led_eapd,
+       },
+       [CXT_FIXUP_HP_DOCK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x21011020 }, /* line-out */
+                       { 0x18, 0x2181103f }, /* line-in */
+                       { }
+               },
+               .chained = true,
+               .chain_id = CXT_FIXUP_MUTE_LED_GPIO,
+       },
+       [CXT_FIXUP_HP_SPECTRE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* enable NID 0x1d for the speaker on top */
+                       { 0x1d, 0x91170111 },
+                       { }
+               }
+       },
+       [CXT_FIXUP_HP_GATE_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_hp_gate_mic_jack,
+       },
+       [CXT_FIXUP_MUTE_LED_GPIO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_mute_led_gpio,
+       },
+       [CXT_FIXUP_HP_ELITEONE_OUT_DIS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_update_pinctl,
+       },
+       [CXT_FIXUP_HP_ZBOOK_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_hp_zbook_mute_led,
+       },
+       [CXT_FIXUP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_headset_mic,
+       },
+       [CXT_FIXUP_HP_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02a1113c },
+                       { }
+               },
+               .chained = true,
+               .chain_id = CXT_FIXUP_HEADSET_MIC,
+       },
+       [CXT_PINCFG_SWS_JS201D] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = cxt_pincfg_sws_js201d,
+       },
+       [CXT_PINCFG_TOP_SPEAKER] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1d, 0x82170111 },
+                       { }
+               },
+       },
+       [CXT_FIXUP_HP_A_U] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cxt_fixup_hp_a_u,
+       },
+};
+
+static const struct hda_quirk cxt5045_fixups[] = {
+       SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530),
+       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105),
+       /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
+        * really bad sound over 0dB on NID 0x17.
+        */
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP),
+       {}
+};
+
+static const struct hda_model_fixup cxt5045_fixup_models[] = {
+       { .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" },
+       { .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" },
+       { .id = CXT_FIXUP_HP_530, .name = "hp-530" },
+       {}
+};
+
+static const struct hda_quirk cxt5047_fixups[] = {
+       /* HP laptops have really bad sound over 0 dB on NID 0x10.
+        */
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
+       {}
+};
+
+static const struct hda_model_fixup cxt5047_fixup_models[] = {
+       { .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" },
+       {}
+};
+
+static const struct hda_quirk cxt5051_fixups[] = {
+       SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
+       SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
+       {}
+};
+
+static const struct hda_model_fixup cxt5051_fixup_models[] = {
+       { .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" },
+       {}
+};
+
+static const struct hda_quirk cxt5066_fixups[] = {
+       SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
+       SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
+       SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
+       SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x8231, "HP ProBook 450 G4", CXT_FIXUP_MUTE_LED_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
+       SND_PCI_QUIRK(0x103c, 0x83e5, "HP EliteOne 1000 G2", CXT_FIXUP_HP_ELITEONE_OUT_DIS),
+       SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
+       SND_PCI_QUIRK(0x14f1, 0x0252, "MBX-Z60MR100", CXT_FIXUP_HP_A_U),
+       SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D),
+       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
+       SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21d2, "Lenovo T420s", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
+       SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
+       SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
+       /* NOTE: we'd need to extend the quirk for 17aa:3977 as the same
+        * PCI SSID is used on multiple Lenovo models
+        */
+       SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad/Ideapad", CXT_FIXUP_LENOVO_XPAD_ACPI),
+       SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
+       SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
+       HDA_CODEC_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER),
+       HDA_CODEC_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER),
+       {}
+};
+
+static const struct hda_model_fixup cxt5066_fixup_models[] = {
+       { .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" },
+       { .id = CXT_FIXUP_GPIO1, .name = "gpio1" },
+       { .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" },
+       { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" },
+       { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" },
+       { .id = CXT_FIXUP_LENOVO_XPAD_ACPI, .name = "thinkpad-ideapad" },
+       { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" },
+       { .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" },
+       { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
+       { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
+       { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
+       { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
+       { .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
+       { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
+       { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" },
+       { .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" },
+       { .id = CXT_PINCFG_TOP_SPEAKER, .name = "sirius-top-speaker" },
+       { .id = CXT_FIXUP_HP_A_U, .name = "HP-U-support" },
+       {}
+};
+
+/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
+ * can be created (bko#42825)
+ */
+static void add_cx5051_fake_mutes(struct hda_codec *codec)
+{
+       struct conexant_spec *spec = codec->spec;
+       static const hda_nid_t out_nids[] = {
+               0x10, 0x11, 0
+       };
+       const hda_nid_t *p;
+
+       for (p = out_nids; *p; p++)
+               snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
+                                         AC_AMPCAP_MIN_MUTE |
+                                         query_amp_caps(codec, *p, HDA_OUTPUT));
+       spec->gen.dac_min_mute = true;
+}
+
+static int patch_conexant_auto(struct hda_codec *codec)
+{
+       struct conexant_spec *spec;
+       int err;
+
+       codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       snd_hda_gen_spec_init(&spec->gen);
+       codec->spec = spec;
+       codec->patch_ops = cx_auto_patch_ops;
+
+       /* init cx11880/sn6140 flag and reset headset_present_flag */
+       switch (codec->core.vendor_id) {
+       case 0x14f11f86:
+       case 0x14f11f87:
+               spec->is_cx11880_sn6140 = true;
+               snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref);
+               break;
+       }
+
+       cx_auto_parse_eapd(codec);
+       spec->gen.own_eapd_ctl = 1;
+
+       switch (codec->core.vendor_id) {
+       case 0x14f15045:
+               codec->single_adc_amp = 1;
+               spec->gen.mixer_nid = 0x17;
+               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
+               snd_hda_pick_fixup(codec, cxt5045_fixup_models,
+                                  cxt5045_fixups, cxt_fixups);
+               break;
+       case 0x14f15047:
+               codec->pin_amp_workaround = 1;
+               spec->gen.mixer_nid = 0x19;
+               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
+               snd_hda_pick_fixup(codec, cxt5047_fixup_models,
+                                  cxt5047_fixups, cxt_fixups);
+               break;
+       case 0x14f15051:
+               add_cx5051_fake_mutes(codec);
+               codec->pin_amp_workaround = 1;
+               snd_hda_pick_fixup(codec, cxt5051_fixup_models,
+                                  cxt5051_fixups, cxt_fixups);
+               break;
+       case 0x14f15098:
+               codec->pin_amp_workaround = 1;
+               spec->gen.mixer_nid = 0x22;
+               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
+               snd_hda_pick_fixup(codec, cxt5066_fixup_models,
+                                  cxt5066_fixups, cxt_fixups);
+               break;
+       case 0x14f150f2:
+               codec->power_save_node = 1;
+               fallthrough;
+       default:
+               codec->pin_amp_workaround = 1;
+               snd_hda_pick_fixup(codec, cxt5066_fixup_models,
+                                  cxt5066_fixups, cxt_fixups);
+               break;
+       }
+
+       if (!spec->gen.vmaster_mute.hook && spec->dynamic_eapd)
+               spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
+                                      spec->parse_flags);
+       if (err < 0)
+               goto error;
+
+       err = cx_auto_parse_beep(codec);
+       if (err < 0)
+               goto error;
+
+       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+       if (err < 0)
+               goto error;
+
+       /* Some laptops with Conexant chips show stalls in S3 resume,
+        * which falls into the single-cmd mode.
+        * Better to make reset, then.
+        */
+       if (!codec->bus->core.sync_write) {
+               codec_info(codec,
+                          "Enable sync_write for stable communication\n");
+               codec->bus->core.sync_write = 1;
+               codec->bus->allow_bus_reset = 1;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       cx_auto_free(codec);
+       return err;
+}
+
+/*
+ */
+
+static const struct hda_device_id snd_hda_id_conexant[] = {
+       HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto),
+       HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Conexant HD-audio codec");
+
+static struct hda_codec_driver conexant_driver = {
+       .id = snd_hda_id_conexant,
+};
+
+module_hda_codec_driver(conexant_driver);
diff --git a/sound/hda/codecs/generic.c b/sound/hda/codecs/generic.c
new file mode 100644 (file)
index 0000000..873fd4b
--- /dev/null
@@ -0,0 +1,6160 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * Generic widget tree parser
+ *
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+#include <linux/sort.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/module.h>
+#include <linux/leds.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/tlv.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "hda_beep.h"
+#include "generic.h"
+
+
+/**
+ * snd_hda_gen_spec_init - initialize hda_gen_spec struct
+ * @spec: hda_gen_spec object to initialize
+ *
+ * Initialize the given hda_gen_spec object.
+ */
+int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
+{
+       snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
+       snd_array_init(&spec->paths, sizeof(struct nid_path), 8);
+       snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8);
+       mutex_init(&spec->pcm_mutex);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init);
+
+/**
+ * snd_hda_gen_add_kctl - Add a new kctl_new struct from the template
+ * @spec: hda_gen_spec object
+ * @name: name string to override the template, NULL if unchanged
+ * @temp: template for the new kctl
+ *
+ * Add a new kctl (actually snd_kcontrol_new to be instantiated later)
+ * element based on the given snd_kcontrol_new template @temp and the
+ * name string @name to the list in @spec.
+ * Returns the newly created object or NULL as error.
+ */
+struct snd_kcontrol_new *
+snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
+                    const struct snd_kcontrol_new *temp)
+{
+       struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
+       if (!knew)
+               return NULL;
+       *knew = *temp;
+       if (name)
+               knew->name = kstrdup(name, GFP_KERNEL);
+       else if (knew->name)
+               knew->name = kstrdup(knew->name, GFP_KERNEL);
+       if (!knew->name)
+               return NULL;
+       return knew;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_kctl);
+
+static void free_kctls(struct hda_gen_spec *spec)
+{
+       if (spec->kctls.list) {
+               struct snd_kcontrol_new *kctl = spec->kctls.list;
+               int i;
+               for (i = 0; i < spec->kctls.used; i++)
+                       kfree(kctl[i].name);
+       }
+       snd_array_free(&spec->kctls);
+}
+
+static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
+{
+       if (!spec)
+               return;
+       free_kctls(spec);
+       snd_array_free(&spec->paths);
+       snd_array_free(&spec->loopback_list);
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
+       if (spec->led_cdevs[LED_AUDIO_MUTE])
+               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
+       if (spec->led_cdevs[LED_AUDIO_MICMUTE])
+               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
+#endif
+}
+
+/*
+ * store user hints
+ */
+static void parse_user_hints(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int val;
+
+       val = snd_hda_get_bool_hint(codec, "jack_detect");
+       if (val >= 0)
+               codec->no_jack_detect = !val;
+       val = snd_hda_get_bool_hint(codec, "inv_jack_detect");
+       if (val >= 0)
+               codec->inv_jack_detect = !!val;
+       val = snd_hda_get_bool_hint(codec, "trigger_sense");
+       if (val >= 0)
+               codec->no_trigger_sense = !val;
+       val = snd_hda_get_bool_hint(codec, "inv_eapd");
+       if (val >= 0)
+               codec->inv_eapd = !!val;
+       val = snd_hda_get_bool_hint(codec, "pcm_format_first");
+       if (val >= 0)
+               codec->pcm_format_first = !!val;
+       val = snd_hda_get_bool_hint(codec, "sticky_stream");
+       if (val >= 0)
+               codec->no_sticky_stream = !val;
+       val = snd_hda_get_bool_hint(codec, "spdif_status_reset");
+       if (val >= 0)
+               codec->spdif_status_reset = !!val;
+       val = snd_hda_get_bool_hint(codec, "pin_amp_workaround");
+       if (val >= 0)
+               codec->pin_amp_workaround = !!val;
+       val = snd_hda_get_bool_hint(codec, "single_adc_amp");
+       if (val >= 0)
+               codec->single_adc_amp = !!val;
+       val = snd_hda_get_bool_hint(codec, "power_save_node");
+       if (val >= 0)
+               codec->power_save_node = !!val;
+
+       val = snd_hda_get_bool_hint(codec, "auto_mute");
+       if (val >= 0)
+               spec->suppress_auto_mute = !val;
+       val = snd_hda_get_bool_hint(codec, "auto_mic");
+       if (val >= 0)
+               spec->suppress_auto_mic = !val;
+       val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
+       if (val >= 0)
+               spec->line_in_auto_switch = !!val;
+       val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp");
+       if (val >= 0)
+               spec->auto_mute_via_amp = !!val;
+       val = snd_hda_get_bool_hint(codec, "need_dac_fix");
+       if (val >= 0)
+               spec->need_dac_fix = !!val;
+       val = snd_hda_get_bool_hint(codec, "primary_hp");
+       if (val >= 0)
+               spec->no_primary_hp = !val;
+       val = snd_hda_get_bool_hint(codec, "multi_io");
+       if (val >= 0)
+               spec->no_multi_io = !val;
+       val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
+       if (val >= 0)
+               spec->multi_cap_vol = !!val;
+       val = snd_hda_get_bool_hint(codec, "inv_dmic_split");
+       if (val >= 0)
+               spec->inv_dmic_split = !!val;
+       val = snd_hda_get_bool_hint(codec, "indep_hp");
+       if (val >= 0)
+               spec->indep_hp = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input");
+       if (val >= 0)
+               spec->add_stereo_mix_input = !!val;
+       /* the following two are just for compatibility */
+       val = snd_hda_get_bool_hint(codec, "add_out_jack_modes");
+       if (val >= 0)
+               spec->add_jack_modes = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
+       if (val >= 0)
+               spec->add_jack_modes = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_jack_modes");
+       if (val >= 0)
+               spec->add_jack_modes = !!val;
+       val = snd_hda_get_bool_hint(codec, "power_down_unused");
+       if (val >= 0)
+               spec->power_down_unused = !!val;
+       val = snd_hda_get_bool_hint(codec, "add_hp_mic");
+       if (val >= 0)
+               spec->hp_mic = !!val;
+       val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
+       if (val >= 0)
+               spec->suppress_hp_mic_detect = !val;
+       val = snd_hda_get_bool_hint(codec, "vmaster");
+       if (val >= 0)
+               spec->suppress_vmaster = !val;
+
+       if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
+               spec->mixer_nid = val;
+}
+
+/*
+ * pin control value accesses
+ */
+
+#define update_pin_ctl(codec, pin, val) \
+       snd_hda_codec_write_cache(codec, pin, 0, \
+                                  AC_VERB_SET_PIN_WIDGET_CONTROL, val)
+
+/* restore the pinctl based on the cached value */
+static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin)
+{
+       update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin));
+}
+
+/* set the pinctl target value and write it if requested */
+static void set_pin_target(struct hda_codec *codec, hda_nid_t pin,
+                          unsigned int val, bool do_write)
+{
+       if (!pin)
+               return;
+       val = snd_hda_correct_pin_ctl(codec, pin, val);
+       snd_hda_codec_set_pin_target(codec, pin, val);
+       if (do_write)
+               update_pin_ctl(codec, pin, val);
+}
+
+/* set pinctl target values for all given pins */
+static void set_pin_targets(struct hda_codec *codec, int num_pins,
+                           hda_nid_t *pins, unsigned int val)
+{
+       int i;
+       for (i = 0; i < num_pins; i++)
+               set_pin_target(codec, pins[i], val, false);
+}
+
+/*
+ * parsing paths
+ */
+
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+       int i;
+       for (i = 0; i < nums; i++)
+               if (list[i] == nid)
+                       return i;
+       return -1;
+}
+
+/* return true if the given NID is contained in the path */
+static bool is_nid_contained(struct nid_path *path, hda_nid_t nid)
+{
+       return find_idx_in_nid_list(nid, path->path, path->depth) >= 0;
+}
+
+static struct nid_path *get_nid_path(struct hda_codec *codec,
+                                    hda_nid_t from_nid, hda_nid_t to_nid,
+                                    int anchor_nid)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+       int i;
+
+       snd_array_for_each(&spec->paths, i, path) {
+               if (path->depth <= 0)
+                       continue;
+               if ((!from_nid || path->path[0] == from_nid) &&
+                   (!to_nid || path->path[path->depth - 1] == to_nid)) {
+                       if (!anchor_nid ||
+                           (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) ||
+                           (anchor_nid < 0 && !is_nid_contained(path, anchor_nid)))
+                               return path;
+               }
+       }
+       return NULL;
+}
+
+/**
+ * snd_hda_get_path_idx - get the index number corresponding to the path
+ * instance
+ * @codec: the HDA codec
+ * @path: nid_path object
+ *
+ * The returned index starts from 1, i.e. the actual array index with offset 1,
+ * and zero is handled as an invalid path
+ */
+int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *array = spec->paths.list;
+       ssize_t idx;
+
+       if (!spec->paths.used)
+               return 0;
+       idx = path - array;
+       if (idx < 0 || idx >= spec->paths.used)
+               return 0;
+       return idx + 1;
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_path_idx);
+
+/**
+ * snd_hda_get_path_from_idx - get the path instance corresponding to the
+ * given index number
+ * @codec: the HDA codec
+ * @idx: the path index
+ */
+struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (idx <= 0 || idx > spec->paths.used)
+               return NULL;
+       return snd_array_elem(&spec->paths, idx - 1);
+}
+EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx);
+
+/* check whether the given DAC is already found in any existing paths */
+static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct nid_path *path;
+       int i;
+
+       snd_array_for_each(&spec->paths, i, path) {
+               if (path->path[0] == nid)
+                       return true;
+       }
+       return false;
+}
+
+/* check whether the given two widgets can be connected */
+static bool is_reachable_path(struct hda_codec *codec,
+                             hda_nid_t from_nid, hda_nid_t to_nid)
+{
+       if (!from_nid || !to_nid)
+               return false;
+       return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
+}
+
+/* nid, dir and idx */
+#define AMP_VAL_COMPARE_MASK   (0xffff | (1U << 18) | (0x0f << 19))
+
+/* check whether the given ctl is already assigned in any path elements */
+static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct nid_path *path;
+       int i;
+
+       val &= AMP_VAL_COMPARE_MASK;
+       snd_array_for_each(&spec->paths, i, path) {
+               if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val)
+                       return true;
+       }
+       return false;
+}
+
+/* check whether a control with the given (nid, dir, idx) was assigned */
+static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
+                             int dir, int idx, int type)
+{
+       unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
+       return is_ctl_used(codec, val, type);
+}
+
+static void print_nid_path(struct hda_codec *codec,
+                          const char *pfx, struct nid_path *path)
+{
+       char buf[40];
+       char *pos = buf;
+       int i;
+
+       *pos = 0;
+       for (i = 0; i < path->depth; i++)
+               pos += scnprintf(pos, sizeof(buf) - (pos - buf), "%s%02x",
+                                pos != buf ? ":" : "",
+                                path->path[i]);
+
+       codec_dbg(codec, "%s path: depth=%d '%s'\n", pfx, path->depth, buf);
+}
+
+/* called recursively */
+static bool __parse_nid_path(struct hda_codec *codec,
+                            hda_nid_t from_nid, hda_nid_t to_nid,
+                            int anchor_nid, struct nid_path *path,
+                            int depth)
+{
+       const hda_nid_t *conn;
+       int i, nums;
+
+       if (to_nid == anchor_nid)
+               anchor_nid = 0; /* anchor passed */
+       else if (to_nid == (hda_nid_t)(-anchor_nid))
+               return false; /* hit the exclusive nid */
+
+       nums = snd_hda_get_conn_list(codec, to_nid, &conn);
+       for (i = 0; i < nums; i++) {
+               if (conn[i] != from_nid) {
+                       /* special case: when from_nid is 0,
+                        * try to find an empty DAC
+                        */
+                       if (from_nid ||
+                           get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
+                           is_dac_already_used(codec, conn[i]))
+                               continue;
+               }
+               /* anchor is not requested or already passed? */
+               if (anchor_nid <= 0)
+                       goto found;
+       }
+       if (depth >= MAX_NID_PATH_DEPTH)
+               return false;
+       for (i = 0; i < nums; i++) {
+               unsigned int type;
+               type = get_wcaps_type(get_wcaps(codec, conn[i]));
+               if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
+                   type == AC_WID_PIN)
+                       continue;
+               if (__parse_nid_path(codec, from_nid, conn[i],
+                                    anchor_nid, path, depth + 1))
+                       goto found;
+       }
+       return false;
+
+ found:
+       path->path[path->depth] = conn[i];
+       path->idx[path->depth + 1] = i;
+       if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
+               path->multi[path->depth + 1] = 1;
+       path->depth++;
+       return true;
+}
+
+/*
+ * snd_hda_parse_nid_path - parse the widget path from the given nid to
+ * the target nid
+ * @codec: the HDA codec
+ * @from_nid: the NID where the path start from
+ * @to_nid: the NID where the path ends at
+ * @anchor_nid: the anchor indication
+ * @path: the path object to store the result
+ *
+ * Returns true if a matching path is found.
+ *
+ * The parsing behavior depends on parameters:
+ * when @from_nid is 0, try to find an empty DAC;
+ * when @anchor_nid is set to a positive value, only paths through the widget
+ * with the given value are evaluated.
+ * when @anchor_nid is set to a negative value, paths through the widget
+ * with the negative of given value are excluded, only other paths are chosen.
+ * when @anchor_nid is zero, no special handling about path selection.
+ */
+static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
+                           hda_nid_t to_nid, int anchor_nid,
+                           struct nid_path *path)
+{
+       if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) {
+               path->path[path->depth] = to_nid;
+               path->depth++;
+               return true;
+       }
+       return false;
+}
+
+/**
+ * snd_hda_add_new_path - parse the path between the given NIDs and
+ * add to the path list
+ * @codec: the HDA codec
+ * @from_nid: the NID where the path start from
+ * @to_nid: the NID where the path ends at
+ * @anchor_nid: the anchor indication, see snd_hda_parse_nid_path()
+ *
+ * If no valid path is found, returns NULL.
+ */
+struct nid_path *
+snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
+                    hda_nid_t to_nid, int anchor_nid)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+
+       if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
+               return NULL;
+
+       /* check whether the path has been already added */
+       path = get_nid_path(codec, from_nid, to_nid, anchor_nid);
+       if (path)
+               return path;
+
+       path = snd_array_new(&spec->paths);
+       if (!path)
+               return NULL;
+       memset(path, 0, sizeof(*path));
+       if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path))
+               return path;
+       /* push back */
+       spec->paths.used--;
+       return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_hda_add_new_path);
+
+/* clear the given path as invalid so that it won't be picked up later */
+static void invalidate_nid_path(struct hda_codec *codec, int idx)
+{
+       struct nid_path *path = snd_hda_get_path_from_idx(codec, idx);
+       if (!path)
+               return;
+       memset(path, 0, sizeof(*path));
+}
+
+/* return a DAC if paired to the given pin by codec driver */
+static hda_nid_t get_preferred_dac(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const hda_nid_t *list = spec->preferred_dacs;
+
+       if (!list)
+               return 0;
+       for (; *list; list += 2)
+               if (*list == pin)
+                       return list[1];
+       return 0;
+}
+
+/* look for an empty DAC slot */
+static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
+                             bool is_digital)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       bool cap_digital;
+       int i;
+
+       for (i = 0; i < spec->num_all_dacs; i++) {
+               hda_nid_t nid = spec->all_dacs[i];
+               if (!nid || is_dac_already_used(codec, nid))
+                       continue;
+               cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
+               if (is_digital != cap_digital)
+                       continue;
+               if (is_reachable_path(codec, nid, pin))
+                       return nid;
+       }
+       return 0;
+}
+
+/* replace the channels in the composed amp value with the given number */
+static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
+{
+       val &= ~(0x3U << 16);
+       val |= chs << 16;
+       return val;
+}
+
+static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
+                         hda_nid_t nid2, int dir)
+{
+       if (!(get_wcaps(codec, nid1) & (1 << (dir + 1))))
+               return !(get_wcaps(codec, nid2) & (1 << (dir + 1)));
+       return (query_amp_caps(codec, nid1, dir) ==
+               query_amp_caps(codec, nid2, dir));
+}
+
+/* look for a widget suitable for assigning a mute switch in the path */
+static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
+                                      struct nid_path *path)
+{
+       int i;
+
+       for (i = path->depth - 1; i >= 0; i--) {
+               if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
+                       return path->path[i];
+               if (i != path->depth - 1 && i != 0 &&
+                   nid_has_mute(codec, path->path[i], HDA_INPUT))
+                       return path->path[i];
+       }
+       return 0;
+}
+
+/* look for a widget suitable for assigning a volume ctl in the path */
+static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
+                                     struct nid_path *path)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+
+       for (i = path->depth - 1; i >= 0; i--) {
+               hda_nid_t nid = path->path[i];
+               if ((spec->out_vol_mask >> nid) & 1)
+                       continue;
+               if (nid_has_volume(codec, nid, HDA_OUTPUT))
+                       return nid;
+       }
+       return 0;
+}
+
+/*
+ * path activation / deactivation
+ */
+
+/* can have the amp-in capability? */
+static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
+{
+       hda_nid_t nid = path->path[idx];
+       unsigned int caps = get_wcaps(codec, nid);
+       unsigned int type = get_wcaps_type(caps);
+
+       if (!(caps & AC_WCAP_IN_AMP))
+               return false;
+       if (type == AC_WID_PIN && idx > 0) /* only for input pins */
+               return false;
+       return true;
+}
+
+/* can have the amp-out capability? */
+static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
+{
+       hda_nid_t nid = path->path[idx];
+       unsigned int caps = get_wcaps(codec, nid);
+       unsigned int type = get_wcaps_type(caps);
+
+       if (!(caps & AC_WCAP_OUT_AMP))
+               return false;
+       if (type == AC_WID_PIN && !idx) /* only for output pins */
+               return false;
+       return true;
+}
+
+/* check whether the given (nid,dir,idx) is active */
+static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
+                         unsigned int dir, unsigned int idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int type = get_wcaps_type(get_wcaps(codec, nid));
+       const struct nid_path *path;
+       int i, n;
+
+       if (nid == codec->core.afg)
+               return true;
+
+       snd_array_for_each(&spec->paths, n, path) {
+               if (!path->active)
+                       continue;
+               if (codec->power_save_node) {
+                       if (!path->stream_enabled)
+                               continue;
+                       /* ignore unplugged paths except for DAC/ADC */
+                       if (!(path->pin_enabled || path->pin_fixed) &&
+                           type != AC_WID_AUD_OUT && type != AC_WID_AUD_IN)
+                               continue;
+               }
+               for (i = 0; i < path->depth; i++) {
+                       if (path->path[i] == nid) {
+                               if (dir == HDA_OUTPUT || idx == -1 ||
+                                   path->idx[i] == idx)
+                                       return true;
+                               break;
+                       }
+               }
+       }
+       return false;
+}
+
+/* check whether the NID is referred by any active paths */
+#define is_active_nid_for_any(codec, nid) \
+       is_active_nid(codec, nid, HDA_OUTPUT, -1)
+
+/* get the default amp value for the target state */
+static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
+                                  int dir, unsigned int caps, bool enable)
+{
+       unsigned int val = 0;
+
+       if (caps & AC_AMPCAP_NUM_STEPS) {
+               /* set to 0dB */
+               if (enable)
+                       val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
+       }
+       if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
+               if (!enable)
+                       val |= HDA_AMP_MUTE;
+       }
+       return val;
+}
+
+/* is this a stereo widget or a stereo-to-mono mix? */
+static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
+{
+       unsigned int wcaps = get_wcaps(codec, nid);
+       hda_nid_t conn;
+
+       if (wcaps & AC_WCAP_STEREO)
+               return true;
+       if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
+               return false;
+       if (snd_hda_get_num_conns(codec, nid) != 1)
+               return false;
+       if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
+               return false;
+       return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
+}
+
+/* initialize the amp value (only at the first time) */
+static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
+{
+       unsigned int caps = query_amp_caps(codec, nid, dir);
+       int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
+
+       if (is_stereo_amps(codec, nid, dir))
+               snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
+       else
+               snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
+}
+
+/* update the amp, doing in stereo or mono depending on NID */
+static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
+                     unsigned int mask, unsigned int val)
+{
+       if (is_stereo_amps(codec, nid, dir))
+               return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
+                                               mask, val);
+       else
+               return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+                                               mask, val);
+}
+
+/* calculate amp value mask we can modify;
+ * if the given amp is controlled by mixers, don't touch it
+ */
+static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
+                                          hda_nid_t nid, int dir, int idx,
+                                          unsigned int caps)
+{
+       unsigned int mask = 0xff;
+
+       if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
+               if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
+                       mask &= ~0x80;
+       }
+       if (caps & AC_AMPCAP_NUM_STEPS) {
+               if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
+                   is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
+                       mask &= ~0x7f;
+       }
+       return mask;
+}
+
+static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
+                        int idx, int idx_to_check, bool enable)
+{
+       unsigned int caps;
+       unsigned int mask, val;
+
+       caps = query_amp_caps(codec, nid, dir);
+       val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
+       mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
+       if (!mask)
+               return;
+
+       val &= mask;
+       update_amp(codec, nid, dir, idx, mask, val);
+}
+
+static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid,
+                                  int dir, int idx, int idx_to_check,
+                                  bool enable)
+{
+       /* check whether the given amp is still used by others */
+       if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
+               return;
+       activate_amp(codec, nid, dir, idx, idx_to_check, enable);
+}
+
+static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
+                            int i, bool enable)
+{
+       hda_nid_t nid = path->path[i];
+       init_amp(codec, nid, HDA_OUTPUT, 0);
+       check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
+}
+
+static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
+                           int i, bool enable, bool add_aamix)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const hda_nid_t *conn;
+       int n, nums, idx;
+       int type;
+       hda_nid_t nid = path->path[i];
+
+       nums = snd_hda_get_conn_list(codec, nid, &conn);
+       if (nums < 0)
+               return;
+       type = get_wcaps_type(get_wcaps(codec, nid));
+       if (type == AC_WID_PIN ||
+           (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
+               nums = 1;
+               idx = 0;
+       } else
+               idx = path->idx[i];
+
+       for (n = 0; n < nums; n++)
+               init_amp(codec, nid, HDA_INPUT, n);
+
+       /* here is a little bit tricky in comparison with activate_amp_out();
+        * when aa-mixer is available, we need to enable the path as well
+        */
+       for (n = 0; n < nums; n++) {
+               if (n != idx) {
+                       if (conn[n] != spec->mixer_merge_nid)
+                               continue;
+                       /* when aamix is disabled, force to off */
+                       if (!add_aamix) {
+                               activate_amp(codec, nid, HDA_INPUT, n, n, false);
+                               continue;
+                       }
+               }
+               check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
+       }
+}
+
+/* sync power of each widget in the given path */
+static hda_nid_t path_power_update(struct hda_codec *codec,
+                                  struct nid_path *path,
+                                  bool allow_powerdown)
+{
+       hda_nid_t nid, changed = 0;
+       int i, state, power;
+
+       for (i = 0; i < path->depth; i++) {
+               nid = path->path[i];
+               if (!(get_wcaps(codec, nid) & AC_WCAP_POWER))
+                       continue;
+               if (nid == codec->core.afg)
+                       continue;
+               if (!allow_powerdown || is_active_nid_for_any(codec, nid))
+                       state = AC_PWRST_D0;
+               else
+                       state = AC_PWRST_D3;
+               power = snd_hda_codec_read(codec, nid, 0,
+                                          AC_VERB_GET_POWER_STATE, 0);
+               if (power != (state | (state << 4))) {
+                       snd_hda_codec_write(codec, nid, 0,
+                                           AC_VERB_SET_POWER_STATE, state);
+                       changed = nid;
+                       /* all known codecs seem to be capable to handl
+                        * widgets state even in D3, so far.
+                        * if any new codecs need to restore the widget
+                        * states after D0 transition, call the function
+                        * below.
+                        */
+#if 0 /* disabled */
+                       if (state == AC_PWRST_D0)
+                               snd_hdac_regmap_sync_node(&codec->core, nid);
+#endif
+               }
+       }
+       return changed;
+}
+
+/* do sync with the last power state change */
+static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid)
+{
+       if (nid) {
+               msleep(10);
+               snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+       }
+}
+
+/**
+ * snd_hda_activate_path - activate or deactivate the given path
+ * @codec: the HDA codec
+ * @path: the path to activate/deactivate
+ * @enable: flag to activate or not
+ * @add_aamix: enable the input from aamix NID
+ *
+ * If @add_aamix is set, enable the input from aa-mix NID as well (if any).
+ */
+void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
+                          bool enable, bool add_aamix)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+
+       path->active = enable;
+
+       /* make sure the widget is powered up */
+       if (enable && (spec->power_down_unused || codec->power_save_node))
+               path_power_update(codec, path, codec->power_save_node);
+
+       for (i = path->depth - 1; i >= 0; i--) {
+               hda_nid_t nid = path->path[i];
+
+               if (enable && path->multi[i])
+                       snd_hda_codec_write_cache(codec, nid, 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           path->idx[i]);
+               if (has_amp_in(codec, path, i))
+                       activate_amp_in(codec, path, i, enable, add_aamix);
+               if (has_amp_out(codec, path, i))
+                       activate_amp_out(codec, path, i, enable);
+       }
+}
+EXPORT_SYMBOL_GPL(snd_hda_activate_path);
+
+/* if the given path is inactive, put widgets into D3 (only if suitable) */
+static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (!(spec->power_down_unused || codec->power_save_node) || path->active)
+               return;
+       sync_power_state_change(codec, path_power_update(codec, path, true));
+}
+
+/* turn on/off EAPD on the given pin */
+static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->own_eapd_ctl ||
+           !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
+               return;
+       if (spec->keep_eapd_on && !enable)
+               return;
+       if (codec->inv_eapd)
+               enable = !enable;
+       snd_hda_codec_write_cache(codec, pin, 0,
+                                  AC_VERB_SET_EAPD_BTLENABLE,
+                                  enable ? 0x02 : 0x00);
+}
+
+/* re-initialize the path specified by the given path index */
+static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
+{
+       struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
+       if (path)
+               snd_hda_activate_path(codec, path, path->active, false);
+}
+
+
+/*
+ * Helper functions for creating mixer ctl elements
+ */
+
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol);
+static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol);
+static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol);
+
+enum {
+       HDA_CTL_WIDGET_VOL,
+       HDA_CTL_WIDGET_MUTE,
+       HDA_CTL_BIND_MUTE,
+};
+static const struct snd_kcontrol_new control_templates[] = {
+       HDA_CODEC_VOLUME(NULL, 0, 0, 0),
+       /* only the put callback is replaced for handling the special mute */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = hda_gen_mixer_mute_put, /* replaced */
+               .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = hda_gen_bind_mute_get,
+               .put = hda_gen_bind_mute_put, /* replaced */
+               .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
+       },
+};
+
+/* add dynamic controls from template */
+static struct snd_kcontrol_new *
+add_control(struct hda_gen_spec *spec, int type, const char *name,
+                      int cidx, unsigned long val)
+{
+       struct snd_kcontrol_new *knew;
+
+       knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
+       if (!knew)
+               return NULL;
+       knew->index = cidx;
+       if (get_amp_nid_(val))
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
+       if (knew->access == 0)
+               knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+       knew->private_value = val;
+       return knew;
+}
+
+static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
+                               const char *pfx, const char *dir,
+                               const char *sfx, int cidx, unsigned long val)
+{
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       int len;
+
+       len = snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
+       if (snd_BUG_ON(len >= sizeof(name)))
+               return -EINVAL;
+       if (!add_control(spec, type, name, cidx, val))
+               return -ENOMEM;
+       return 0;
+}
+
+#define add_pb_vol_ctrl(spec, type, pfx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
+#define add_pb_sw_ctrl(spec, type, pfx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
+#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)                  \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
+#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)                   \
+       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
+
+static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx,
+                      unsigned int chs, struct nid_path *path)
+{
+       unsigned int val;
+       if (!path)
+               return 0;
+       val = path->ctls[NID_PATH_VOL_CTL];
+       if (!val)
+               return 0;
+       val = amp_val_replace_channels(val, chs);
+       return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val);
+}
+
+/* return the channel bits suitable for the given path->ctls[] */
+static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
+                              int type)
+{
+       int chs = 1; /* mono (left only) */
+       if (path) {
+               hda_nid_t nid = get_amp_nid_(path->ctls[type]);
+               if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
+                       chs = 3; /* stereo */
+       }
+       return chs;
+}
+
+static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx,
+                         struct nid_path *path)
+{
+       int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
+       return add_vol_ctl(codec, pfx, cidx, chs, path);
+}
+
+/* create a mute-switch for the given mixer widget;
+ * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
+ */
+static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx,
+                     unsigned int chs, struct nid_path *path)
+{
+       unsigned int val;
+       int type = HDA_CTL_WIDGET_MUTE;
+
+       if (!path)
+               return 0;
+       val = path->ctls[NID_PATH_MUTE_CTL];
+       if (!val)
+               return 0;
+       val = amp_val_replace_channels(val, chs);
+       if (get_amp_direction_(val) == HDA_INPUT) {
+               hda_nid_t nid = get_amp_nid_(val);
+               int nums = snd_hda_get_num_conns(codec, nid);
+               if (nums > 1) {
+                       type = HDA_CTL_BIND_MUTE;
+                       val |= nums << 19;
+               }
+       }
+       return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
+}
+
+static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
+                                 int cidx, struct nid_path *path)
+{
+       int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
+       return add_sw_ctl(codec, pfx, cidx, chs, path);
+}
+
+/* playback mute control with the software mute bit check */
+static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (spec->auto_mute_via_amp) {
+               hda_nid_t nid = get_amp_nid(kcontrol);
+               bool enabled = !((spec->mute_bits >> nid) & 1);
+               ucontrol->value.integer.value[0] &= enabled;
+               ucontrol->value.integer.value[1] &= enabled;
+       }
+}
+
+static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       sync_auto_mute_bits(kcontrol, ucontrol);
+       return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+}
+
+/*
+ * Bound mute controls
+ */
+#define AMP_VAL_IDX_SHIFT      19
+#define AMP_VAL_IDX_MASK       (0x0f<<19)
+
+static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned long pval;
+       int err;
+
+       mutex_lock(&codec->control_mutex);
+       pval = kcontrol->private_value;
+       kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
+       err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
+       kcontrol->private_value = pval;
+       mutex_unlock(&codec->control_mutex);
+       return err;
+}
+
+static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned long pval;
+       int i, indices, err = 0, change = 0;
+
+       sync_auto_mute_bits(kcontrol, ucontrol);
+
+       mutex_lock(&codec->control_mutex);
+       pval = kcontrol->private_value;
+       indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
+       for (i = 0; i < indices; i++) {
+               kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) |
+                       (i << AMP_VAL_IDX_SHIFT);
+               err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+               if (err < 0)
+                       break;
+               change |= err;
+       }
+       kcontrol->private_value = pval;
+       mutex_unlock(&codec->control_mutex);
+       return err < 0 ? err : change;
+}
+
+/* any ctl assigned to the path with the given index? */
+static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
+{
+       struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
+       return path && path->ctls[ctl_type];
+}
+
+static const char * const channel_name[] = {
+       "Front", "Surround", "CLFE", "Side", "Back",
+};
+
+/* give some appropriate ctl name prefix for the given line out channel */
+static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
+                                   int *index, int ctl_type)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       *index = 0;
+       if (cfg->line_outs == 1 && !spec->multi_ios &&
+           !codec->force_pin_prefix &&
+           !cfg->hp_outs && !cfg->speaker_outs)
+               return spec->vmaster_mute.hook ? "PCM" : "Master";
+
+       /* if there is really a single DAC used in the whole output paths,
+        * use it master (or "PCM" if a vmaster hook is present)
+        */
+       if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
+           !codec->force_pin_prefix &&
+           !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
+               return spec->vmaster_mute.hook ? "PCM" : "Master";
+
+       /* multi-io channels */
+       if (ch >= cfg->line_outs)
+               goto fixed_name;
+
+       switch (cfg->line_out_type) {
+       case AUTO_PIN_SPEAKER_OUT:
+               /* if the primary channel vol/mute is shared with HP volume,
+                * don't name it as Speaker
+                */
+               if (!ch && cfg->hp_outs &&
+                   !path_has_mixer(codec, spec->hp_paths[0], ctl_type))
+                       break;
+               if (cfg->line_outs == 1)
+                       return "Speaker";
+               if (cfg->line_outs == 2)
+                       return ch ? "Bass Speaker" : "Speaker";
+               break;
+       case AUTO_PIN_HP_OUT:
+               /* if the primary channel vol/mute is shared with spk volume,
+                * don't name it as Headphone
+                */
+               if (!ch && cfg->speaker_outs &&
+                   !path_has_mixer(codec, spec->speaker_paths[0], ctl_type))
+                       break;
+               /* for multi-io case, only the primary out */
+               if (ch && spec->multi_ios)
+                       break;
+               *index = ch;
+               return "Headphone";
+       case AUTO_PIN_LINE_OUT:
+               /* This deals with the case where one HP or one Speaker or
+                * one HP + one Speaker need to share the DAC with LO
+                */
+               if (!ch) {
+                       bool hp_lo_shared = false, spk_lo_shared = false;
+
+                       if (cfg->speaker_outs)
+                               spk_lo_shared = !path_has_mixer(codec,
+                                                               spec->speaker_paths[0], ctl_type);
+                       if (cfg->hp_outs)
+                               hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type);
+                       if (hp_lo_shared && spk_lo_shared)
+                               return spec->vmaster_mute.hook ? "PCM" : "Master";
+                       if (hp_lo_shared)
+                               return "Headphone+LO";
+                       if (spk_lo_shared)
+                               return "Speaker+LO";
+               }
+       }
+
+       /* for a single channel output, we don't have to name the channel */
+       if (cfg->line_outs == 1 && !spec->multi_ios)
+               return "Line Out";
+
+ fixed_name:
+       if (ch >= ARRAY_SIZE(channel_name)) {
+               snd_BUG();
+               return "PCM";
+       }
+
+       return channel_name[ch];
+}
+
+/*
+ * Parse output paths
+ */
+
+/* badness definition */
+enum {
+       /* No primary DAC is found for the main output */
+       BAD_NO_PRIMARY_DAC = 0x10000,
+       /* No DAC is found for the extra output */
+       BAD_NO_DAC = 0x4000,
+       /* No possible multi-ios */
+       BAD_MULTI_IO = 0x120,
+       /* No individual DAC for extra output */
+       BAD_NO_EXTRA_DAC = 0x102,
+       /* No individual DAC for extra surrounds */
+       BAD_NO_EXTRA_SURR_DAC = 0x101,
+       /* Primary DAC shared with main surrounds */
+       BAD_SHARED_SURROUND = 0x100,
+       /* No independent HP possible */
+       BAD_NO_INDEP_HP = 0x10,
+       /* Primary DAC shared with main CLFE */
+       BAD_SHARED_CLFE = 0x10,
+       /* Primary DAC shared with extra surrounds */
+       BAD_SHARED_EXTRA_SURROUND = 0x10,
+       /* Volume widget is shared */
+       BAD_SHARED_VOL = 0x10,
+};
+
+/* look for widgets in the given path which are appropriate for
+ * volume and mute controls, and assign the values to ctls[].
+ *
+ * When no appropriate widget is found in the path, the badness value
+ * is incremented depending on the situation.  The function returns the
+ * total badness for both volume and mute controls.
+ */
+static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t nid;
+       unsigned int val;
+       int badness = 0;
+
+       if (!path)
+               return BAD_SHARED_VOL * 2;
+
+       if (path->ctls[NID_PATH_VOL_CTL] ||
+           path->ctls[NID_PATH_MUTE_CTL])
+               return 0; /* already evaluated */
+
+       nid = look_for_out_vol_nid(codec, path);
+       if (nid) {
+               val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+               if (spec->dac_min_mute)
+                       val |= HDA_AMP_VAL_MIN_MUTE;
+               if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
+                       badness += BAD_SHARED_VOL;
+               else
+                       path->ctls[NID_PATH_VOL_CTL] = val;
+       } else
+               badness += BAD_SHARED_VOL;
+       nid = look_for_out_mute_nid(codec, path);
+       if (nid) {
+               unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
+               if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
+                   nid_has_mute(codec, nid, HDA_OUTPUT))
+                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+               else
+                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
+               if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
+                       badness += BAD_SHARED_VOL;
+               else
+                       path->ctls[NID_PATH_MUTE_CTL] = val;
+       } else
+               badness += BAD_SHARED_VOL;
+       return badness;
+}
+
+const struct badness_table hda_main_out_badness = {
+       .no_primary_dac = BAD_NO_PRIMARY_DAC,
+       .no_dac = BAD_NO_DAC,
+       .shared_primary = BAD_NO_PRIMARY_DAC,
+       .shared_surr = BAD_SHARED_SURROUND,
+       .shared_clfe = BAD_SHARED_CLFE,
+       .shared_surr_main = BAD_SHARED_SURROUND,
+};
+EXPORT_SYMBOL_GPL(hda_main_out_badness);
+
+const struct badness_table hda_extra_out_badness = {
+       .no_primary_dac = BAD_NO_DAC,
+       .no_dac = BAD_NO_DAC,
+       .shared_primary = BAD_NO_EXTRA_DAC,
+       .shared_surr = BAD_SHARED_EXTRA_SURROUND,
+       .shared_clfe = BAD_SHARED_EXTRA_SURROUND,
+       .shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
+};
+EXPORT_SYMBOL_GPL(hda_extra_out_badness);
+
+/* get the DAC of the primary output corresponding to the given array index */
+static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+
+       if (cfg->line_outs > idx)
+               return spec->private_dac_nids[idx];
+       idx -= cfg->line_outs;
+       if (spec->multi_ios > idx)
+               return spec->multi_io[idx].dac;
+       return 0;
+}
+
+/* return the DAC if it's reachable, otherwise zero */
+static inline hda_nid_t try_dac(struct hda_codec *codec,
+                               hda_nid_t dac, hda_nid_t pin)
+{
+       return is_reachable_path(codec, dac, pin) ? dac : 0;
+}
+
+/* try to assign DACs to pins and return the resultant badness */
+static int try_assign_dacs(struct hda_codec *codec, int num_outs,
+                          const hda_nid_t *pins, hda_nid_t *dacs,
+                          int *path_idx,
+                          const struct badness_table *bad)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i, j;
+       int badness = 0;
+       hda_nid_t dac;
+
+       if (!num_outs)
+               return 0;
+
+       for (i = 0; i < num_outs; i++) {
+               struct nid_path *path;
+               hda_nid_t pin = pins[i];
+
+               if (!spec->preferred_dacs) {
+                       path = snd_hda_get_path_from_idx(codec, path_idx[i]);
+                       if (path) {
+                               badness += assign_out_path_ctls(codec, path);
+                               continue;
+                       }
+               }
+
+               dacs[i] = get_preferred_dac(codec, pin);
+               if (dacs[i]) {
+                       if (is_dac_already_used(codec, dacs[i]))
+                               badness += bad->shared_primary;
+               } else if (spec->preferred_dacs) {
+                       badness += BAD_NO_PRIMARY_DAC;
+               }
+
+               if (!dacs[i])
+                       dacs[i] = look_for_dac(codec, pin, false);
+               if (!dacs[i] && !i) {
+                       /* try to steal the DAC of surrounds for the front */
+                       for (j = 1; j < num_outs; j++) {
+                               if (is_reachable_path(codec, dacs[j], pin)) {
+                                       dacs[0] = dacs[j];
+                                       dacs[j] = 0;
+                                       invalidate_nid_path(codec, path_idx[j]);
+                                       path_idx[j] = 0;
+                                       break;
+                               }
+                       }
+               }
+               dac = dacs[i];
+               if (!dac) {
+                       if (num_outs > 2)
+                               dac = try_dac(codec, get_primary_out(codec, i), pin);
+                       if (!dac)
+                               dac = try_dac(codec, dacs[0], pin);
+                       if (!dac)
+                               dac = try_dac(codec, get_primary_out(codec, i), pin);
+                       if (dac) {
+                               if (!i)
+                                       badness += bad->shared_primary;
+                               else if (i == 1)
+                                       badness += bad->shared_surr;
+                               else
+                                       badness += bad->shared_clfe;
+                       } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) {
+                               dac = spec->private_dac_nids[0];
+                               badness += bad->shared_surr_main;
+                       } else if (!i)
+                               badness += bad->no_primary_dac;
+                       else
+                               badness += bad->no_dac;
+               }
+               if (!dac)
+                       continue;
+               path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid);
+               if (!path && !i && spec->mixer_nid) {
+                       /* try with aamix */
+                       path = snd_hda_add_new_path(codec, dac, pin, 0);
+               }
+               if (!path) {
+                       dacs[i] = 0;
+                       badness += bad->no_dac;
+               } else {
+                       /* print_nid_path(codec, "output", path); */
+                       path->active = true;
+                       path_idx[i] = snd_hda_get_path_idx(codec, path);
+                       badness += assign_out_path_ctls(codec, path);
+               }
+       }
+
+       return badness;
+}
+
+/* return NID if the given pin has only a single connection to a certain DAC */
+static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+       hda_nid_t nid_found = 0;
+
+       for (i = 0; i < spec->num_all_dacs; i++) {
+               hda_nid_t nid = spec->all_dacs[i];
+               if (!nid || is_dac_already_used(codec, nid))
+                       continue;
+               if (is_reachable_path(codec, nid, pin)) {
+                       if (nid_found)
+                               return 0;
+                       nid_found = nid;
+               }
+       }
+       return nid_found;
+}
+
+/* check whether the given pin can be a multi-io pin */
+static bool can_be_multiio_pin(struct hda_codec *codec,
+                              unsigned int location, hda_nid_t nid)
+{
+       unsigned int defcfg, caps;
+
+       defcfg = snd_hda_codec_get_pincfg(codec, nid);
+       if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
+               return false;
+       if (location && get_defcfg_location(defcfg) != location)
+               return false;
+       caps = snd_hda_query_pin_caps(codec, nid);
+       if (!(caps & AC_PINCAP_OUT))
+               return false;
+       return true;
+}
+
+/* count the number of input pins that are capable to be multi-io */
+static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
+       unsigned int location = get_defcfg_location(defcfg);
+       int type, i;
+       int num_pins = 0;
+
+       for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+               for (i = 0; i < cfg->num_inputs; i++) {
+                       if (cfg->inputs[i].type != type)
+                               continue;
+                       if (can_be_multiio_pin(codec, location,
+                                              cfg->inputs[i].pin))
+                               num_pins++;
+               }
+       }
+       return num_pins;
+}
+
+/*
+ * multi-io helper
+ *
+ * When hardwired is set, try to fill ony hardwired pins, and returns
+ * zero if any pins are filled, non-zero if nothing found.
+ * When hardwired is off, try to fill possible input pins, and returns
+ * the badness value.
+ */
+static int fill_multi_ios(struct hda_codec *codec,
+                         hda_nid_t reference_pin,
+                         bool hardwired)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int type, i, j, num_pins, old_pins;
+       unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
+       unsigned int location = get_defcfg_location(defcfg);
+       int badness = 0;
+       struct nid_path *path;
+
+       old_pins = spec->multi_ios;
+       if (old_pins >= 2)
+               goto end_fill;
+
+       num_pins = count_multiio_pins(codec, reference_pin);
+       if (num_pins < 2)
+               goto end_fill;
+
+       for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
+               for (i = 0; i < cfg->num_inputs; i++) {
+                       hda_nid_t nid = cfg->inputs[i].pin;
+                       hda_nid_t dac = 0;
+
+                       if (cfg->inputs[i].type != type)
+                               continue;
+                       if (!can_be_multiio_pin(codec, location, nid))
+                               continue;
+                       for (j = 0; j < spec->multi_ios; j++) {
+                               if (nid == spec->multi_io[j].pin)
+                                       break;
+                       }
+                       if (j < spec->multi_ios)
+                               continue;
+
+                       if (hardwired)
+                               dac = get_dac_if_single(codec, nid);
+                       else if (!dac)
+                               dac = look_for_dac(codec, nid, false);
+                       if (!dac) {
+                               badness++;
+                               continue;
+                       }
+                       path = snd_hda_add_new_path(codec, dac, nid,
+                                                   -spec->mixer_nid);
+                       if (!path) {
+                               badness++;
+                               continue;
+                       }
+                       /* print_nid_path(codec, "multiio", path); */
+                       spec->multi_io[spec->multi_ios].pin = nid;
+                       spec->multi_io[spec->multi_ios].dac = dac;
+                       spec->out_paths[cfg->line_outs + spec->multi_ios] =
+                               snd_hda_get_path_idx(codec, path);
+                       spec->multi_ios++;
+                       if (spec->multi_ios >= 2)
+                               break;
+               }
+       }
+ end_fill:
+       if (badness)
+               badness = BAD_MULTI_IO;
+       if (old_pins == spec->multi_ios) {
+               if (hardwired)
+                       return 1; /* nothing found */
+               else
+                       return badness; /* no badness if nothing found */
+       }
+       if (!hardwired && spec->multi_ios < 2) {
+               /* cancel newly assigned paths */
+               spec->paths.used -= spec->multi_ios - old_pins;
+               spec->multi_ios = old_pins;
+               return badness;
+       }
+
+       /* assign volume and mute controls */
+       for (i = old_pins; i < spec->multi_ios; i++) {
+               path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]);
+               badness += assign_out_path_ctls(codec, path);
+       }
+
+       return badness;
+}
+
+/* map DACs for all pins in the list if they are single connections */
+static bool map_singles(struct hda_codec *codec, int outs,
+                       const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+       bool found = false;
+       for (i = 0; i < outs; i++) {
+               struct nid_path *path;
+               hda_nid_t dac;
+               if (dacs[i])
+                       continue;
+               dac = get_dac_if_single(codec, pins[i]);
+               if (!dac)
+                       continue;
+               path = snd_hda_add_new_path(codec, dac, pins[i],
+                                           -spec->mixer_nid);
+               if (!path && !i && spec->mixer_nid)
+                       path = snd_hda_add_new_path(codec, dac, pins[i], 0);
+               if (path) {
+                       dacs[i] = dac;
+                       found = true;
+                       /* print_nid_path(codec, "output", path); */
+                       path->active = true;
+                       path_idx[i] = snd_hda_get_path_idx(codec, path);
+               }
+       }
+       return found;
+}
+
+static inline bool has_aamix_out_paths(struct hda_gen_spec *spec)
+{
+       return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
+               spec->aamix_out_paths[2];
+}
+
+/* create a new path including aamix if available, and return its index */
+static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+       hda_nid_t path_dac, dac, pin;
+
+       path = snd_hda_get_path_from_idx(codec, path_idx);
+       if (!path || !path->depth ||
+           is_nid_contained(path, spec->mixer_nid))
+               return 0;
+       path_dac = path->path[0];
+       dac = spec->private_dac_nids[0];
+       pin = path->path[path->depth - 1];
+       path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid);
+       if (!path) {
+               if (dac != path_dac)
+                       dac = path_dac;
+               else if (spec->multiout.hp_out_nid[0])
+                       dac = spec->multiout.hp_out_nid[0];
+               else if (spec->multiout.extra_out_nid[0])
+                       dac = spec->multiout.extra_out_nid[0];
+               else
+                       dac = 0;
+               if (dac)
+                       path = snd_hda_add_new_path(codec, dac, pin,
+                                                   spec->mixer_nid);
+       }
+       if (!path)
+               return 0;
+       /* print_nid_path(codec, "output-aamix", path); */
+       path->active = false; /* unused as default */
+       path->pin_fixed = true; /* static route */
+       return snd_hda_get_path_idx(codec, path);
+}
+
+/* check whether the independent HP is available with the current config */
+static bool indep_hp_possible(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct nid_path *path;
+       int i, idx;
+
+       if (cfg->line_out_type == AUTO_PIN_HP_OUT)
+               idx = spec->out_paths[0];
+       else
+               idx = spec->hp_paths[0];
+       path = snd_hda_get_path_from_idx(codec, idx);
+       if (!path)
+               return false;
+
+       /* assume no path conflicts unless aamix is involved */
+       if (!spec->mixer_nid || !is_nid_contained(path, spec->mixer_nid))
+               return true;
+
+       /* check whether output paths contain aamix */
+       for (i = 0; i < cfg->line_outs; i++) {
+               if (spec->out_paths[i] == idx)
+                       break;
+               path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
+               if (path && is_nid_contained(path, spec->mixer_nid))
+                       return false;
+       }
+       for (i = 0; i < cfg->speaker_outs; i++) {
+               path = snd_hda_get_path_from_idx(codec, spec->speaker_paths[i]);
+               if (path && is_nid_contained(path, spec->mixer_nid))
+                       return false;
+       }
+
+       return true;
+}
+
+/* fill the empty entries in the dac array for speaker/hp with the
+ * shared dac pointed by the paths
+ */
+static void refill_shared_dacs(struct hda_codec *codec, int num_outs,
+                              hda_nid_t *dacs, int *path_idx)
+{
+       struct nid_path *path;
+       int i;
+
+       for (i = 0; i < num_outs; i++) {
+               if (dacs[i])
+                       continue;
+               path = snd_hda_get_path_from_idx(codec, path_idx[i]);
+               if (!path)
+                       continue;
+               dacs[i] = path->path[0];
+       }
+}
+
+/* fill in the dac_nids table from the parsed pin configuration */
+static int fill_and_eval_dacs(struct hda_codec *codec,
+                             bool fill_hardwired,
+                             bool fill_mio_first)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i, err, badness;
+
+       /* set num_dacs once to full for look_for_dac() */
+       spec->multiout.num_dacs = cfg->line_outs;
+       spec->multiout.dac_nids = spec->private_dac_nids;
+       memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
+       memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
+       memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
+       spec->multi_ios = 0;
+       snd_array_free(&spec->paths);
+
+       /* clear path indices */
+       memset(spec->out_paths, 0, sizeof(spec->out_paths));
+       memset(spec->hp_paths, 0, sizeof(spec->hp_paths));
+       memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths));
+       memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths));
+       memset(spec->digout_paths, 0, sizeof(spec->digout_paths));
+       memset(spec->input_paths, 0, sizeof(spec->input_paths));
+       memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths));
+       memset(&spec->digin_path, 0, sizeof(spec->digin_path));
+
+       badness = 0;
+
+       /* fill hard-wired DACs first */
+       if (fill_hardwired) {
+               bool mapped;
+               do {
+                       mapped = map_singles(codec, cfg->line_outs,
+                                            cfg->line_out_pins,
+                                            spec->private_dac_nids,
+                                            spec->out_paths);
+                       mapped |= map_singles(codec, cfg->hp_outs,
+                                             cfg->hp_pins,
+                                             spec->multiout.hp_out_nid,
+                                             spec->hp_paths);
+                       mapped |= map_singles(codec, cfg->speaker_outs,
+                                             cfg->speaker_pins,
+                                             spec->multiout.extra_out_nid,
+                                             spec->speaker_paths);
+                       if (!spec->no_multi_io &&
+                           fill_mio_first && cfg->line_outs == 1 &&
+                           cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+                               err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
+                               if (!err)
+                                       mapped = true;
+                       }
+               } while (mapped);
+       }
+
+       badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
+                                  spec->private_dac_nids, spec->out_paths,
+                                  spec->main_out_badness);
+
+       if (!spec->no_multi_io && fill_mio_first &&
+           cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               /* try to fill multi-io first */
+               err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
+               if (err < 0)
+                       return err;
+               /* we don't count badness at this stage yet */
+       }
+
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+               err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
+                                     spec->multiout.hp_out_nid,
+                                     spec->hp_paths,
+                                     spec->extra_out_badness);
+               if (err < 0)
+                       return err;
+               badness += err;
+       }
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               err = try_assign_dacs(codec, cfg->speaker_outs,
+                                     cfg->speaker_pins,
+                                     spec->multiout.extra_out_nid,
+                                     spec->speaker_paths,
+                                     spec->extra_out_badness);
+               if (err < 0)
+                       return err;
+               badness += err;
+       }
+       if (!spec->no_multi_io &&
+           cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
+               if (err < 0)
+                       return err;
+               badness += err;
+       }
+
+       if (spec->mixer_nid) {
+               spec->aamix_out_paths[0] =
+                       check_aamix_out_path(codec, spec->out_paths[0]);
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+                       spec->aamix_out_paths[1] =
+                               check_aamix_out_path(codec, spec->hp_paths[0]);
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+                       spec->aamix_out_paths[2] =
+                               check_aamix_out_path(codec, spec->speaker_paths[0]);
+       }
+
+       if (!spec->no_multi_io &&
+           cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
+               if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
+                       spec->multi_ios = 1; /* give badness */
+
+       /* re-count num_dacs and squash invalid entries */
+       spec->multiout.num_dacs = 0;
+       for (i = 0; i < cfg->line_outs; i++) {
+               if (spec->private_dac_nids[i])
+                       spec->multiout.num_dacs++;
+               else {
+                       memmove(spec->private_dac_nids + i,
+                               spec->private_dac_nids + i + 1,
+                               sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
+                       spec->private_dac_nids[cfg->line_outs - 1] = 0;
+               }
+       }
+
+       spec->ext_channel_count = spec->min_channel_count =
+               spec->multiout.num_dacs * 2;
+
+       if (spec->multi_ios == 2) {
+               for (i = 0; i < 2; i++)
+                       spec->private_dac_nids[spec->multiout.num_dacs++] =
+                               spec->multi_io[i].dac;
+       } else if (spec->multi_ios) {
+               spec->multi_ios = 0;
+               badness += BAD_MULTI_IO;
+       }
+
+       if (spec->indep_hp && !indep_hp_possible(codec))
+               badness += BAD_NO_INDEP_HP;
+
+       /* re-fill the shared DAC for speaker / headphone */
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+               refill_shared_dacs(codec, cfg->hp_outs,
+                                  spec->multiout.hp_out_nid,
+                                  spec->hp_paths);
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+               refill_shared_dacs(codec, cfg->speaker_outs,
+                                  spec->multiout.extra_out_nid,
+                                  spec->speaker_paths);
+
+       return badness;
+}
+
+#define DEBUG_BADNESS
+
+#ifdef DEBUG_BADNESS
+#define debug_badness(fmt, ...)                                                \
+       codec_dbg(codec, fmt, ##__VA_ARGS__)
+#else
+#define debug_badness(fmt, ...)                                                \
+       do { if (0) codec_dbg(codec, fmt, ##__VA_ARGS__); } while (0)
+#endif
+
+#ifdef DEBUG_BADNESS
+static inline void print_nid_path_idx(struct hda_codec *codec,
+                                     const char *pfx, int idx)
+{
+       struct nid_path *path;
+
+       path = snd_hda_get_path_from_idx(codec, idx);
+       if (path)
+               print_nid_path(codec, pfx, path);
+}
+
+static void debug_show_configs(struct hda_codec *codec,
+                              struct auto_pin_cfg *cfg)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       static const char * const lo_type[3] = { "LO", "SP", "HP" };
+       int i;
+
+       debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n",
+                     cfg->line_out_pins[0], cfg->line_out_pins[1],
+                     cfg->line_out_pins[2], cfg->line_out_pins[3],
+                     spec->multiout.dac_nids[0],
+                     spec->multiout.dac_nids[1],
+                     spec->multiout.dac_nids[2],
+                     spec->multiout.dac_nids[3],
+                     lo_type[cfg->line_out_type]);
+       for (i = 0; i < cfg->line_outs; i++)
+               print_nid_path_idx(codec, "  out", spec->out_paths[i]);
+       if (spec->multi_ios > 0)
+               debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
+                             spec->multi_ios,
+                             spec->multi_io[0].pin, spec->multi_io[1].pin,
+                             spec->multi_io[0].dac, spec->multi_io[1].dac);
+       for (i = 0; i < spec->multi_ios; i++)
+               print_nid_path_idx(codec, "  mio",
+                                  spec->out_paths[cfg->line_outs + i]);
+       if (cfg->hp_outs)
+               debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+                     cfg->hp_pins[0], cfg->hp_pins[1],
+                     cfg->hp_pins[2], cfg->hp_pins[3],
+                     spec->multiout.hp_out_nid[0],
+                     spec->multiout.hp_out_nid[1],
+                     spec->multiout.hp_out_nid[2],
+                     spec->multiout.hp_out_nid[3]);
+       for (i = 0; i < cfg->hp_outs; i++)
+               print_nid_path_idx(codec, "  hp ", spec->hp_paths[i]);
+       if (cfg->speaker_outs)
+               debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
+                     cfg->speaker_pins[0], cfg->speaker_pins[1],
+                     cfg->speaker_pins[2], cfg->speaker_pins[3],
+                     spec->multiout.extra_out_nid[0],
+                     spec->multiout.extra_out_nid[1],
+                     spec->multiout.extra_out_nid[2],
+                     spec->multiout.extra_out_nid[3]);
+       for (i = 0; i < cfg->speaker_outs; i++)
+               print_nid_path_idx(codec, "  spk", spec->speaker_paths[i]);
+       for (i = 0; i < 3; i++)
+               print_nid_path_idx(codec, "  mix", spec->aamix_out_paths[i]);
+}
+#else
+#define debug_show_configs(codec, cfg) /* NOP */
+#endif
+
+/* find all available DACs of the codec */
+static void fill_all_dac_nids(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t nid;
+
+       spec->num_all_dacs = 0;
+       memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
+       for_each_hda_codec_node(nid, codec) {
+               if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
+                       continue;
+               if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
+                       codec_err(codec, "Too many DACs!\n");
+                       break;
+               }
+               spec->all_dacs[spec->num_all_dacs++] = nid;
+       }
+}
+
+static int parse_output_paths(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct auto_pin_cfg *best_cfg;
+       unsigned int val;
+       int best_badness = INT_MAX;
+       int badness;
+       bool fill_hardwired = true, fill_mio_first = true;
+       bool best_wired = true, best_mio = true;
+       bool hp_spk_swapped = false;
+
+       best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
+       if (!best_cfg)
+               return -ENOMEM;
+       *best_cfg = *cfg;
+
+       for (;;) {
+               badness = fill_and_eval_dacs(codec, fill_hardwired,
+                                            fill_mio_first);
+               if (badness < 0) {
+                       kfree(best_cfg);
+                       return badness;
+               }
+               debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
+                             cfg->line_out_type, fill_hardwired, fill_mio_first,
+                             badness);
+               debug_show_configs(codec, cfg);
+               if (badness < best_badness) {
+                       best_badness = badness;
+                       *best_cfg = *cfg;
+                       best_wired = fill_hardwired;
+                       best_mio = fill_mio_first;
+               }
+               if (!badness)
+                       break;
+               fill_mio_first = !fill_mio_first;
+               if (!fill_mio_first)
+                       continue;
+               fill_hardwired = !fill_hardwired;
+               if (!fill_hardwired)
+                       continue;
+               if (hp_spk_swapped)
+                       break;
+               hp_spk_swapped = true;
+               if (cfg->speaker_outs > 0 &&
+                   cfg->line_out_type == AUTO_PIN_HP_OUT) {
+                       cfg->hp_outs = cfg->line_outs;
+                       memcpy(cfg->hp_pins, cfg->line_out_pins,
+                              sizeof(cfg->hp_pins));
+                       cfg->line_outs = cfg->speaker_outs;
+                       memcpy(cfg->line_out_pins, cfg->speaker_pins,
+                              sizeof(cfg->speaker_pins));
+                       cfg->speaker_outs = 0;
+                       memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
+                       cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
+                       fill_hardwired = true;
+                       continue;
+               }
+               if (cfg->hp_outs > 0 &&
+                   cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+                       cfg->speaker_outs = cfg->line_outs;
+                       memcpy(cfg->speaker_pins, cfg->line_out_pins,
+                              sizeof(cfg->speaker_pins));
+                       cfg->line_outs = cfg->hp_outs;
+                       memcpy(cfg->line_out_pins, cfg->hp_pins,
+                              sizeof(cfg->hp_pins));
+                       cfg->hp_outs = 0;
+                       memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+                       cfg->line_out_type = AUTO_PIN_HP_OUT;
+                       fill_hardwired = true;
+                       continue;
+               }
+               break;
+       }
+
+       if (badness) {
+               debug_badness("==> restoring best_cfg\n");
+               *cfg = *best_cfg;
+               fill_and_eval_dacs(codec, best_wired, best_mio);
+       }
+       debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
+                     cfg->line_out_type, best_wired, best_mio);
+       debug_show_configs(codec, cfg);
+
+       if (cfg->line_out_pins[0]) {
+               struct nid_path *path;
+               path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
+               if (path)
+                       spec->vmaster_nid = look_for_out_vol_nid(codec, path);
+               if (spec->vmaster_nid) {
+                       snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
+                                               HDA_OUTPUT, spec->vmaster_tlv);
+                       if (spec->dac_min_mute)
+                               spec->vmaster_tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] |= TLV_DB_SCALE_MUTE;
+               }
+       }
+
+       /* set initial pinctl targets */
+       if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT)
+               val = PIN_HP;
+       else
+               val = PIN_OUT;
+       set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val);
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+               set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT;
+               set_pin_targets(codec, cfg->speaker_outs,
+                               cfg->speaker_pins, val);
+       }
+
+       /* clear indep_hp flag if not available */
+       if (spec->indep_hp && !indep_hp_possible(codec))
+               spec->indep_hp = 0;
+
+       kfree(best_cfg);
+       return 0;
+}
+
+/* add playback controls from the parsed DAC table */
+static int create_multi_out_ctls(struct hda_codec *codec,
+                                const struct auto_pin_cfg *cfg)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i, err, noutputs;
+
+       noutputs = cfg->line_outs;
+       if (spec->multi_ios > 0 && cfg->line_outs < 3)
+               noutputs += spec->multi_ios;
+
+       for (i = 0; i < noutputs; i++) {
+               const char *name;
+               int index;
+               struct nid_path *path;
+
+               path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
+               if (!path)
+                       continue;
+
+               name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL);
+               if (!name || !strcmp(name, "CLFE")) {
+                       /* Center/LFE */
+                       err = add_vol_ctl(codec, "Center", 0, 1, path);
+                       if (err < 0)
+                               return err;
+                       err = add_vol_ctl(codec, "LFE", 0, 2, path);
+                       if (err < 0)
+                               return err;
+               } else {
+                       err = add_stereo_vol(codec, name, index, path);
+                       if (err < 0)
+                               return err;
+               }
+
+               name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL);
+               if (!name || !strcmp(name, "CLFE")) {
+                       err = add_sw_ctl(codec, "Center", 0, 1, path);
+                       if (err < 0)
+                               return err;
+                       err = add_sw_ctl(codec, "LFE", 0, 2, path);
+                       if (err < 0)
+                               return err;
+               } else {
+                       err = add_stereo_sw(codec, name, index, path);
+                       if (err < 0)
+                               return err;
+               }
+       }
+       return 0;
+}
+
+static int create_extra_out(struct hda_codec *codec, int path_idx,
+                           const char *pfx, int cidx)
+{
+       struct nid_path *path;
+       int err;
+
+       path = snd_hda_get_path_from_idx(codec, path_idx);
+       if (!path)
+               return 0;
+       err = add_stereo_vol(codec, pfx, cidx, path);
+       if (err < 0)
+               return err;
+       err = add_stereo_sw(codec, pfx, cidx, path);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+/* add playback controls for speaker and HP outputs */
+static int create_extra_outs(struct hda_codec *codec, int num_pins,
+                            const int *paths, const char *pfx)
+{
+       int i;
+
+       for (i = 0; i < num_pins; i++) {
+               const char *name;
+               char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+               int err, idx = 0;
+
+               if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
+                       name = "Bass Speaker";
+               else if (num_pins >= 3) {
+                       snprintf(tmp, sizeof(tmp), "%s %s",
+                                pfx, channel_name[i]);
+                       name = tmp;
+               } else {
+                       name = pfx;
+                       idx = i;
+               }
+               err = create_extra_out(codec, paths[i], name, idx);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+static int create_hp_out_ctls(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       return create_extra_outs(codec, spec->autocfg.hp_outs,
+                                spec->hp_paths,
+                                "Headphone");
+}
+
+static int create_speaker_out_ctls(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       return create_extra_outs(codec, spec->autocfg.speaker_outs,
+                                spec->speaker_paths,
+                                "Speaker");
+}
+
+/*
+ * independent HP controls
+ */
+
+static void call_hp_automute(struct hda_codec *codec,
+                            struct hda_jack_callback *jack);
+static int indep_hp_info(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_info *uinfo)
+{
+       return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
+}
+
+static int indep_hp_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled;
+       return 0;
+}
+
+static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
+                              int nomix_path_idx, int mix_path_idx,
+                              int out_type);
+
+static int indep_hp_put(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       unsigned int select = ucontrol->value.enumerated.item[0];
+       int ret = 0;
+
+       mutex_lock(&spec->pcm_mutex);
+       if (spec->active_streams) {
+               ret = -EBUSY;
+               goto unlock;
+       }
+
+       if (spec->indep_hp_enabled != select) {
+               hda_nid_t *dacp;
+               if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+                       dacp = &spec->private_dac_nids[0];
+               else
+                       dacp = &spec->multiout.hp_out_nid[0];
+
+               /* update HP aamix paths in case it conflicts with indep HP */
+               if (spec->have_aamix_ctl) {
+                       if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+                               update_aamix_paths(codec, spec->aamix_mode,
+                                                  spec->out_paths[0],
+                                                  spec->aamix_out_paths[0],
+                                                  spec->autocfg.line_out_type);
+                       else
+                               update_aamix_paths(codec, spec->aamix_mode,
+                                                  spec->hp_paths[0],
+                                                  spec->aamix_out_paths[1],
+                                                  AUTO_PIN_HP_OUT);
+               }
+
+               spec->indep_hp_enabled = select;
+               if (spec->indep_hp_enabled)
+                       *dacp = 0;
+               else
+                       *dacp = spec->alt_dac_nid;
+
+               call_hp_automute(codec, NULL);
+               ret = 1;
+       }
+ unlock:
+       mutex_unlock(&spec->pcm_mutex);
+       return ret;
+}
+
+static const struct snd_kcontrol_new indep_hp_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Independent HP",
+       .info = indep_hp_info,
+       .get = indep_hp_get,
+       .put = indep_hp_put,
+};
+
+
+static int create_indep_hp_ctls(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t dac;
+
+       if (!spec->indep_hp)
+               return 0;
+       if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+               dac = spec->multiout.dac_nids[0];
+       else
+               dac = spec->multiout.hp_out_nid[0];
+       if (!dac) {
+               spec->indep_hp = 0;
+               return 0;
+       }
+
+       spec->indep_hp_enabled = false;
+       spec->alt_dac_nid = dac;
+       if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl))
+               return -ENOMEM;
+       return 0;
+}
+
+/*
+ * channel mode enum control
+ */
+
+static int ch_mode_info(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       int chs;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = spec->multi_ios + 1;
+       if (uinfo->value.enumerated.item > spec->multi_ios)
+               uinfo->value.enumerated.item = spec->multi_ios;
+       chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count;
+       sprintf(uinfo->value.enumerated.name, "%dch", chs);
+       return 0;
+}
+
+static int ch_mode_get(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] =
+               (spec->ext_channel_count - spec->min_channel_count) / 2;
+       return 0;
+}
+
+static inline struct nid_path *
+get_multiio_path(struct hda_codec *codec, int idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       return snd_hda_get_path_from_idx(codec,
+               spec->out_paths[spec->autocfg.line_outs + idx]);
+}
+
+static void update_automute_all(struct hda_codec *codec);
+
+/* Default value to be passed as aamix argument for snd_hda_activate_path();
+ * used for output paths
+ */
+static bool aamix_default(struct hda_gen_spec *spec)
+{
+       return !spec->have_aamix_ctl || spec->aamix_mode;
+}
+
+static int set_multi_io(struct hda_codec *codec, int idx, bool output)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t nid = spec->multi_io[idx].pin;
+       struct nid_path *path;
+
+       path = get_multiio_path(codec, idx);
+       if (!path)
+               return -EINVAL;
+
+       if (path->active == output)
+               return 0;
+
+       if (output) {
+               set_pin_target(codec, nid, PIN_OUT, true);
+               snd_hda_activate_path(codec, path, true, aamix_default(spec));
+               set_pin_eapd(codec, nid, true);
+       } else {
+               set_pin_eapd(codec, nid, false);
+               snd_hda_activate_path(codec, path, false, aamix_default(spec));
+               set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
+               path_power_down_sync(codec, path);
+       }
+
+       /* update jack retasking in case it modifies any of them */
+       update_automute_all(codec);
+
+       return 0;
+}
+
+static int ch_mode_put(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       int i, ch;
+
+       ch = ucontrol->value.enumerated.item[0];
+       if (ch < 0 || ch > spec->multi_ios)
+               return -EINVAL;
+       if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2)
+               return 0;
+       spec->ext_channel_count = ch * 2 + spec->min_channel_count;
+       for (i = 0; i < spec->multi_ios; i++)
+               set_multi_io(codec, i, i < ch);
+       spec->multiout.max_channels = max(spec->ext_channel_count,
+                                         spec->const_channel_count);
+       if (spec->need_dac_fix)
+               spec->multiout.num_dacs = spec->multiout.max_channels / 2;
+       return 1;
+}
+
+static const struct snd_kcontrol_new channel_mode_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Channel Mode",
+       .info = ch_mode_info,
+       .get = ch_mode_get,
+       .put = ch_mode_put,
+};
+
+static int create_multi_channel_mode(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (spec->multi_ios > 0) {
+               if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum))
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+/*
+ * aamix loopback enable/disable switch
+ */
+
+#define loopback_mixing_info   indep_hp_info
+
+static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       ucontrol->value.enumerated.item[0] = spec->aamix_mode;
+       return 0;
+}
+
+static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
+                              int nomix_path_idx, int mix_path_idx,
+                              int out_type)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *nomix_path, *mix_path;
+
+       nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
+       mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
+       if (!nomix_path || !mix_path)
+               return;
+
+       /* if HP aamix path is driven from a different DAC and the
+        * independent HP mode is ON, can't turn on aamix path
+        */
+       if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled &&
+           mix_path->path[0] != spec->alt_dac_nid)
+               do_mix = false;
+
+       if (do_mix) {
+               snd_hda_activate_path(codec, nomix_path, false, true);
+               snd_hda_activate_path(codec, mix_path, true, true);
+               path_power_down_sync(codec, nomix_path);
+       } else {
+               snd_hda_activate_path(codec, mix_path, false, false);
+               snd_hda_activate_path(codec, nomix_path, true, false);
+               path_power_down_sync(codec, mix_path);
+       }
+}
+
+/* re-initialize the output paths; only called from loopback_mixing_put() */
+static void update_output_paths(struct hda_codec *codec, int num_outs,
+                               const int *paths)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+       int i;
+
+       for (i = 0; i < num_outs; i++) {
+               path = snd_hda_get_path_from_idx(codec, paths[i]);
+               if (path)
+                       snd_hda_activate_path(codec, path, path->active,
+                                             spec->aamix_mode);
+       }
+}
+
+static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int val = ucontrol->value.enumerated.item[0];
+
+       if (val == spec->aamix_mode)
+               return 0;
+       spec->aamix_mode = val;
+       if (has_aamix_out_paths(spec)) {
+               update_aamix_paths(codec, val, spec->out_paths[0],
+                                  spec->aamix_out_paths[0],
+                                  cfg->line_out_type);
+               update_aamix_paths(codec, val, spec->hp_paths[0],
+                                  spec->aamix_out_paths[1],
+                                  AUTO_PIN_HP_OUT);
+               update_aamix_paths(codec, val, spec->speaker_paths[0],
+                                  spec->aamix_out_paths[2],
+                                  AUTO_PIN_SPEAKER_OUT);
+       } else {
+               update_output_paths(codec, cfg->line_outs, spec->out_paths);
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+                       update_output_paths(codec, cfg->hp_outs, spec->hp_paths);
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+                       update_output_paths(codec, cfg->speaker_outs,
+                                           spec->speaker_paths);
+       }
+       return 1;
+}
+
+static const struct snd_kcontrol_new loopback_mixing_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Loopback Mixing",
+       .info = loopback_mixing_info,
+       .get = loopback_mixing_get,
+       .put = loopback_mixing_put,
+};
+
+static int create_loopback_mixing_ctl(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (!spec->mixer_nid)
+               return 0;
+       if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
+               return -ENOMEM;
+       spec->have_aamix_ctl = 1;
+       return 0;
+}
+
+/*
+ * shared headphone/mic handling
+ */
+
+static void call_update_outputs(struct hda_codec *codec);
+
+/* for shared I/O, change the pin-control accordingly */
+static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       bool as_mic;
+       unsigned int val;
+       hda_nid_t pin;
+
+       pin = spec->hp_mic_pin;
+       as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx;
+
+       if (!force) {
+               val = snd_hda_codec_get_pin_target(codec, pin);
+               if (as_mic) {
+                       if (val & PIN_IN)
+                               return;
+               } else {
+                       if (val & PIN_OUT)
+                               return;
+               }
+       }
+
+       val = snd_hda_get_default_vref(codec, pin);
+       /* if the HP pin doesn't support VREF and the codec driver gives an
+        * alternative pin, set up the VREF on that pin instead
+        */
+       if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
+               const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
+               unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
+               if (vref_val != AC_PINCTL_VREF_HIZ)
+                       snd_hda_set_pin_ctl_cache(codec, vref_pin,
+                                                 PIN_IN | (as_mic ? vref_val : 0));
+       }
+
+       if (!spec->hp_mic_jack_modes) {
+               if (as_mic)
+                       val |= PIN_IN;
+               else
+                       val = PIN_HP;
+               set_pin_target(codec, pin, val, true);
+               call_hp_automute(codec, NULL);
+       }
+}
+
+/* create a shared input with the headphone out */
+static int create_hp_mic(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int defcfg;
+       hda_nid_t nid;
+
+       if (!spec->hp_mic) {
+               if (spec->suppress_hp_mic_detect)
+                       return 0;
+               /* automatic detection: only if no input or a single internal
+                * input pin is found, try to detect the shared hp/mic
+                */
+               if (cfg->num_inputs > 1)
+                       return 0;
+               else if (cfg->num_inputs == 1) {
+                       defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
+                       if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
+                               return 0;
+               }
+       }
+
+       spec->hp_mic = 0; /* clear once */
+       if (cfg->num_inputs >= AUTO_CFG_MAX_INS)
+               return 0;
+
+       nid = 0;
+       if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0)
+               nid = cfg->line_out_pins[0];
+       else if (cfg->hp_outs > 0)
+               nid = cfg->hp_pins[0];
+       if (!nid)
+               return 0;
+
+       if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
+               return 0; /* no input */
+
+       cfg->inputs[cfg->num_inputs].pin = nid;
+       cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC;
+       cfg->inputs[cfg->num_inputs].is_headphone_mic = 1;
+       cfg->num_inputs++;
+       spec->hp_mic = 1;
+       spec->hp_mic_pin = nid;
+       /* we can't handle auto-mic together with HP-mic */
+       spec->suppress_auto_mic = 1;
+       codec_dbg(codec, "Enable shared I/O jack on NID 0x%x\n", nid);
+       return 0;
+}
+
+/*
+ * output jack mode
+ */
+
+static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin);
+
+static const char * const out_jack_texts[] = {
+       "Line Out", "Headphone Out",
+};
+
+static int out_jack_mode_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts);
+}
+
+static int out_jack_mode_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP)
+               ucontrol->value.enumerated.item[0] = 1;
+       else
+               ucontrol->value.enumerated.item[0] = 0;
+       return 0;
+}
+
+static int out_jack_mode_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       unsigned int val;
+
+       val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT;
+       if (snd_hda_codec_get_pin_target(codec, nid) == val)
+               return 0;
+       snd_hda_set_pin_ctl_cache(codec, nid, val);
+       return 1;
+}
+
+static const struct snd_kcontrol_new out_jack_mode_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = out_jack_mode_info,
+       .get = out_jack_mode_get,
+       .put = out_jack_mode_put,
+};
+
+static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct snd_kcontrol_new *kctl;
+       int i;
+
+       snd_array_for_each(&spec->kctls, i, kctl) {
+               if (!strcmp(kctl->name, name) && kctl->index == idx)
+                       return true;
+       }
+       return false;
+}
+
+static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
+                              char *name, size_t name_len)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int idx = 0;
+
+       snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx);
+       strlcat(name, " Jack Mode", name_len);
+
+       for (; find_kctl_name(codec, name, idx); idx++)
+               ;
+}
+
+static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->add_jack_modes) {
+               unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
+               if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV))
+                       return 2;
+       }
+       return 1;
+}
+
+static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
+                                hda_nid_t *pins)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < num_pins; i++) {
+               hda_nid_t pin = pins[i];
+               if (pin == spec->hp_mic_pin)
+                       continue;
+               if (get_out_jack_num_items(codec, pin) > 1) {
+                       struct snd_kcontrol_new *knew;
+                       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+                       get_jack_mode_name(codec, pin, name, sizeof(name));
+                       knew = snd_hda_gen_add_kctl(spec, name,
+                                                   &out_jack_mode_enum);
+                       if (!knew)
+                               return -ENOMEM;
+                       knew->private_value = pin;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * input jack mode
+ */
+
+/* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */
+#define NUM_VREFS      6
+
+static const char * const vref_texts[NUM_VREFS] = {
+       "Line In", "Mic 50pc Bias", "Mic 0V Bias",
+       "", "Mic 80pc Bias", "Mic 100pc Bias"
+};
+
+static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int pincap;
+
+       pincap = snd_hda_query_pin_caps(codec, pin);
+       pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
+       /* filter out unusual vrefs */
+       pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100);
+       return pincap;
+}
+
+/* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */
+static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx)
+{
+       unsigned int i, n = 0;
+
+       for (i = 0; i < NUM_VREFS; i++) {
+               if (vref_caps & (1 << i)) {
+                       if (n == item_idx)
+                               return i;
+                       n++;
+               }
+       }
+       return 0;
+}
+
+/* convert back from the vref ctl index to the enum item index */
+static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx)
+{
+       unsigned int i, n = 0;
+
+       for (i = 0; i < NUM_VREFS; i++) {
+               if (i == idx)
+                       return n;
+               if (vref_caps & (1 << i))
+                       n++;
+       }
+       return 0;
+}
+
+static int in_jack_mode_info(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       unsigned int vref_caps = get_vref_caps(codec, nid);
+
+       snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps),
+                                vref_texts);
+       /* set the right text */
+       strcpy(uinfo->value.enumerated.name,
+              vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]);
+       return 0;
+}
+
+static int in_jack_mode_get(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       unsigned int vref_caps = get_vref_caps(codec, nid);
+       unsigned int idx;
+
+       idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN;
+       ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx);
+       return 0;
+}
+
+static int in_jack_mode_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       unsigned int vref_caps = get_vref_caps(codec, nid);
+       unsigned int val, idx;
+
+       val = snd_hda_codec_get_pin_target(codec, nid);
+       idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN);
+       if (idx == ucontrol->value.enumerated.item[0])
+               return 0;
+
+       val &= ~AC_PINCTL_VREFEN;
+       val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]);
+       snd_hda_set_pin_ctl_cache(codec, nid, val);
+       return 1;
+}
+
+static const struct snd_kcontrol_new in_jack_mode_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = in_jack_mode_info,
+       .get = in_jack_mode_get,
+       .put = in_jack_mode_put,
+};
+
+static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int nitems = 0;
+       if (spec->add_jack_modes)
+               nitems = hweight32(get_vref_caps(codec, pin));
+       return nitems ? nitems : 1;
+}
+
+static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct snd_kcontrol_new *knew;
+       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       unsigned int defcfg;
+
+       if (pin == spec->hp_mic_pin)
+               return 0; /* already done in create_out_jack_mode() */
+
+       /* no jack mode for fixed pins */
+       defcfg = snd_hda_codec_get_pincfg(codec, pin);
+       if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
+               return 0;
+
+       /* no multiple vref caps? */
+       if (get_in_jack_num_items(codec, pin) <= 1)
+               return 0;
+
+       get_jack_mode_name(codec, pin, name, sizeof(name));
+       knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum);
+       if (!knew)
+               return -ENOMEM;
+       knew->private_value = pin;
+       return 0;
+}
+
+/*
+ * HP/mic shared jack mode
+ */
+static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       int out_jacks = get_out_jack_num_items(codec, nid);
+       int in_jacks = get_in_jack_num_items(codec, nid);
+       const char *text = NULL;
+       int idx;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = out_jacks + in_jacks;
+       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
+               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+       idx = uinfo->value.enumerated.item;
+       if (idx < out_jacks) {
+               if (out_jacks > 1)
+                       text = out_jack_texts[idx];
+               else
+                       text = "Headphone Out";
+       } else {
+               idx -= out_jacks;
+               if (in_jacks > 1) {
+                       unsigned int vref_caps = get_vref_caps(codec, nid);
+                       text = vref_texts[get_vref_idx(vref_caps, idx)];
+               } else
+                       text = "Mic In";
+       }
+
+       strcpy(uinfo->value.enumerated.name, text);
+       return 0;
+}
+
+static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid)
+{
+       int out_jacks = get_out_jack_num_items(codec, nid);
+       int in_jacks = get_in_jack_num_items(codec, nid);
+       unsigned int val = snd_hda_codec_get_pin_target(codec, nid);
+       int idx = 0;
+
+       if (val & PIN_OUT) {
+               if (out_jacks > 1 && val == PIN_HP)
+                       idx = 1;
+       } else if (val & PIN_IN) {
+               idx = out_jacks;
+               if (in_jacks > 1) {
+                       unsigned int vref_caps = get_vref_caps(codec, nid);
+                       val &= AC_PINCTL_VREFEN;
+                       idx += cvt_from_vref_idx(vref_caps, val);
+               }
+       }
+       return idx;
+}
+
+static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       ucontrol->value.enumerated.item[0] =
+               get_cur_hp_mic_jack_mode(codec, nid);
+       return 0;
+}
+
+static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       hda_nid_t nid = kcontrol->private_value;
+       int out_jacks = get_out_jack_num_items(codec, nid);
+       int in_jacks = get_in_jack_num_items(codec, nid);
+       unsigned int val, oldval, idx;
+
+       oldval = get_cur_hp_mic_jack_mode(codec, nid);
+       idx = ucontrol->value.enumerated.item[0];
+       if (oldval == idx)
+               return 0;
+
+       if (idx < out_jacks) {
+               if (out_jacks > 1)
+                       val = idx ? PIN_HP : PIN_OUT;
+               else
+                       val = PIN_HP;
+       } else {
+               idx -= out_jacks;
+               if (in_jacks > 1) {
+                       unsigned int vref_caps = get_vref_caps(codec, nid);
+                       val = snd_hda_codec_get_pin_target(codec, nid);
+                       val &= ~(AC_PINCTL_VREFEN | PIN_HP);
+                       val |= get_vref_idx(vref_caps, idx) | PIN_IN;
+               } else
+                       val = snd_hda_get_default_vref(codec, nid) | PIN_IN;
+       }
+       snd_hda_set_pin_ctl_cache(codec, nid, val);
+       call_hp_automute(codec, NULL);
+
+       return 1;
+}
+
+static const struct snd_kcontrol_new hp_mic_jack_mode_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = hp_mic_jack_mode_info,
+       .get = hp_mic_jack_mode_get,
+       .put = hp_mic_jack_mode_put,
+};
+
+static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct snd_kcontrol_new *knew;
+
+       knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
+                                   &hp_mic_jack_mode_enum);
+       if (!knew)
+               return -ENOMEM;
+       knew->private_value = pin;
+       spec->hp_mic_jack_modes = 1;
+       return 0;
+}
+
+/*
+ * Parse input paths
+ */
+
+/* add the powersave loopback-list entry */
+static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
+{
+       struct hda_amp_list *list;
+
+       list = snd_array_new(&spec->loopback_list);
+       if (!list)
+               return -ENOMEM;
+       list->nid = mix;
+       list->dir = HDA_INPUT;
+       list->idx = idx;
+       spec->loopback.amplist = spec->loopback_list.list;
+       return 0;
+}
+
+/* return true if either a volume or a mute amp is found for the given
+ * aamix path; the amp has to be either in the mixer node or its direct leaf
+ */
+static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid,
+                                  hda_nid_t pin, unsigned int *mix_val,
+                                  unsigned int *mute_val)
+{
+       int idx, num_conns;
+       const hda_nid_t *list;
+       hda_nid_t nid;
+
+       idx = snd_hda_get_conn_index(codec, mix_nid, pin, true);
+       if (idx < 0)
+               return false;
+
+       *mix_val = *mute_val = 0;
+       if (nid_has_volume(codec, mix_nid, HDA_INPUT))
+               *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
+       if (nid_has_mute(codec, mix_nid, HDA_INPUT))
+               *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
+       if (*mix_val && *mute_val)
+               return true;
+
+       /* check leaf node */
+       num_conns = snd_hda_get_conn_list(codec, mix_nid, &list);
+       if (num_conns < idx)
+               return false;
+       nid = list[idx];
+       if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) &&
+           !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL))
+               *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+       if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) &&
+           !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL))
+               *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+
+       return *mix_val || *mute_val;
+}
+
+/* create input playback/capture controls for the given pin */
+static int new_analog_input(struct hda_codec *codec, int input_idx,
+                           hda_nid_t pin, const char *ctlname, int ctlidx,
+                           hda_nid_t mix_nid)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+       unsigned int mix_val, mute_val;
+       int err, idx;
+
+       if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val))
+               return 0;
+
+       path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
+       if (!path)
+               return -EINVAL;
+       print_nid_path(codec, "loopback", path);
+       spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
+
+       idx = path->idx[path->depth - 1];
+       if (mix_val) {
+               err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val);
+               if (err < 0)
+                       return err;
+               path->ctls[NID_PATH_VOL_CTL] = mix_val;
+       }
+
+       if (mute_val) {
+               err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val);
+               if (err < 0)
+                       return err;
+               path->ctls[NID_PATH_MUTE_CTL] = mute_val;
+       }
+
+       path->active = true;
+       path->stream_enabled = true; /* no DAC/ADC involved */
+       err = add_loopback_list(spec, mix_nid, idx);
+       if (err < 0)
+               return err;
+
+       if (spec->mixer_nid != spec->mixer_merge_nid &&
+           !spec->loopback_merge_path) {
+               path = snd_hda_add_new_path(codec, spec->mixer_nid,
+                                           spec->mixer_merge_nid, 0);
+               if (path) {
+                       print_nid_path(codec, "loopback-merge", path);
+                       path->active = true;
+                       path->pin_fixed = true; /* static route */
+                       path->stream_enabled = true; /* no DAC/ADC involved */
+                       spec->loopback_merge_path =
+                               snd_hda_get_path_idx(codec, path);
+               }
+       }
+
+       return 0;
+}
+
+static int is_input_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
+       return (pincap & AC_PINCAP_IN) != 0;
+}
+
+/* Parse the codec tree and retrieve ADCs */
+static int fill_adc_nids(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t nid;
+       hda_nid_t *adc_nids = spec->adc_nids;
+       int max_nums = ARRAY_SIZE(spec->adc_nids);
+       int nums = 0;
+
+       for_each_hda_codec_node(nid, codec) {
+               unsigned int caps = get_wcaps(codec, nid);
+               int type = get_wcaps_type(caps);
+
+               if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
+                       continue;
+               adc_nids[nums] = nid;
+               if (++nums >= max_nums)
+                       break;
+       }
+       spec->num_adc_nids = nums;
+
+       /* copy the detected ADCs to all_adcs[] */
+       spec->num_all_adcs = nums;
+       memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t));
+
+       return nums;
+}
+
+/* filter out invalid adc_nids that don't give all active input pins;
+ * if needed, check whether dynamic ADC-switching is available
+ */
+static int check_dyn_adc_switch(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->input_mux;
+       unsigned int ok_bits;
+       int i, n, nums;
+
+       nums = 0;
+       ok_bits = 0;
+       for (n = 0; n < spec->num_adc_nids; n++) {
+               for (i = 0; i < imux->num_items; i++) {
+                       if (!spec->input_paths[i][n])
+                               break;
+               }
+               if (i >= imux->num_items) {
+                       ok_bits |= (1 << n);
+                       nums++;
+               }
+       }
+
+       if (!ok_bits) {
+               /* check whether ADC-switch is possible */
+               for (i = 0; i < imux->num_items; i++) {
+                       for (n = 0; n < spec->num_adc_nids; n++) {
+                               if (spec->input_paths[i][n]) {
+                                       spec->dyn_adc_idx[i] = n;
+                                       break;
+                               }
+                       }
+               }
+
+               codec_dbg(codec, "enabling ADC switching\n");
+               spec->dyn_adc_switch = 1;
+       } else if (nums != spec->num_adc_nids) {
+               /* shrink the invalid adcs and input paths */
+               nums = 0;
+               for (n = 0; n < spec->num_adc_nids; n++) {
+                       if (!(ok_bits & (1 << n)))
+                               continue;
+                       if (n != nums) {
+                               spec->adc_nids[nums] = spec->adc_nids[n];
+                               for (i = 0; i < imux->num_items; i++) {
+                                       invalidate_nid_path(codec,
+                                               spec->input_paths[i][nums]);
+                                       spec->input_paths[i][nums] =
+                                               spec->input_paths[i][n];
+                                       spec->input_paths[i][n] = 0;
+                               }
+                       }
+                       nums++;
+               }
+               spec->num_adc_nids = nums;
+       }
+
+       if (imux->num_items == 1 ||
+           (imux->num_items == 2 && spec->hp_mic)) {
+               codec_dbg(codec, "reducing to a single ADC\n");
+               spec->num_adc_nids = 1; /* reduce to a single ADC */
+       }
+
+       /* single index for individual volumes ctls */
+       if (!spec->dyn_adc_switch && spec->multi_cap_vol)
+               spec->num_adc_nids = 1;
+
+       return 0;
+}
+
+/* parse capture source paths from the given pin and create imux items */
+static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
+                               int cfg_idx, int num_adcs,
+                               const char *label, int anchor)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->input_mux;
+       int imux_idx = imux->num_items;
+       bool imux_added = false;
+       int c;
+
+       for (c = 0; c < num_adcs; c++) {
+               struct nid_path *path;
+               hda_nid_t adc = spec->adc_nids[c];
+
+               if (!is_reachable_path(codec, pin, adc))
+                       continue;
+               path = snd_hda_add_new_path(codec, pin, adc, anchor);
+               if (!path)
+                       continue;
+               print_nid_path(codec, "input", path);
+               spec->input_paths[imux_idx][c] =
+                       snd_hda_get_path_idx(codec, path);
+
+               if (!imux_added) {
+                       if (spec->hp_mic_pin == pin)
+                               spec->hp_mic_mux_idx = imux->num_items;
+                       spec->imux_pins[imux->num_items] = pin;
+                       snd_hda_add_imux_item(codec, imux, label, cfg_idx, NULL);
+                       imux_added = true;
+                       if (spec->dyn_adc_switch)
+                               spec->dyn_adc_idx[imux_idx] = c;
+               }
+       }
+
+       return 0;
+}
+
+/*
+ * create playback/capture controls for input pins
+ */
+
+/* fill the label for each input at first */
+static int fill_input_pin_labels(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin = cfg->inputs[i].pin;
+               const char *label;
+               int j, idx;
+
+               if (!is_input_pin(codec, pin))
+                       continue;
+
+               label = hda_get_autocfg_input_label(codec, cfg, i);
+               idx = 0;
+               for (j = i - 1; j >= 0; j--) {
+                       if (spec->input_labels[j] &&
+                           !strcmp(spec->input_labels[j], label)) {
+                               idx = spec->input_label_idxs[j] + 1;
+                               break;
+                       }
+               }
+
+               spec->input_labels[i] = label;
+               spec->input_label_idxs[i] = idx;
+       }
+
+       return 0;
+}
+
+#define CFG_IDX_MIX    99      /* a dummy cfg->input idx for stereo mix */
+
+static int create_input_ctls(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t mixer = spec->mixer_nid;
+       int num_adcs;
+       int i, err;
+       unsigned int val;
+
+       num_adcs = fill_adc_nids(codec);
+       if (num_adcs < 0)
+               return 0;
+
+       err = fill_input_pin_labels(codec);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t pin;
+
+               pin = cfg->inputs[i].pin;
+               if (!is_input_pin(codec, pin))
+                       continue;
+
+               val = PIN_IN;
+               if (cfg->inputs[i].type == AUTO_PIN_MIC)
+                       val |= snd_hda_get_default_vref(codec, pin);
+               if (pin != spec->hp_mic_pin &&
+                   !snd_hda_codec_get_pin_target(codec, pin))
+                       set_pin_target(codec, pin, val, false);
+
+               if (mixer) {
+                       if (is_reachable_path(codec, pin, mixer)) {
+                               err = new_analog_input(codec, i, pin,
+                                                      spec->input_labels[i],
+                                                      spec->input_label_idxs[i],
+                                                      mixer);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+
+               err = parse_capture_source(codec, pin, i, num_adcs,
+                                          spec->input_labels[i], -mixer);
+               if (err < 0)
+                       return err;
+
+               if (spec->add_jack_modes) {
+                       err = create_in_jack_mode(codec, pin);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       /* add stereo mix when explicitly enabled via hint */
+       if (mixer && spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_ENABLE) {
+               err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
+                                          "Stereo Mix", 0);
+               if (err < 0)
+                       return err;
+               else
+                       spec->suppress_auto_mic = 1;
+       }
+
+       return 0;
+}
+
+
+/*
+ * input source mux
+ */
+
+/* get the input path specified by the given adc and imux indices */
+static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) {
+               snd_BUG();
+               return NULL;
+       }
+       if (spec->dyn_adc_switch)
+               adc_idx = spec->dyn_adc_idx[imux_idx];
+       if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) {
+               snd_BUG();
+               return NULL;
+       }
+       return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]);
+}
+
+static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
+                     unsigned int idx);
+
+static int mux_enum_info(struct snd_kcontrol *kcontrol,
+                        struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       return snd_hda_input_mux_info(&spec->input_mux, uinfo);
+}
+
+static int mux_enum_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       /* the ctls are created at once with multiple counts */
+       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+       ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
+       return 0;
+}
+
+static int mux_enum_put(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       return mux_select(codec, adc_idx,
+                         ucontrol->value.enumerated.item[0]);
+}
+
+static const struct snd_kcontrol_new cap_src_temp = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Input Source",
+       .info = mux_enum_info,
+       .get = mux_enum_get,
+       .put = mux_enum_put,
+};
+
+/*
+ * capture volume and capture switch ctls
+ */
+
+typedef int (*put_call_t)(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol);
+
+/* call the given amp update function for all amps in the imux list at once */
+static int cap_put_caller(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol,
+                         put_call_t func, int type)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       const struct hda_input_mux *imux;
+       struct nid_path *path;
+       int i, adc_idx, ret, err = 0;
+
+       imux = &spec->input_mux;
+       adc_idx = kcontrol->id.index;
+       mutex_lock(&codec->control_mutex);
+       for (i = 0; i < imux->num_items; i++) {
+               path = get_input_path(codec, adc_idx, i);
+               if (!path || !path->ctls[type])
+                       continue;
+               kcontrol->private_value = path->ctls[type];
+               ret = func(kcontrol, ucontrol);
+               if (ret < 0) {
+                       err = ret;
+                       break;
+               }
+               if (ret > 0)
+                       err = 1;
+       }
+       mutex_unlock(&codec->control_mutex);
+       if (err >= 0 && spec->cap_sync_hook)
+               spec->cap_sync_hook(codec, kcontrol, ucontrol);
+       return err;
+}
+
+/* capture volume ctl callbacks */
+#define cap_vol_info           snd_hda_mixer_amp_volume_info
+#define cap_vol_get            snd_hda_mixer_amp_volume_get
+#define cap_vol_tlv            snd_hda_mixer_amp_tlv
+
+static int cap_vol_put(struct snd_kcontrol *kcontrol,
+                      struct snd_ctl_elem_value *ucontrol)
+{
+       return cap_put_caller(kcontrol, ucontrol,
+                             snd_hda_mixer_amp_volume_put,
+                             NID_PATH_VOL_CTL);
+}
+
+static const struct snd_kcontrol_new cap_vol_temp = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Volume",
+       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_READ |
+                  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
+       .info = cap_vol_info,
+       .get = cap_vol_get,
+       .put = cap_vol_put,
+       .tlv = { .c = cap_vol_tlv },
+};
+
+/* capture switch ctl callbacks */
+#define cap_sw_info            snd_ctl_boolean_stereo_info
+#define cap_sw_get             snd_hda_mixer_amp_switch_get
+
+static int cap_sw_put(struct snd_kcontrol *kcontrol,
+                     struct snd_ctl_elem_value *ucontrol)
+{
+       return cap_put_caller(kcontrol, ucontrol,
+                             snd_hda_mixer_amp_switch_put,
+                             NID_PATH_MUTE_CTL);
+}
+
+static const struct snd_kcontrol_new cap_sw_temp = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Capture Switch",
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = cap_sw_info,
+       .get = cap_sw_get,
+       .put = cap_sw_put,
+};
+
+static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path)
+{
+       hda_nid_t nid;
+       int i, depth;
+
+       path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0;
+       for (depth = 0; depth < 3; depth++) {
+               if (depth >= path->depth)
+                       return -EINVAL;
+               i = path->depth - depth - 1;
+               nid = path->path[i];
+               if (!path->ctls[NID_PATH_VOL_CTL]) {
+                       if (nid_has_volume(codec, nid, HDA_OUTPUT))
+                               path->ctls[NID_PATH_VOL_CTL] =
+                                       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+                       else if (nid_has_volume(codec, nid, HDA_INPUT)) {
+                               int idx = path->idx[i];
+                               if (!depth && codec->single_adc_amp)
+                                       idx = 0;
+                               path->ctls[NID_PATH_VOL_CTL] =
+                                       HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
+                       }
+               }
+               if (!path->ctls[NID_PATH_MUTE_CTL]) {
+                       if (nid_has_mute(codec, nid, HDA_OUTPUT))
+                               path->ctls[NID_PATH_MUTE_CTL] =
+                                       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+                       else if (nid_has_mute(codec, nid, HDA_INPUT)) {
+                               int idx = path->idx[i];
+                               if (!depth && codec->single_adc_amp)
+                                       idx = 0;
+                               path->ctls[NID_PATH_MUTE_CTL] =
+                                       HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
+                       }
+               }
+       }
+       return 0;
+}
+
+static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int val;
+       int i;
+
+       if (!spec->inv_dmic_split)
+               return false;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].pin != nid)
+                       continue;
+               if (cfg->inputs[i].type != AUTO_PIN_MIC)
+                       return false;
+               val = snd_hda_codec_get_pincfg(codec, nid);
+               return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT;
+       }
+       return false;
+}
+
+/* capture switch put callback for a single control with hook call */
+static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       int ret;
+
+       ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       if (ret < 0)
+               return ret;
+
+       if (spec->cap_sync_hook)
+               spec->cap_sync_hook(codec, kcontrol, ucontrol);
+
+       return ret;
+}
+
+static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
+                             int idx, bool is_switch, unsigned int ctl,
+                             bool inv_dmic)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
+       const char *sfx = is_switch ? "Switch" : "Volume";
+       unsigned int chs = inv_dmic ? 1 : 3;
+       struct snd_kcontrol_new *knew;
+
+       if (!ctl)
+               return 0;
+
+       if (label)
+               snprintf(tmpname, sizeof(tmpname),
+                        "%s Capture %s", label, sfx);
+       else
+               snprintf(tmpname, sizeof(tmpname),
+                        "Capture %s", sfx);
+       knew = add_control(spec, type, tmpname, idx,
+                          amp_val_replace_channels(ctl, chs));
+       if (!knew)
+               return -ENOMEM;
+       if (is_switch) {
+               knew->put = cap_single_sw_put;
+               if (spec->mic_mute_led)
+                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
+       }
+       if (!inv_dmic)
+               return 0;
+
+       /* Make independent right kcontrol */
+       if (label)
+               snprintf(tmpname, sizeof(tmpname),
+                        "Inverted %s Capture %s", label, sfx);
+       else
+               snprintf(tmpname, sizeof(tmpname),
+                        "Inverted Capture %s", sfx);
+       knew = add_control(spec, type, tmpname, idx,
+                          amp_val_replace_channels(ctl, 2));
+       if (!knew)
+               return -ENOMEM;
+       if (is_switch) {
+               knew->put = cap_single_sw_put;
+               if (spec->mic_mute_led)
+                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
+       }
+       return 0;
+}
+
+/* create single (and simple) capture volume and switch controls */
+static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx,
+                                    unsigned int vol_ctl, unsigned int sw_ctl,
+                                    bool inv_dmic)
+{
+       int err;
+       err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic);
+       if (err < 0)
+               return err;
+       err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic);
+       if (err < 0)
+               return err;
+       return 0;
+}
+
+/* create bound capture volume and switch controls */
+static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
+                                  unsigned int vol_ctl, unsigned int sw_ctl)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct snd_kcontrol_new *knew;
+
+       if (vol_ctl) {
+               knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp);
+               if (!knew)
+                       return -ENOMEM;
+               knew->index = idx;
+               knew->private_value = vol_ctl;
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
+       }
+       if (sw_ctl) {
+               knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp);
+               if (!knew)
+                       return -ENOMEM;
+               knew->index = idx;
+               knew->private_value = sw_ctl;
+               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
+               if (spec->mic_mute_led)
+                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
+       }
+       return 0;
+}
+
+/* return the vol ctl when used first in the imux list */
+static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type)
+{
+       struct nid_path *path;
+       unsigned int ctl;
+       int i;
+
+       path = get_input_path(codec, 0, idx);
+       if (!path)
+               return 0;
+       ctl = path->ctls[type];
+       if (!ctl)
+               return 0;
+       for (i = 0; i < idx - 1; i++) {
+               path = get_input_path(codec, 0, i);
+               if (path && path->ctls[type] == ctl)
+                       return 0;
+       }
+       return ctl;
+}
+
+/* create individual capture volume and switch controls per input */
+static int create_multi_cap_vol_ctl(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->input_mux;
+       int i, err, type;
+
+       for (i = 0; i < imux->num_items; i++) {
+               bool inv_dmic;
+               int idx;
+
+               idx = imux->items[i].index;
+               if (idx >= spec->autocfg.num_inputs)
+                       continue;
+               inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]);
+
+               for (type = 0; type < 2; type++) {
+                       err = add_single_cap_ctl(codec,
+                                                spec->input_labels[idx],
+                                                spec->input_label_idxs[idx],
+                                                type,
+                                                get_first_cap_ctl(codec, i, type),
+                                                inv_dmic);
+                       if (err < 0)
+                               return err;
+               }
+       }
+       return 0;
+}
+
+static int create_capture_mixers(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->input_mux;
+       int i, n, nums, err;
+
+       if (spec->dyn_adc_switch)
+               nums = 1;
+       else
+               nums = spec->num_adc_nids;
+
+       if (!spec->auto_mic && imux->num_items > 1) {
+               struct snd_kcontrol_new *knew;
+               const char *name;
+               name = nums > 1 ? "Input Source" : "Capture Source";
+               knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp);
+               if (!knew)
+                       return -ENOMEM;
+               knew->count = nums;
+       }
+
+       for (n = 0; n < nums; n++) {
+               bool multi = false;
+               bool multi_cap_vol = spec->multi_cap_vol;
+               bool inv_dmic = false;
+               int vol, sw;
+
+               vol = sw = 0;
+               for (i = 0; i < imux->num_items; i++) {
+                       struct nid_path *path;
+                       path = get_input_path(codec, n, i);
+                       if (!path)
+                               continue;
+                       parse_capvol_in_path(codec, path);
+                       if (!vol)
+                               vol = path->ctls[NID_PATH_VOL_CTL];
+                       else if (vol != path->ctls[NID_PATH_VOL_CTL]) {
+                               multi = true;
+                               if (!same_amp_caps(codec, vol,
+                                   path->ctls[NID_PATH_VOL_CTL], HDA_INPUT))
+                                       multi_cap_vol = true;
+                       }
+                       if (!sw)
+                               sw = path->ctls[NID_PATH_MUTE_CTL];
+                       else if (sw != path->ctls[NID_PATH_MUTE_CTL]) {
+                               multi = true;
+                               if (!same_amp_caps(codec, sw,
+                                   path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT))
+                                       multi_cap_vol = true;
+                       }
+                       if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
+                               inv_dmic = true;
+               }
+
+               if (!multi)
+                       err = create_single_cap_vol_ctl(codec, n, vol, sw,
+                                                       inv_dmic);
+               else if (!multi_cap_vol && !inv_dmic)
+                       err = create_bind_cap_vol_ctl(codec, n, vol, sw);
+               else
+                       err = create_multi_cap_vol_ctl(codec);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+/*
+ * add mic boosts if needed
+ */
+
+/* check whether the given amp is feasible as a boost volume */
+static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid,
+                           int dir, int idx)
+{
+       unsigned int step;
+
+       if (!nid_has_volume(codec, nid, dir) ||
+           is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
+           is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
+               return false;
+
+       step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE)
+               >> AC_AMPCAP_STEP_SIZE_SHIFT;
+       if (step < 0x20)
+               return false;
+       return true;
+}
+
+/* look for a boost amp in a widget close to the pin */
+static unsigned int look_for_boost_amp(struct hda_codec *codec,
+                                      struct nid_path *path)
+{
+       unsigned int val = 0;
+       hda_nid_t nid;
+       int depth;
+
+       for (depth = 0; depth < 3; depth++) {
+               if (depth >= path->depth - 1)
+                       break;
+               nid = path->path[depth];
+               if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) {
+                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
+                       break;
+               } else if (check_boost_vol(codec, nid, HDA_INPUT,
+                                          path->idx[depth])) {
+                       val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth],
+                                                 HDA_INPUT);
+                       break;
+               }
+       }
+
+       return val;
+}
+
+static int parse_mic_boost(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       struct hda_input_mux *imux = &spec->input_mux;
+       int i;
+
+       if (!spec->num_adc_nids)
+               return 0;
+
+       for (i = 0; i < imux->num_items; i++) {
+               struct nid_path *path;
+               unsigned int val;
+               int idx;
+               char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+
+               idx = imux->items[i].index;
+               if (idx >= imux->num_items)
+                       continue;
+
+               /* check only line-in and mic pins */
+               if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
+                       continue;
+
+               path = get_input_path(codec, 0, i);
+               if (!path)
+                       continue;
+
+               val = look_for_boost_amp(codec, path);
+               if (!val)
+                       continue;
+
+               /* create a boost control */
+               snprintf(boost_label, sizeof(boost_label),
+                        "%s Boost Volume", spec->input_labels[idx]);
+               if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label,
+                                spec->input_label_idxs[idx], val))
+                       return -ENOMEM;
+
+               path->ctls[NID_PATH_BOOST_CTL] = val;
+       }
+       return 0;
+}
+
+#ifdef CONFIG_SND_HDA_GENERIC_LEDS
+/*
+ * vmaster mute LED hook helpers
+ */
+
+static int create_mute_led_cdev(struct hda_codec *codec,
+                               int (*callback)(struct led_classdev *,
+                                               enum led_brightness),
+                               bool micmute)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct led_classdev *cdev;
+       int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
+       int err;
+
+       cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
+       if (!cdev)
+               return -ENOMEM;
+
+       cdev->name = micmute ? "hda::micmute" : "hda::mute";
+       cdev->max_brightness = 1;
+       cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
+       cdev->brightness_set_blocking = callback;
+       cdev->flags = LED_CORE_SUSPENDRESUME;
+
+       err = led_classdev_register(&codec->core.dev, cdev);
+       if (err < 0)
+               return err;
+       spec->led_cdevs[idx] = cdev;
+       return 0;
+}
+
+/**
+ * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
+ * @codec: the HDA codec
+ * @callback: the callback for LED classdev brightness_set_blocking
+ */
+int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
+                                 int (*callback)(struct led_classdev *,
+                                                 enum led_brightness))
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err;
+
+       if (callback) {
+               err = create_mute_led_cdev(codec, callback, false);
+               if (err) {
+                       codec_warn(codec, "failed to create a mute LED cdev\n");
+                       return err;
+               }
+       }
+
+       if (spec->vmaster_mute.hook)
+               codec_err(codec, "vmaster hook already present before cdev!\n");
+
+       spec->vmaster_mute_led = 1;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);
+
+/**
+ * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
+ * @codec: the HDA codec
+ * @callback: the callback for LED classdev brightness_set_blocking
+ *
+ * Called from the codec drivers for offering the mic mute LED controls.
+ * This creates a LED classdev and sets up the cap_sync_hook that is called at
+ * each time when the capture mixer switch changes.
+ *
+ * When NULL is passed to @callback, no classdev is created but only the
+ * LED-trigger is set up.
+ *
+ * Returns 0 or a negative error.
+ */
+int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
+                                    int (*callback)(struct led_classdev *,
+                                                    enum led_brightness))
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err;
+
+       if (callback) {
+               err = create_mute_led_cdev(codec, callback, true);
+               if (err) {
+                       codec_warn(codec, "failed to create a mic-mute LED cdev\n");
+                       return err;
+               }
+       }
+
+       spec->mic_mute_led = 1;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
+#endif /* CONFIG_SND_HDA_GENERIC_LEDS */
+
+/*
+ * parse digital I/Os and set up NIDs in BIOS auto-parse mode
+ */
+static void parse_digital(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+       int i, nums;
+       hda_nid_t dig_nid, pin;
+
+       /* support multiple SPDIFs; the secondary is set up as a follower */
+       nums = 0;
+       for (i = 0; i < spec->autocfg.dig_outs; i++) {
+               pin = spec->autocfg.dig_out_pins[i];
+               dig_nid = look_for_dac(codec, pin, true);
+               if (!dig_nid)
+                       continue;
+               path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
+               if (!path)
+                       continue;
+               print_nid_path(codec, "digout", path);
+               path->active = true;
+               path->pin_fixed = true; /* no jack detection */
+               spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
+               set_pin_target(codec, pin, PIN_OUT, false);
+               if (!nums) {
+                       spec->multiout.dig_out_nid = dig_nid;
+                       spec->dig_out_type = spec->autocfg.dig_out_type[0];
+               } else {
+                       spec->multiout.follower_dig_outs = spec->follower_dig_outs;
+                       if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1)
+                               break;
+                       spec->follower_dig_outs[nums - 1] = dig_nid;
+               }
+               nums++;
+       }
+
+       if (spec->autocfg.dig_in_pin) {
+               pin = spec->autocfg.dig_in_pin;
+               for_each_hda_codec_node(dig_nid, codec) {
+                       unsigned int wcaps = get_wcaps(codec, dig_nid);
+                       if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
+                               continue;
+                       if (!(wcaps & AC_WCAP_DIGITAL))
+                               continue;
+                       path = snd_hda_add_new_path(codec, pin, dig_nid, 0);
+                       if (path) {
+                               print_nid_path(codec, "digin", path);
+                               path->active = true;
+                               path->pin_fixed = true; /* no jack */
+                               spec->dig_in_nid = dig_nid;
+                               spec->digin_path = snd_hda_get_path_idx(codec, path);
+                               set_pin_target(codec, pin, PIN_IN, false);
+                               break;
+                       }
+               }
+       }
+}
+
+
+/*
+ * input MUX handling
+ */
+
+static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur);
+
+/* select the given imux item; either unmute exclusively or select the route */
+static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
+                     unsigned int idx)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct hda_input_mux *imux;
+       struct nid_path *old_path, *path;
+
+       imux = &spec->input_mux;
+       if (!imux->num_items)
+               return 0;
+
+       if (idx >= imux->num_items)
+               idx = imux->num_items - 1;
+       if (spec->cur_mux[adc_idx] == idx)
+               return 0;
+
+       old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]);
+       if (!old_path)
+               return 0;
+       if (old_path->active)
+               snd_hda_activate_path(codec, old_path, false, false);
+
+       spec->cur_mux[adc_idx] = idx;
+
+       if (spec->hp_mic)
+               update_hp_mic(codec, adc_idx, false);
+
+       if (spec->dyn_adc_switch)
+               dyn_adc_pcm_resetup(codec, idx);
+
+       path = get_input_path(codec, adc_idx, idx);
+       if (!path)
+               return 0;
+       if (path->active)
+               return 0;
+       snd_hda_activate_path(codec, path, true, false);
+       if (spec->cap_sync_hook)
+               spec->cap_sync_hook(codec, NULL, NULL);
+       path_power_down_sync(codec, old_path);
+       return 1;
+}
+
+/* power up/down widgets in the all paths that match with the given NID
+ * as terminals (either start- or endpoint)
+ *
+ * returns the last changed NID, or zero if unchanged.
+ */
+static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid,
+                               int pin_state, int stream_state)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t last, changed = 0;
+       struct nid_path *path;
+       int n;
+
+       snd_array_for_each(&spec->paths, n, path) {
+               if (!path->depth)
+                       continue;
+               if (path->path[0] == nid ||
+                   path->path[path->depth - 1] == nid) {
+                       bool pin_old = path->pin_enabled;
+                       bool stream_old = path->stream_enabled;
+
+                       if (pin_state >= 0)
+                               path->pin_enabled = pin_state;
+                       if (stream_state >= 0)
+                               path->stream_enabled = stream_state;
+                       if ((!path->pin_fixed && path->pin_enabled != pin_old)
+                           || path->stream_enabled != stream_old) {
+                               last = path_power_update(codec, path, true);
+                               if (last)
+                                       changed = last;
+                       }
+               }
+       }
+       return changed;
+}
+
+/* check the jack status for power control */
+static bool detect_pin_state(struct hda_codec *codec, hda_nid_t pin)
+{
+       if (!is_jack_detectable(codec, pin))
+               return true;
+       return snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT;
+}
+
+/* power up/down the paths of the given pin according to the jack state;
+ * power = 0/1 : only power up/down if it matches with the jack state,
+ *       < 0   : force power up/down to follow the jack sate
+ *
+ * returns the last changed NID, or zero if unchanged.
+ */
+static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin,
+                                   int power)
+{
+       bool on;
+
+       if (!codec->power_save_node)
+               return 0;
+
+       on = detect_pin_state(codec, pin);
+
+       if (power >= 0 && on != power)
+               return 0;
+       return set_path_power(codec, pin, on, -1);
+}
+
+static void pin_power_callback(struct hda_codec *codec,
+                              struct hda_jack_callback *jack,
+                              bool on)
+{
+       if (jack && jack->nid)
+               sync_power_state_change(codec,
+                                       set_pin_power_jack(codec, jack->nid, on));
+}
+
+/* callback only doing power up -- called at first */
+static void pin_power_up_callback(struct hda_codec *codec,
+                                 struct hda_jack_callback *jack)
+{
+       pin_power_callback(codec, jack, true);
+}
+
+/* callback only doing power down -- called at last */
+static void pin_power_down_callback(struct hda_codec *codec,
+                                   struct hda_jack_callback *jack)
+{
+       pin_power_callback(codec, jack, false);
+}
+
+/* set up the power up/down callbacks */
+static void add_pin_power_ctls(struct hda_codec *codec, int num_pins,
+                              const hda_nid_t *pins, bool on)
+{
+       int i;
+       hda_jack_callback_fn cb =
+               on ? pin_power_up_callback : pin_power_down_callback;
+
+       for (i = 0; i < num_pins && pins[i]; i++) {
+               if (is_jack_detectable(codec, pins[i]))
+                       snd_hda_jack_detect_enable_callback(codec, pins[i], cb);
+               else
+                       set_path_power(codec, pins[i], true, -1);
+       }
+}
+
+/* enabled power callback to each available I/O pin with jack detections;
+ * the digital I/O pins are excluded because of the unreliable detectsion
+ */
+static void add_all_pin_power_ctls(struct hda_codec *codec, bool on)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       if (!codec->power_save_node)
+               return;
+       add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on);
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+               add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on);
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+               add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on);
+       for (i = 0; i < cfg->num_inputs; i++)
+               add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on);
+}
+
+/* sync path power up/down with the jack states of given pins */
+static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins,
+                               const hda_nid_t *pins)
+{
+       int i;
+
+       for (i = 0; i < num_pins && pins[i]; i++)
+               if (is_jack_detectable(codec, pins[i]))
+                       set_pin_power_jack(codec, pins[i], -1);
+}
+
+/* sync path power up/down with pins; called at init and resume */
+static void sync_all_pin_power_ctls(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       if (!codec->power_save_node)
+               return;
+       sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins);
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+               sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins);
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+               sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins);
+       for (i = 0; i < cfg->num_inputs; i++)
+               sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin);
+}
+
+/* add fake paths if not present yet */
+static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid,
+                          int num_pins, const hda_nid_t *pins)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+       int i;
+
+       for (i = 0; i < num_pins; i++) {
+               if (!pins[i])
+                       break;
+               if (get_nid_path(codec, nid, pins[i], 0))
+                       continue;
+               path = snd_array_new(&spec->paths);
+               if (!path)
+                       return -ENOMEM;
+               memset(path, 0, sizeof(*path));
+               path->depth = 2;
+               path->path[0] = nid;
+               path->path[1] = pins[i];
+               path->active = true;
+       }
+       return 0;
+}
+
+/* create fake paths to all outputs from beep */
+static int add_fake_beep_paths(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       hda_nid_t nid = spec->beep_nid;
+       int err;
+
+       if (!codec->power_save_node || !nid)
+               return 0;
+       err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins);
+       if (err < 0)
+               return err;
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+               err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins);
+               if (err < 0)
+                       return err;
+       }
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+               err = add_fake_paths(codec, nid, cfg->speaker_outs,
+                                    cfg->speaker_pins);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+/* power up/down beep widget and its output paths */
+static void beep_power_hook(struct hda_beep *beep, bool on)
+{
+       set_path_power(beep->codec, beep->nid, -1, on);
+}
+
+/**
+ * snd_hda_gen_fix_pin_power - Fix the power of the given pin widget to D0
+ * @codec: the HDA codec
+ * @pin: NID of pin to fix
+ */
+int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct nid_path *path;
+
+       path = snd_array_new(&spec->paths);
+       if (!path)
+               return -ENOMEM;
+       memset(path, 0, sizeof(*path));
+       path->depth = 1;
+       path->path[0] = pin;
+       path->active = true;
+       path->pin_fixed = true;
+       path->stream_enabled = true;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_fix_pin_power);
+
+/*
+ * Jack detections for HP auto-mute and mic-switch
+ */
+
+/* check each pin in the given array; returns true if any of them is plugged */
+static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins)
+{
+       int i;
+       bool present = false;
+
+       for (i = 0; i < num_pins; i++) {
+               hda_nid_t nid = pins[i];
+               if (!nid)
+                       break;
+               /* don't detect pins retasked as inputs */
+               if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
+                       continue;
+               if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT)
+                       present = true;
+       }
+       return present;
+}
+
+/* standard HP/line-out auto-mute helper */
+static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins,
+                       int *paths, bool mute)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < num_pins; i++) {
+               hda_nid_t nid = pins[i];
+               unsigned int val, oldval;
+               if (!nid)
+                       break;
+
+               oldval = snd_hda_codec_get_pin_target(codec, nid);
+               if (oldval & PIN_IN)
+                       continue; /* no mute for inputs */
+
+               if (spec->auto_mute_via_amp) {
+                       struct nid_path *path;
+                       hda_nid_t mute_nid;
+
+                       path = snd_hda_get_path_from_idx(codec, paths[i]);
+                       if (!path)
+                               continue;
+                       mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]);
+                       if (!mute_nid)
+                               continue;
+                       if (mute)
+                               spec->mute_bits |= (1ULL << mute_nid);
+                       else
+                               spec->mute_bits &= ~(1ULL << mute_nid);
+                       continue;
+               } else {
+                       /* don't reset VREF value in case it's controlling
+                        * the amp (see alc861_fixup_asus_amp_vref_0f())
+                        */
+                       if (spec->keep_vref_in_automute)
+                               val = oldval & ~PIN_HP;
+                       else
+                               val = 0;
+                       if (!mute)
+                               val |= oldval;
+                       /* here we call update_pin_ctl() so that the pinctl is
+                        * changed without changing the pinctl target value;
+                        * the original target value will be still referred at
+                        * the init / resume again
+                        */
+                       update_pin_ctl(codec, nid, val);
+               }
+
+               set_pin_eapd(codec, nid, !mute);
+               if (codec->power_save_node) {
+                       bool on = !mute;
+                       if (on)
+                               on = detect_pin_state(codec, nid);
+                       set_path_power(codec, nid, on, -1);
+               }
+       }
+}
+
+/**
+ * snd_hda_gen_update_outputs - Toggle outputs muting
+ * @codec: the HDA codec
+ *
+ * Update the mute status of all outputs based on the current jack states.
+ */
+void snd_hda_gen_update_outputs(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int *paths;
+       int on;
+
+       /* Control HP pins/amps depending on master_mute state;
+        * in general, HP pins/amps control should be enabled in all cases,
+        * but currently set only for master_mute, just to be safe
+        */
+       if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
+               paths = spec->out_paths;
+       else
+               paths = spec->hp_paths;
+       do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
+                   spec->autocfg.hp_pins, paths, spec->master_mute);
+
+       if (!spec->automute_speaker)
+               on = 0;
+       else
+               on = spec->hp_jack_present | spec->line_jack_present;
+       on |= spec->master_mute;
+       spec->speaker_muted = on;
+       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+               paths = spec->out_paths;
+       else
+               paths = spec->speaker_paths;
+       do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
+                   spec->autocfg.speaker_pins, paths, on);
+
+       /* toggle line-out mutes if needed, too */
+       /* if LO is a copy of either HP or Speaker, don't need to handle it */
+       if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
+           spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
+               return;
+       if (!spec->automute_lo)
+               on = 0;
+       else
+               on = spec->hp_jack_present;
+       on |= spec->master_mute;
+       spec->line_out_muted = on;
+       paths = spec->out_paths;
+       do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
+                   spec->autocfg.line_out_pins, paths, on);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs);
+
+static void call_update_outputs(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->automute_hook)
+               spec->automute_hook(codec);
+       else
+               snd_hda_gen_update_outputs(codec);
+
+       /* sync the whole vmaster followers to reflect the new auto-mute status */
+       if (spec->auto_mute_via_amp && !codec->bus->shutdown)
+               snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
+}
+
+/**
+ * snd_hda_gen_hp_automute - standard HP-automute helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
+void snd_hda_gen_hp_automute(struct hda_codec *codec,
+                            struct hda_jack_callback *jack)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t *pins = spec->autocfg.hp_pins;
+       int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins);
+
+       /* No detection for the first HP jack during indep-HP mode */
+       if (spec->indep_hp_enabled) {
+               pins++;
+               num_pins--;
+       }
+
+       spec->hp_jack_present = detect_jacks(codec, num_pins, pins);
+       if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
+               return;
+       call_update_outputs(codec);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
+
+/**
+ * snd_hda_gen_line_automute - standard line-out-automute helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
+void snd_hda_gen_line_automute(struct hda_codec *codec,
+                              struct hda_jack_callback *jack)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
+               return;
+       /* check LO jack only when it's different from HP */
+       if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
+               return;
+
+       spec->line_jack_present =
+               detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
+                            spec->autocfg.line_out_pins);
+       if (!spec->automute_speaker || !spec->detect_lo)
+               return;
+       call_update_outputs(codec);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
+
+/**
+ * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
+void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
+                               struct hda_jack_callback *jack)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+
+       if (!spec->auto_mic)
+               return;
+
+       for (i = spec->am_num_entries - 1; i > 0; i--) {
+               hda_nid_t pin = spec->am_entry[i].pin;
+               /* don't detect pins retasked as outputs */
+               if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
+                       continue;
+               if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
+                       mux_select(codec, 0, spec->am_entry[i].idx);
+                       return;
+               }
+       }
+       mux_select(codec, 0, spec->am_entry[0].idx);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);
+
+/* call appropriate hooks */
+static void call_hp_automute(struct hda_codec *codec,
+                            struct hda_jack_callback *jack)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->hp_automute_hook)
+               spec->hp_automute_hook(codec, jack);
+       else
+               snd_hda_gen_hp_automute(codec, jack);
+}
+
+static void call_line_automute(struct hda_codec *codec,
+                              struct hda_jack_callback *jack)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->line_automute_hook)
+               spec->line_automute_hook(codec, jack);
+       else
+               snd_hda_gen_line_automute(codec, jack);
+}
+
+static void call_mic_autoswitch(struct hda_codec *codec,
+                               struct hda_jack_callback *jack)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->mic_autoswitch_hook)
+               spec->mic_autoswitch_hook(codec, jack);
+       else
+               snd_hda_gen_mic_autoswitch(codec, jack);
+}
+
+/* update jack retasking */
+static void update_automute_all(struct hda_codec *codec)
+{
+       call_hp_automute(codec, NULL);
+       call_line_automute(codec, NULL);
+       call_mic_autoswitch(codec, NULL);
+}
+
+/*
+ * Auto-Mute mode mixer enum support
+ */
+static int automute_mode_info(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       static const char * const texts3[] = {
+               "Disabled", "Speaker Only", "Line Out+Speaker"
+       };
+
+       if (spec->automute_speaker_possible && spec->automute_lo_possible)
+               return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
+       return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
+}
+
+static int automute_mode_get(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+       unsigned int val = 0;
+       if (spec->automute_speaker)
+               val++;
+       if (spec->automute_lo)
+               val++;
+
+       ucontrol->value.enumerated.item[0] = val;
+       return 0;
+}
+
+static int automute_mode_put(struct snd_kcontrol *kcontrol,
+                            struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hda_gen_spec *spec = codec->spec;
+
+       switch (ucontrol->value.enumerated.item[0]) {
+       case 0:
+               if (!spec->automute_speaker && !spec->automute_lo)
+                       return 0;
+               spec->automute_speaker = 0;
+               spec->automute_lo = 0;
+               break;
+       case 1:
+               if (spec->automute_speaker_possible) {
+                       if (!spec->automute_lo && spec->automute_speaker)
+                               return 0;
+                       spec->automute_speaker = 1;
+                       spec->automute_lo = 0;
+               } else if (spec->automute_lo_possible) {
+                       if (spec->automute_lo)
+                               return 0;
+                       spec->automute_lo = 1;
+               } else
+                       return -EINVAL;
+               break;
+       case 2:
+               if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
+                       return -EINVAL;
+               if (spec->automute_speaker && spec->automute_lo)
+                       return 0;
+               spec->automute_speaker = 1;
+               spec->automute_lo = 1;
+               break;
+       default:
+               return -EINVAL;
+       }
+       call_update_outputs(codec);
+       return 1;
+}
+
+static const struct snd_kcontrol_new automute_mode_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Auto-Mute Mode",
+       .info = automute_mode_info,
+       .get = automute_mode_get,
+       .put = automute_mode_put,
+};
+
+static int add_automute_mode_enum(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum))
+               return -ENOMEM;
+       return 0;
+}
+
+/*
+ * Check the availability of HP/line-out auto-mute;
+ * Set up appropriately if really supported
+ */
+static int check_auto_mute_availability(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int present = 0;
+       int i, err;
+
+       if (spec->suppress_auto_mute)
+               return 0;
+
+       if (cfg->hp_pins[0])
+               present++;
+       if (cfg->line_out_pins[0])
+               present++;
+       if (cfg->speaker_pins[0])
+               present++;
+       if (present < 2) /* need two different output types */
+               return 0;
+
+       if (!cfg->speaker_pins[0] &&
+           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
+               memcpy(cfg->speaker_pins, cfg->line_out_pins,
+                      sizeof(cfg->speaker_pins));
+               cfg->speaker_outs = cfg->line_outs;
+       }
+
+       if (!cfg->hp_pins[0] &&
+           cfg->line_out_type == AUTO_PIN_HP_OUT) {
+               memcpy(cfg->hp_pins, cfg->line_out_pins,
+                      sizeof(cfg->hp_pins));
+               cfg->hp_outs = cfg->line_outs;
+       }
+
+       for (i = 0; i < cfg->hp_outs; i++) {
+               hda_nid_t nid = cfg->hp_pins[i];
+               if (!is_jack_detectable(codec, nid))
+                       continue;
+               codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid);
+               snd_hda_jack_detect_enable_callback(codec, nid,
+                                                   call_hp_automute);
+               spec->detect_hp = 1;
+       }
+
+       if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
+               if (cfg->speaker_outs)
+                       for (i = 0; i < cfg->line_outs; i++) {
+                               hda_nid_t nid = cfg->line_out_pins[i];
+                               if (!is_jack_detectable(codec, nid))
+                                       continue;
+                               codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid);
+                               snd_hda_jack_detect_enable_callback(codec, nid,
+                                                                   call_line_automute);
+                               spec->detect_lo = 1;
+                       }
+               spec->automute_lo_possible = spec->detect_hp;
+       }
+
+       spec->automute_speaker_possible = cfg->speaker_outs &&
+               (spec->detect_hp || spec->detect_lo);
+
+       spec->automute_lo = spec->automute_lo_possible;
+       spec->automute_speaker = spec->automute_speaker_possible;
+
+       if (spec->automute_speaker_possible || spec->automute_lo_possible) {
+               /* create a control for automute mode */
+               err = add_automute_mode_enum(codec);
+               if (err < 0)
+                       return err;
+       }
+       return 0;
+}
+
+/* check whether all auto-mic pins are valid; setup indices if OK */
+static bool auto_mic_check_imux(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const struct hda_input_mux *imux;
+       int i;
+
+       imux = &spec->input_mux;
+       for (i = 0; i < spec->am_num_entries; i++) {
+               spec->am_entry[i].idx =
+                       find_idx_in_nid_list(spec->am_entry[i].pin,
+                                            spec->imux_pins, imux->num_items);
+               if (spec->am_entry[i].idx < 0)
+                       return false; /* no corresponding imux */
+       }
+
+       /* we don't need the jack detection for the first pin */
+       for (i = 1; i < spec->am_num_entries; i++)
+               snd_hda_jack_detect_enable_callback(codec,
+                                                   spec->am_entry[i].pin,
+                                                   call_mic_autoswitch);
+       return true;
+}
+
+static int compare_attr(const void *ap, const void *bp)
+{
+       const struct automic_entry *a = ap;
+       const struct automic_entry *b = bp;
+       return (int)(a->attr - b->attr);
+}
+
+/*
+ * Check the availability of auto-mic switch;
+ * Set up if really supported
+ */
+static int check_auto_mic_availability(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       unsigned int types;
+       int i, num_pins;
+
+       if (spec->suppress_auto_mic)
+               return 0;
+
+       types = 0;
+       num_pins = 0;
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               unsigned int attr;
+               attr = snd_hda_codec_get_pincfg(codec, nid);
+               attr = snd_hda_get_input_pin_attr(attr);
+               if (types & (1 << attr))
+                       return 0; /* already occupied */
+               switch (attr) {
+               case INPUT_PIN_ATTR_INT:
+                       if (cfg->inputs[i].type != AUTO_PIN_MIC)
+                               return 0; /* invalid type */
+                       break;
+               case INPUT_PIN_ATTR_UNUSED:
+                       return 0; /* invalid entry */
+               default:
+                       if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
+                               return 0; /* invalid type */
+                       if (!spec->line_in_auto_switch &&
+                           cfg->inputs[i].type != AUTO_PIN_MIC)
+                               return 0; /* only mic is allowed */
+                       if (!is_jack_detectable(codec, nid))
+                               return 0; /* no unsol support */
+                       break;
+               }
+               if (num_pins >= MAX_AUTO_MIC_PINS)
+                       return 0;
+               types |= (1 << attr);
+               spec->am_entry[num_pins].pin = nid;
+               spec->am_entry[num_pins].attr = attr;
+               num_pins++;
+       }
+
+       if (num_pins < 2)
+               return 0;
+
+       spec->am_num_entries = num_pins;
+       /* sort the am_entry in the order of attr so that the pin with a
+        * higher attr will be selected when the jack is plugged.
+        */
+       sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]),
+            compare_attr, NULL);
+
+       if (!auto_mic_check_imux(codec))
+               return 0;
+
+       spec->auto_mic = 1;
+       spec->num_adc_nids = 1;
+       spec->cur_mux[0] = spec->am_entry[0].idx;
+       codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
+                   spec->am_entry[0].pin,
+                   spec->am_entry[1].pin,
+                   spec->am_entry[2].pin);
+
+       return 0;
+}
+
+/**
+ * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets
+ * into power down
+ * @codec: the HDA codec
+ * @nid: NID to evalute
+ * @power_state: target power state
+ */
+unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
+                                                 hda_nid_t nid,
+                                                 unsigned int power_state)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (!spec->power_down_unused && !codec->power_save_node)
+               return power_state;
+       if (power_state != AC_PWRST_D0 || nid == codec->core.afg)
+               return power_state;
+       if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
+               return power_state;
+       if (is_active_nid_for_any(codec, nid))
+               return power_state;
+       return AC_PWRST_D3;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter);
+
+/* mute all aamix inputs initially; parse up to the first leaves */
+static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
+{
+       int i, nums;
+       const hda_nid_t *conn;
+       bool has_amp;
+
+       nums = snd_hda_get_conn_list(codec, mix, &conn);
+       has_amp = nid_has_mute(codec, mix, HDA_INPUT);
+       for (i = 0; i < nums; i++) {
+               if (has_amp)
+                       update_amp(codec, mix, HDA_INPUT, i,
+                                  0xff, HDA_AMP_MUTE);
+               else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
+                       update_amp(codec, conn[i], HDA_OUTPUT, 0,
+                                  0xff, HDA_AMP_MUTE);
+       }
+}
+
+/**
+ * snd_hda_gen_stream_pm - Stream power management callback
+ * @codec: the HDA codec
+ * @nid: audio widget
+ * @on: power on/off flag
+ *
+ * Set this in patch_ops.stream_pm.  Only valid with power_save_node flag.
+ */
+void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
+{
+       if (codec->power_save_node)
+               set_path_power(codec, nid, -1, on);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
+
+/* forcibly mute the speaker output without caching; return true if updated */
+static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid)
+{
+       if (!nid)
+               return false;
+       if (!nid_has_mute(codec, nid, HDA_OUTPUT))
+               return false; /* no mute, skip */
+       if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
+           snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) &
+           HDA_AMP_MUTE)
+               return false; /* both channels already muted, skip */
+
+       /* direct amp update without caching */
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                           AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT |
+                           AC_AMP_SET_RIGHT | HDA_AMP_MUTE);
+       return true;
+}
+
+/**
+ * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs
+ * @codec: the HDA codec
+ *
+ * Forcibly mute the speaker outputs, to be called at suspend or shutdown.
+ *
+ * The mute state done by this function isn't cached, hence the original state
+ * will be restored at resume.
+ *
+ * Return true if the mute state has been changed.
+ */
+bool snd_hda_gen_shutup_speakers(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       const int *paths;
+       const struct nid_path *path;
+       int i, p, num_paths;
+       bool updated = false;
+
+       /* if already powered off, do nothing */
+       if (!snd_hdac_is_power_on(&codec->core))
+               return false;
+
+       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
+               paths = spec->out_paths;
+               num_paths = spec->autocfg.line_outs;
+       } else {
+               paths = spec->speaker_paths;
+               num_paths = spec->autocfg.speaker_outs;
+       }
+
+       for (i = 0; i < num_paths; i++) {
+               path = snd_hda_get_path_from_idx(codec, paths[i]);
+               if (!path)
+                       continue;
+               for (p = 0; p < path->depth; p++)
+                       if (force_mute_output_path(codec, path->path[p]))
+                               updated = true;
+       }
+
+       return updated;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers);
+
+/**
+ * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
+ * set up the hda_gen_spec
+ * @codec: the HDA codec
+ * @cfg: Parsed pin configuration
+ *
+ * return 1 if successful, 0 if the proper config is not found,
+ * or a negative error code
+ */
+int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
+                                 struct auto_pin_cfg *cfg)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err;
+
+       parse_user_hints(codec);
+
+       if (spec->vmaster_mute_led || spec->mic_mute_led)
+               snd_ctl_led_request();
+
+       if (spec->mixer_nid && !spec->mixer_merge_nid)
+               spec->mixer_merge_nid = spec->mixer_nid;
+
+       if (cfg != &spec->autocfg) {
+               spec->autocfg = *cfg;
+               cfg = &spec->autocfg;
+       }
+
+       if (!spec->main_out_badness)
+               spec->main_out_badness = &hda_main_out_badness;
+       if (!spec->extra_out_badness)
+               spec->extra_out_badness = &hda_extra_out_badness;
+
+       fill_all_dac_nids(codec);
+
+       if (!cfg->line_outs) {
+               if (cfg->dig_outs || cfg->dig_in_pin) {
+                       spec->multiout.max_channels = 2;
+                       spec->no_analog = 1;
+                       goto dig_only;
+               }
+               if (!cfg->num_inputs && !cfg->dig_in_pin)
+                       return 0; /* can't find valid BIOS pin config */
+       }
+
+       if (!spec->no_primary_hp &&
+           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
+           cfg->line_outs <= cfg->hp_outs) {
+               /* use HP as primary out */
+               cfg->speaker_outs = cfg->line_outs;
+               memcpy(cfg->speaker_pins, cfg->line_out_pins,
+                      sizeof(cfg->speaker_pins));
+               cfg->line_outs = cfg->hp_outs;
+               memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
+               cfg->hp_outs = 0;
+               memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
+               cfg->line_out_type = AUTO_PIN_HP_OUT;
+       }
+
+       err = parse_output_paths(codec);
+       if (err < 0)
+               return err;
+       err = create_multi_channel_mode(codec);
+       if (err < 0)
+               return err;
+       err = create_multi_out_ctls(codec, cfg);
+       if (err < 0)
+               return err;
+       err = create_hp_out_ctls(codec);
+       if (err < 0)
+               return err;
+       err = create_speaker_out_ctls(codec);
+       if (err < 0)
+               return err;
+       err = create_indep_hp_ctls(codec);
+       if (err < 0)
+               return err;
+       err = create_loopback_mixing_ctl(codec);
+       if (err < 0)
+               return err;
+       err = create_hp_mic(codec);
+       if (err < 0)
+               return err;
+       err = create_input_ctls(codec);
+       if (err < 0)
+               return err;
+
+       /* add power-down pin callbacks at first */
+       add_all_pin_power_ctls(codec, false);
+
+       spec->const_channel_count = spec->ext_channel_count;
+       /* check the multiple speaker and headphone pins */
+       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
+               spec->const_channel_count = max(spec->const_channel_count,
+                                               cfg->speaker_outs * 2);
+       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
+               spec->const_channel_count = max(spec->const_channel_count,
+                                               cfg->hp_outs * 2);
+       spec->multiout.max_channels = max(spec->ext_channel_count,
+                                         spec->const_channel_count);
+
+       err = check_auto_mute_availability(codec);
+       if (err < 0)
+               return err;
+
+       err = check_dyn_adc_switch(codec);
+       if (err < 0)
+               return err;
+
+       err = check_auto_mic_availability(codec);
+       if (err < 0)
+               return err;
+
+       /* add stereo mix if available and not enabled yet */
+       if (!spec->auto_mic && spec->mixer_nid &&
+           spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_AUTO &&
+           spec->input_mux.num_items > 1) {
+               err = parse_capture_source(codec, spec->mixer_nid,
+                                          CFG_IDX_MIX, spec->num_all_adcs,
+                                          "Stereo Mix", 0);
+               if (err < 0)
+                       return err;
+       }
+
+
+       err = create_capture_mixers(codec);
+       if (err < 0)
+               return err;
+
+       err = parse_mic_boost(codec);
+       if (err < 0)
+               return err;
+
+       /* create "Headphone Mic Jack Mode" if no input selection is
+        * available (or user specifies add_jack_modes hint)
+        */
+       if (spec->hp_mic_pin &&
+           (spec->auto_mic || spec->input_mux.num_items == 1 ||
+            spec->add_jack_modes)) {
+               err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin);
+               if (err < 0)
+                       return err;
+       }
+
+       if (spec->add_jack_modes) {
+               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
+                       err = create_out_jack_modes(codec, cfg->line_outs,
+                                                   cfg->line_out_pins);
+                       if (err < 0)
+                               return err;
+               }
+               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
+                       err = create_out_jack_modes(codec, cfg->hp_outs,
+                                                   cfg->hp_pins);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       /* add power-up pin callbacks at last */
+       add_all_pin_power_ctls(codec, true);
+
+       /* mute all aamix input initially */
+       if (spec->mixer_nid)
+               mute_all_mixer_nid(codec, spec->mixer_nid);
+
+ dig_only:
+       parse_digital(codec);
+
+       if (spec->power_down_unused || codec->power_save_node) {
+               if (!codec->power_filter)
+                       codec->power_filter = snd_hda_gen_path_power_filter;
+               if (!codec->patch_ops.stream_pm)
+                       codec->patch_ops.stream_pm = snd_hda_gen_stream_pm;
+       }
+
+       if (!spec->no_analog && spec->beep_nid) {
+               err = snd_hda_attach_beep_device(codec, spec->beep_nid);
+               if (err < 0)
+                       return err;
+               if (codec->beep && codec->power_save_node) {
+                       err = add_fake_beep_paths(codec);
+                       if (err < 0)
+                               return err;
+                       codec->beep->power_hook = beep_power_hook;
+               }
+       }
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config);
+
+
+/*
+ * Build control elements
+ */
+
+/* follower controls for virtual master */
+static const char * const follower_pfxs[] = {
+       "Front", "Surround", "Center", "LFE", "Side",
+       "Headphone", "Speaker", "Mono", "Line Out",
+       "CLFE", "Bass Speaker", "PCM",
+       "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
+       "Headphone Front", "Headphone Surround", "Headphone CLFE",
+       "Headphone Side", "Headphone+LO", "Speaker+LO",
+       NULL,
+};
+
+/**
+ * snd_hda_gen_build_controls - Build controls from the parsed results
+ * @codec: the HDA codec
+ *
+ * Pass this to build_controls patch_ops.
+ */
+int snd_hda_gen_build_controls(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err;
+
+       if (spec->kctls.used) {
+               err = snd_hda_add_new_ctls(codec, spec->kctls.list);
+               if (err < 0)
+                       return err;
+       }
+
+       if (spec->multiout.dig_out_nid) {
+               err = snd_hda_create_dig_out_ctls(codec,
+                                                 spec->multiout.dig_out_nid,
+                                                 spec->multiout.dig_out_nid,
+                                                 spec->pcm_rec[1]->pcm_type);
+               if (err < 0)
+                       return err;
+               if (!spec->no_analog) {
+                       err = snd_hda_create_spdif_share_sw(codec,
+                                                           &spec->multiout);
+                       if (err < 0)
+                               return err;
+                       spec->multiout.share_spdif = 1;
+               }
+       }
+       if (spec->dig_in_nid) {
+               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
+               if (err < 0)
+                       return err;
+       }
+
+       /* if we have no master control, let's create it */
+       if (!spec->no_analog && !spec->suppress_vmaster &&
+           !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
+               err = snd_hda_add_vmaster(codec, "Master Playback Volume",
+                                         spec->vmaster_tlv, follower_pfxs,
+                                         "Playback Volume", 0);
+               if (err < 0)
+                       return err;
+       }
+       if (!spec->no_analog && !spec->suppress_vmaster &&
+           !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
+               err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
+                                           NULL, follower_pfxs,
+                                           "Playback Switch", true,
+                                           spec->vmaster_mute_led ?
+                                               SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0,
+                                           &spec->vmaster_mute.sw_kctl);
+               if (err < 0)
+                       return err;
+               if (spec->vmaster_mute.hook) {
+                       snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
+                       snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+               }
+       }
+
+       free_kctls(spec); /* no longer needed */
+
+       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls);
+
+
+/*
+ * PCM definitions
+ */
+
+static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream,
+                                  int action)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->pcm_playback_hook)
+               spec->pcm_playback_hook(hinfo, codec, substream, action);
+}
+
+static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream,
+                                 int action)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       if (spec->pcm_capture_hook)
+               spec->pcm_capture_hook(hinfo, codec, substream, action);
+}
+
+/*
+ * Analog playback callbacks
+ */
+static int playback_pcm_open(struct hda_pcm_stream *hinfo,
+                            struct hda_codec *codec,
+                            struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err;
+
+       mutex_lock(&spec->pcm_mutex);
+       err = snd_hda_multi_out_analog_open(codec,
+                                           &spec->multiout, substream,
+                                            hinfo);
+       if (!err) {
+               spec->active_streams |= 1 << STREAM_MULTI_OUT;
+               call_pcm_playback_hook(hinfo, codec, substream,
+                                      HDA_GEN_PCM_ACT_OPEN);
+       }
+       mutex_unlock(&spec->pcm_mutex);
+       return err;
+}
+
+static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                               struct hda_codec *codec,
+                               unsigned int stream_tag,
+                               unsigned int format,
+                               struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
+                                              stream_tag, format, substream);
+       if (!err)
+               call_pcm_playback_hook(hinfo, codec, substream,
+                                      HDA_GEN_PCM_ACT_PREPARE);
+       return err;
+}
+
+static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                               struct hda_codec *codec,
+                               struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err;
+
+       err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
+       if (!err)
+               call_pcm_playback_hook(hinfo, codec, substream,
+                                      HDA_GEN_PCM_ACT_CLEANUP);
+       return err;
+}
+
+static int playback_pcm_close(struct hda_pcm_stream *hinfo,
+                             struct hda_codec *codec,
+                             struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       mutex_lock(&spec->pcm_mutex);
+       spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_CLOSE);
+       mutex_unlock(&spec->pcm_mutex);
+       return 0;
+}
+
+static int capture_pcm_open(struct hda_pcm_stream *hinfo,
+                           struct hda_codec *codec,
+                           struct snd_pcm_substream *substream)
+{
+       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN);
+       return 0;
+}
+
+static int capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+                              struct hda_codec *codec,
+                              unsigned int stream_tag,
+                              unsigned int format,
+                              struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
+       call_pcm_capture_hook(hinfo, codec, substream,
+                             HDA_GEN_PCM_ACT_PREPARE);
+       return 0;
+}
+
+static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                              struct hda_codec *codec,
+                              struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+       call_pcm_capture_hook(hinfo, codec, substream,
+                             HDA_GEN_PCM_ACT_CLEANUP);
+       return 0;
+}
+
+static int capture_pcm_close(struct hda_pcm_stream *hinfo,
+                            struct hda_codec *codec,
+                            struct snd_pcm_substream *substream)
+{
+       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE);
+       return 0;
+}
+
+static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                struct hda_codec *codec,
+                                struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int err = 0;
+
+       mutex_lock(&spec->pcm_mutex);
+       if (spec->indep_hp && !spec->indep_hp_enabled)
+               err = -EBUSY;
+       else
+               spec->active_streams |= 1 << STREAM_INDEP_HP;
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_OPEN);
+       mutex_unlock(&spec->pcm_mutex);
+       return err;
+}
+
+static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       mutex_lock(&spec->pcm_mutex);
+       spec->active_streams &= ~(1 << STREAM_INDEP_HP);
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_CLOSE);
+       mutex_unlock(&spec->pcm_mutex);
+       return 0;
+}
+
+static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   unsigned int stream_tag,
+                                   unsigned int format,
+                                   struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_PREPARE);
+       return 0;
+}
+
+static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+       call_pcm_playback_hook(hinfo, codec, substream,
+                              HDA_GEN_PCM_ACT_CLEANUP);
+       return 0;
+}
+
+/*
+ * Digital out
+ */
+static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                struct hda_codec *codec,
+                                struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   unsigned int stream_tag,
+                                   unsigned int format,
+                                   struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+                                            stream_tag, format, substream);
+}
+
+static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
+}
+
+static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+/*
+ * Analog capture
+ */
+#define alt_capture_pcm_open   capture_pcm_open
+#define alt_capture_pcm_close  capture_pcm_close
+
+static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  unsigned int stream_tag,
+                                  unsigned int format,
+                                  struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
+                                  stream_tag, 0, format);
+       call_pcm_capture_hook(hinfo, codec, substream,
+                             HDA_GEN_PCM_ACT_PREPARE);
+       return 0;
+}
+
+static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       snd_hda_codec_cleanup_stream(codec,
+                                    spec->adc_nids[substream->number + 1]);
+       call_pcm_capture_hook(hinfo, codec, substream,
+                             HDA_GEN_PCM_ACT_CLEANUP);
+       return 0;
+}
+
+/*
+ */
+static const struct hda_pcm_stream pcm_analog_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       /* NID is set in build_pcms */
+       .ops = {
+               .open = playback_pcm_open,
+               .close = playback_pcm_close,
+               .prepare = playback_pcm_prepare,
+               .cleanup = playback_pcm_cleanup
+       },
+};
+
+static const struct hda_pcm_stream pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in build_pcms */
+       .ops = {
+               .open = capture_pcm_open,
+               .close = capture_pcm_close,
+               .prepare = capture_pcm_prepare,
+               .cleanup = capture_pcm_cleanup
+       },
+};
+
+static const struct hda_pcm_stream pcm_analog_alt_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in build_pcms */
+       .ops = {
+               .open = alt_playback_pcm_open,
+               .close = alt_playback_pcm_close,
+               .prepare = alt_playback_pcm_prepare,
+               .cleanup = alt_playback_pcm_cleanup
+       },
+};
+
+static const struct hda_pcm_stream pcm_analog_alt_capture = {
+       .substreams = 2, /* can be overridden */
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in build_pcms */
+       .ops = {
+               .open = alt_capture_pcm_open,
+               .close = alt_capture_pcm_close,
+               .prepare = alt_capture_pcm_prepare,
+               .cleanup = alt_capture_pcm_cleanup
+       },
+};
+
+static const struct hda_pcm_stream pcm_digital_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in build_pcms */
+       .ops = {
+               .open = dig_playback_pcm_open,
+               .close = dig_playback_pcm_close,
+               .prepare = dig_playback_pcm_prepare,
+               .cleanup = dig_playback_pcm_cleanup
+       },
+};
+
+static const struct hda_pcm_stream pcm_digital_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       /* NID is set in build_pcms */
+};
+
+/* Used by build_pcms to flag that a PCM has no playback stream */
+static const struct hda_pcm_stream pcm_null_stream = {
+       .substreams = 0,
+       .channels_min = 0,
+       .channels_max = 0,
+};
+
+/*
+ * dynamic changing ADC PCM streams
+ */
+static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
+
+       if (spec->cur_adc && spec->cur_adc != new_adc) {
+               /* stream is running, let's swap the current ADC */
+               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
+               spec->cur_adc = new_adc;
+               snd_hda_codec_setup_stream(codec, new_adc,
+                                          spec->cur_adc_stream_tag, 0,
+                                          spec->cur_adc_format);
+               return true;
+       }
+       return false;
+}
+
+/* analog capture with dynamic dual-adc changes */
+static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      unsigned int stream_tag,
+                                      unsigned int format,
+                                      struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
+       spec->cur_adc_stream_tag = stream_tag;
+       spec->cur_adc_format = format;
+       snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
+       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_PREPARE);
+       return 0;
+}
+
+static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      struct snd_pcm_substream *substream)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
+       spec->cur_adc = 0;
+       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLEANUP);
+       return 0;
+}
+
+static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .nid = 0, /* fill later */
+       .ops = {
+               .prepare = dyn_adc_capture_pcm_prepare,
+               .cleanup = dyn_adc_capture_pcm_cleanup
+       },
+};
+
+static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
+                                const char *chip_name)
+{
+       char *p;
+
+       if (*str)
+               return;
+       strscpy(str, chip_name, len);
+
+       /* drop non-alnum chars after a space */
+       for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) {
+               if (!isalnum(p[1])) {
+                       *p = 0;
+                       break;
+               }
+       }
+       strlcat(str, sfx, len);
+}
+
+/* copy PCM stream info from @default_str, and override non-NULL entries
+ * from @spec_str and @nid
+ */
+static void setup_pcm_stream(struct hda_pcm_stream *str,
+                            const struct hda_pcm_stream *default_str,
+                            const struct hda_pcm_stream *spec_str,
+                            hda_nid_t nid)
+{
+       *str = *default_str;
+       if (nid)
+               str->nid = nid;
+       if (spec_str) {
+               if (spec_str->substreams)
+                       str->substreams = spec_str->substreams;
+               if (spec_str->channels_min)
+                       str->channels_min = spec_str->channels_min;
+               if (spec_str->channels_max)
+                       str->channels_max = spec_str->channels_max;
+               if (spec_str->rates)
+                       str->rates = spec_str->rates;
+               if (spec_str->formats)
+                       str->formats = spec_str->formats;
+               if (spec_str->maxbps)
+                       str->maxbps = spec_str->maxbps;
+       }
+}
+
+/**
+ * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
+ * @codec: the HDA codec
+ *
+ * Pass this to build_pcms patch_ops.
+ */
+int snd_hda_gen_build_pcms(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct hda_pcm *info;
+       bool have_multi_adcs;
+
+       if (spec->no_analog)
+               goto skip_analog;
+
+       fill_pcm_stream_name(spec->stream_name_analog,
+                            sizeof(spec->stream_name_analog),
+                            " Analog", codec->core.chip_name);
+       info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
+       if (!info)
+               return -ENOMEM;
+       spec->pcm_rec[0] = info;
+
+       if (spec->multiout.num_dacs > 0) {
+               setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+                                &pcm_analog_playback,
+                                spec->stream_analog_playback,
+                                spec->multiout.dac_nids[0]);
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
+                       spec->multiout.max_channels;
+               if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
+                   spec->autocfg.line_outs == 2)
+                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
+                               snd_pcm_2_1_chmaps;
+       }
+       if (spec->num_adc_nids) {
+               setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+                                (spec->dyn_adc_switch ?
+                                 &dyn_adc_pcm_analog_capture : &pcm_analog_capture),
+                                spec->stream_analog_capture,
+                                spec->adc_nids[0]);
+       }
+
+ skip_analog:
+       /* SPDIF for stream index #1 */
+       if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
+               fill_pcm_stream_name(spec->stream_name_digital,
+                                    sizeof(spec->stream_name_digital),
+                                    " Digital", codec->core.chip_name);
+               info = snd_hda_codec_pcm_new(codec, "%s",
+                                            spec->stream_name_digital);
+               if (!info)
+                       return -ENOMEM;
+               codec->follower_dig_outs = spec->multiout.follower_dig_outs;
+               spec->pcm_rec[1] = info;
+               if (spec->dig_out_type)
+                       info->pcm_type = spec->dig_out_type;
+               else
+                       info->pcm_type = HDA_PCM_TYPE_SPDIF;
+               if (spec->multiout.dig_out_nid)
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+                                        &pcm_digital_playback,
+                                        spec->stream_digital_playback,
+                                        spec->multiout.dig_out_nid);
+               if (spec->dig_in_nid)
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+                                        &pcm_digital_capture,
+                                        spec->stream_digital_capture,
+                                        spec->dig_in_nid);
+       }
+
+       if (spec->no_analog)
+               return 0;
+
+       /* If the use of more than one ADC is requested for the current
+        * model, configure a second analog capture-only PCM.
+        */
+       have_multi_adcs = (spec->num_adc_nids > 1) &&
+               !spec->dyn_adc_switch && !spec->auto_mic;
+       /* Additional Analaog capture for index #2 */
+       if (spec->alt_dac_nid || have_multi_adcs) {
+               fill_pcm_stream_name(spec->stream_name_alt_analog,
+                                    sizeof(spec->stream_name_alt_analog),
+                            " Alt Analog", codec->core.chip_name);
+               info = snd_hda_codec_pcm_new(codec, "%s",
+                                            spec->stream_name_alt_analog);
+               if (!info)
+                       return -ENOMEM;
+               spec->pcm_rec[2] = info;
+               if (spec->alt_dac_nid)
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+                                        &pcm_analog_alt_playback,
+                                        spec->stream_analog_alt_playback,
+                                        spec->alt_dac_nid);
+               else
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
+                                        &pcm_null_stream, NULL, 0);
+               if (have_multi_adcs) {
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+                                        &pcm_analog_alt_capture,
+                                        spec->stream_analog_alt_capture,
+                                        spec->adc_nids[1]);
+                       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
+                               spec->num_adc_nids - 1;
+               } else {
+                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
+                                        &pcm_null_stream, NULL, 0);
+               }
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms);
+
+
+/*
+ * Standard auto-parser initializations
+ */
+
+/* configure the given path as a proper output */
+static void set_output_and_unmute(struct hda_codec *codec, int path_idx)
+{
+       struct nid_path *path;
+       hda_nid_t pin;
+
+       path = snd_hda_get_path_from_idx(codec, path_idx);
+       if (!path || !path->depth)
+               return;
+       pin = path->path[path->depth - 1];
+       restore_pin_ctl(codec, pin);
+       snd_hda_activate_path(codec, path, path->active,
+                             aamix_default(codec->spec));
+       set_pin_eapd(codec, pin, path->active);
+}
+
+/* initialize primary output paths */
+static void init_multi_out(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->autocfg.line_outs; i++)
+               set_output_and_unmute(codec, spec->out_paths[i]);
+}
+
+
+static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths)
+{
+       int i;
+
+       for (i = 0; i < num_outs; i++)
+               set_output_and_unmute(codec, paths[i]);
+}
+
+/* initialize hp and speaker paths */
+static void init_extra_out(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT)
+               __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths);
+       if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT)
+               __init_extra_out(codec, spec->autocfg.speaker_outs,
+                                spec->speaker_paths);
+}
+
+/* initialize multi-io paths */
+static void init_multi_io(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->multi_ios; i++) {
+               hda_nid_t pin = spec->multi_io[i].pin;
+               struct nid_path *path;
+               path = get_multiio_path(codec, i);
+               if (!path)
+                       continue;
+               if (!spec->multi_io[i].ctl_in)
+                       spec->multi_io[i].ctl_in =
+                               snd_hda_codec_get_pin_target(codec, pin);
+               snd_hda_activate_path(codec, path, path->active,
+                                     aamix_default(spec));
+       }
+}
+
+static void init_aamix_paths(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (!spec->have_aamix_ctl)
+               return;
+       if (!has_aamix_out_paths(spec))
+               return;
+       update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0],
+                          spec->aamix_out_paths[0],
+                          spec->autocfg.line_out_type);
+       update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0],
+                          spec->aamix_out_paths[1],
+                          AUTO_PIN_HP_OUT);
+       update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0],
+                          spec->aamix_out_paths[2],
+                          AUTO_PIN_SPEAKER_OUT);
+}
+
+/* set up input pins and loopback paths */
+static void init_analog_input(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->autocfg;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               if (is_input_pin(codec, nid))
+                       restore_pin_ctl(codec, nid);
+
+               /* init loopback inputs */
+               if (spec->mixer_nid) {
+                       resume_path_from_idx(codec, spec->loopback_paths[i]);
+                       resume_path_from_idx(codec, spec->loopback_merge_path);
+               }
+       }
+}
+
+/* initialize ADC paths */
+static void init_input_src(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->input_mux;
+       struct nid_path *path;
+       int i, c, nums;
+
+       if (spec->dyn_adc_switch)
+               nums = 1;
+       else
+               nums = spec->num_adc_nids;
+
+       for (c = 0; c < nums; c++) {
+               for (i = 0; i < imux->num_items; i++) {
+                       path = get_input_path(codec, c, i);
+                       if (path) {
+                               bool active = path->active;
+                               if (i == spec->cur_mux[c])
+                                       active = true;
+                               snd_hda_activate_path(codec, path, active, false);
+                       }
+               }
+               if (spec->hp_mic)
+                       update_hp_mic(codec, c, true);
+       }
+
+       if (spec->cap_sync_hook)
+               spec->cap_sync_hook(codec, NULL, NULL);
+}
+
+/* set right pin controls for digital I/O */
+static void init_digital(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       int i;
+       hda_nid_t pin;
+
+       for (i = 0; i < spec->autocfg.dig_outs; i++)
+               set_output_and_unmute(codec, spec->digout_paths[i]);
+       pin = spec->autocfg.dig_in_pin;
+       if (pin) {
+               restore_pin_ctl(codec, pin);
+               resume_path_from_idx(codec, spec->digin_path);
+       }
+}
+
+/* clear unsol-event tags on unused pins; Conexant codecs seem to leave
+ * invalid unsol tags by some reason
+ */
+static void clear_unsol_on_unused_pins(struct hda_codec *codec)
+{
+       const struct hda_pincfg *pin;
+       int i;
+
+       snd_array_for_each(&codec->init_pins, i, pin) {
+               hda_nid_t nid = pin->nid;
+               if (is_jack_detectable(codec, nid) &&
+                   !snd_hda_jack_tbl_get(codec, nid))
+                       snd_hda_codec_write_cache(codec, nid, 0,
+                                       AC_VERB_SET_UNSOLICITED_ENABLE, 0);
+       }
+}
+
+/**
+ * snd_hda_gen_init - initialize the generic spec
+ * @codec: the HDA codec
+ *
+ * This can be put as patch_ops init function.
+ */
+int snd_hda_gen_init(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec = codec->spec;
+
+       if (spec->init_hook)
+               spec->init_hook(codec);
+
+       if (!spec->skip_verbs)
+               snd_hda_apply_verbs(codec);
+
+       init_multi_out(codec);
+       init_extra_out(codec);
+       init_multi_io(codec);
+       init_aamix_paths(codec);
+       init_analog_input(codec);
+       init_input_src(codec);
+       init_digital(codec);
+
+       clear_unsol_on_unused_pins(codec);
+
+       sync_all_pin_power_ctls(codec);
+
+       /* call init functions of standard auto-mute helpers */
+       update_automute_all(codec);
+
+       snd_hda_regmap_sync(codec);
+
+       if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
+               snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
+
+       hda_call_check_power_status(codec, 0x01);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_init);
+
+/**
+ * snd_hda_gen_free - free the generic spec
+ * @codec: the HDA codec
+ *
+ * This can be put as patch_ops free function.
+ */
+void snd_hda_gen_free(struct hda_codec *codec)
+{
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
+       snd_hda_gen_spec_free(codec->spec);
+       kfree(codec->spec);
+       codec->spec = NULL;
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_free);
+
+/**
+ * snd_hda_gen_check_power_status - check the loopback power save state
+ * @codec: the HDA codec
+ * @nid: NID to inspect
+ *
+ * This can be put as patch_ops check_power_status function.
+ */
+int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct hda_gen_spec *spec = codec->spec;
+       return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
+}
+EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status);
+
+
+/*
+ * the generic codec support
+ */
+
+static const struct hda_codec_ops generic_patch_ops = {
+       .build_controls = snd_hda_gen_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = snd_hda_gen_init,
+       .free = snd_hda_gen_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .check_power_status = snd_hda_gen_check_power_status,
+};
+
+/*
+ * snd_hda_parse_generic_codec - Generic codec parser
+ * @codec: the HDA codec
+ */
+static int snd_hda_parse_generic_codec(struct hda_codec *codec)
+{
+       struct hda_gen_spec *spec;
+       int err;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       snd_hda_gen_spec_init(spec);
+       codec->spec = spec;
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
+       if (err < 0)
+               goto error;
+
+       err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
+       if (err < 0)
+               goto error;
+
+       codec->patch_ops = generic_patch_ops;
+       return 0;
+
+error:
+       snd_hda_gen_free(codec);
+       return err;
+}
+
+static const struct hda_device_id snd_hda_id_generic[] = {
+       HDA_CODEC_ENTRY(0x1af40021, "Generic", snd_hda_parse_generic_codec), /* QEMU */
+       HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic);
+
+static struct hda_codec_driver generic_driver = {
+       .id = snd_hda_id_generic,
+};
+
+module_hda_codec_driver(generic_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Generic HD-audio codec parser");
diff --git a/sound/hda/codecs/generic.h b/sound/hda/codecs/generic.h
new file mode 100644 (file)
index 0000000..9612afa
--- /dev/null
@@ -0,0 +1,357 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Generic BIOS auto-parser helper functions for HD-audio
+ *
+ * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
+ */
+
+#ifndef __SOUND_HDA_GENERIC_H
+#define __SOUND_HDA_GENERIC_H
+
+#include <linux/leds.h>
+#include "hda_auto_parser.h"
+
+struct hda_jack_callback;
+
+/* table entry for multi-io paths */
+struct hda_multi_io {
+       hda_nid_t pin;          /* multi-io widget pin NID */
+       hda_nid_t dac;          /* DAC to be connected */
+       unsigned int ctl_in;    /* cached input-pin control value */
+};
+
+/* Widget connection path
+ *
+ * For output, stored in the order of DAC -> ... -> pin,
+ * for input, pin -> ... -> ADC.
+ *
+ * idx[i] contains the source index number to select on of the widget path[i];
+ * e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget
+ * multi[] indicates whether it's a selector widget with multi-connectors
+ * (i.e. the connection selection is mandatory)
+ * vol_ctl and mute_ctl contains the NIDs for the assigned mixers
+ */
+
+#define MAX_NID_PATH_DEPTH     10
+
+enum {
+       NID_PATH_VOL_CTL,
+       NID_PATH_MUTE_CTL,
+       NID_PATH_BOOST_CTL,
+       NID_PATH_NUM_CTLS
+};
+
+struct nid_path {
+       int depth;
+       hda_nid_t path[MAX_NID_PATH_DEPTH];
+       unsigned char idx[MAX_NID_PATH_DEPTH];
+       unsigned char multi[MAX_NID_PATH_DEPTH];
+       unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
+       bool active:1;          /* activated by driver */
+       bool pin_enabled:1;     /* pins are enabled */
+       bool pin_fixed:1;       /* path with fixed pin */
+       bool stream_enabled:1;  /* stream is active */
+};
+
+/* mic/line-in auto switching entry */
+
+#define MAX_AUTO_MIC_PINS      3
+
+struct automic_entry {
+       hda_nid_t pin;          /* pin */
+       int idx;                /* imux index, -1 = invalid */
+       unsigned int attr;      /* pin attribute (INPUT_PIN_ATTR_*) */
+};
+
+/* active stream id */
+enum { STREAM_MULTI_OUT, STREAM_INDEP_HP };
+
+/* PCM hook action */
+enum {
+       HDA_GEN_PCM_ACT_OPEN,
+       HDA_GEN_PCM_ACT_PREPARE,
+       HDA_GEN_PCM_ACT_CLEANUP,
+       HDA_GEN_PCM_ACT_CLOSE,
+};
+
+/* DAC assignment badness table */
+struct badness_table {
+       int no_primary_dac;     /* no primary DAC */
+       int no_dac;             /* no secondary DACs */
+       int shared_primary;     /* primary DAC is shared with main output */
+       int shared_surr;        /* secondary DAC shared with main or primary */
+       int shared_clfe;        /* third DAC shared with main or primary */
+       int shared_surr_main;   /* secondary DAC sahred with main/DAC0 */
+};
+
+extern const struct badness_table hda_main_out_badness;
+extern const struct badness_table hda_extra_out_badness;
+
+struct hda_gen_spec {
+       char stream_name_analog[32];    /* analog PCM stream */
+       const struct hda_pcm_stream *stream_analog_playback;
+       const struct hda_pcm_stream *stream_analog_capture;
+
+       char stream_name_alt_analog[32]; /* alternative analog PCM stream */
+       const struct hda_pcm_stream *stream_analog_alt_playback;
+       const struct hda_pcm_stream *stream_analog_alt_capture;
+
+       char stream_name_digital[32];   /* digital PCM stream */
+       const struct hda_pcm_stream *stream_digital_playback;
+       const struct hda_pcm_stream *stream_digital_capture;
+
+       /* PCM */
+       unsigned int active_streams;
+       struct mutex pcm_mutex;
+
+       /* playback */
+       struct hda_multi_out multiout;  /* playback set-up
+                                        * max_channels, dacs must be set
+                                        * dig_out_nid and hp_nid are optional
+                                        */
+       hda_nid_t alt_dac_nid;
+       hda_nid_t follower_dig_outs[3]; /* optional - for auto-parsing */
+       int dig_out_type;
+
+       /* capture */
+       unsigned int num_adc_nids;
+       hda_nid_t adc_nids[AUTO_CFG_MAX_INS];
+       hda_nid_t dig_in_nid;           /* digital-in NID; optional */
+       hda_nid_t mixer_nid;            /* analog-mixer NID */
+       hda_nid_t mixer_merge_nid;      /* aamix merge-point NID (optional) */
+       const char *input_labels[HDA_MAX_NUM_INPUTS];
+       int input_label_idxs[HDA_MAX_NUM_INPUTS];
+
+       /* capture setup for dynamic dual-adc switch */
+       hda_nid_t cur_adc;
+       unsigned int cur_adc_stream_tag;
+       unsigned int cur_adc_format;
+
+       /* capture source */
+       struct hda_input_mux input_mux;
+       unsigned int cur_mux[3];
+
+       /* channel model */
+       /* min_channel_count contains the minimum channel count for primary
+        * outputs.  When multi_ios is set, the channels can be configured
+        * between min_channel_count and (min_channel_count + multi_ios * 2).
+        *
+        * ext_channel_count contains the current channel count of the primary
+        * out.  This varies in the range above.
+        *
+        * Meanwhile, const_channel_count is the channel count for all outputs
+        * including headphone and speakers.  It's a constant value, and the
+        * PCM is set up as max(ext_channel_count, const_channel_count).
+        */
+       int min_channel_count;          /* min. channel count for primary out */
+       int ext_channel_count;          /* current channel count for primary */
+       int const_channel_count;        /* channel count for all */
+
+       /* PCM information */
+       struct hda_pcm *pcm_rec[3];     /* used in build_pcms() */
+
+       /* dynamic controls, init_verbs and input_mux */
+       struct auto_pin_cfg autocfg;
+       struct snd_array kctls;
+       hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
+       hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
+       unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
+       /* shared hp/mic */
+       hda_nid_t shared_mic_vref_pin;
+       hda_nid_t hp_mic_pin;
+       int hp_mic_mux_idx;
+
+       /* DAC/ADC lists */
+       int num_all_dacs;
+       hda_nid_t all_dacs[16];
+       int num_all_adcs;
+       hda_nid_t all_adcs[AUTO_CFG_MAX_INS];
+
+       /* path list */
+       struct snd_array paths;
+
+       /* path indices */
+       int out_paths[AUTO_CFG_MAX_OUTS];
+       int hp_paths[AUTO_CFG_MAX_OUTS];
+       int speaker_paths[AUTO_CFG_MAX_OUTS];
+       int aamix_out_paths[3];
+       int digout_paths[AUTO_CFG_MAX_OUTS];
+       int input_paths[HDA_MAX_NUM_INPUTS][AUTO_CFG_MAX_INS];
+       int loopback_paths[HDA_MAX_NUM_INPUTS];
+       int loopback_merge_path;
+       int digin_path;
+
+       /* auto-mic stuff */
+       int am_num_entries;
+       struct automic_entry am_entry[MAX_AUTO_MIC_PINS];
+
+       /* for pin sensing */
+       /* current status; set in hda_generic.c */
+       unsigned int hp_jack_present:1;
+       unsigned int line_jack_present:1;
+       unsigned int speaker_muted:1; /* current status of speaker mute */
+       unsigned int line_out_muted:1; /* current status of LO mute */
+
+       /* internal states of automute / autoswitch behavior */
+       unsigned int auto_mic:1;
+       unsigned int automute_speaker:1; /* automute speaker outputs */
+       unsigned int automute_lo:1; /* automute LO outputs */
+
+       /* capabilities detected by parser */
+       unsigned int detect_hp:1;       /* Headphone detection enabled */
+       unsigned int detect_lo:1;       /* Line-out detection enabled */
+       unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
+       unsigned int automute_lo_possible:1;      /* there are line outs and HP */
+
+       /* additional parameters set by codec drivers */
+       unsigned int master_mute:1;     /* master mute over all */
+       unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
+       unsigned int line_in_auto_switch:1; /* allow line-in auto switch */
+       unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */
+
+       /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */
+       unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */
+       unsigned int suppress_auto_mic:1; /* suppress input jack auto switch */
+
+       /* other parse behavior flags */
+       unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
+       unsigned int hp_mic:1; /* Allow HP as a mic-in */
+       unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
+       unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
+       unsigned int no_multi_io:1; /* Don't try multi I/O config */
+       unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
+       unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
+       unsigned int own_eapd_ctl:1; /* set EAPD by own function */
+       unsigned int keep_eapd_on:1; /* don't turn off EAPD automatically */
+       unsigned int vmaster_mute_led:1; /* add SPK-LED flag to vmaster mute switch */
+       unsigned int mic_mute_led:1; /* add MIC-LED flag to capture mute switch */
+       unsigned int indep_hp:1; /* independent HP supported */
+       unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
+       unsigned int add_stereo_mix_input:2; /* add aamix as a capture src */
+       unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
+       unsigned int power_down_unused:1; /* power down unused widgets */
+       unsigned int dac_min_mute:1; /* minimal = mute for DACs */
+       unsigned int suppress_vmaster:1; /* don't create vmaster kctls */
+
+       /* other internal flags */
+       unsigned int no_analog:1; /* digital I/O only */
+       unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
+       unsigned int indep_hp_enabled:1; /* independent HP enabled */
+       unsigned int have_aamix_ctl:1;
+       unsigned int hp_mic_jack_modes:1;
+       unsigned int skip_verbs:1; /* don't apply verbs at snd_hda_gen_init() */
+
+       /* additional mute flags (only effective with auto_mute_via_amp=1) */
+       u64 mute_bits;
+
+       /* bitmask for skipping volume controls */
+       u64 out_vol_mask;
+
+       /* badness tables for output path evaluations */
+       const struct badness_table *main_out_badness;
+       const struct badness_table *extra_out_badness;
+
+       /* preferred pin/DAC pairs; an array of paired NIDs */
+       const hda_nid_t *preferred_dacs;
+
+       /* loopback mixing mode */
+       bool aamix_mode;
+
+       /* digital beep */
+       hda_nid_t beep_nid;
+
+       /* for virtual master */
+       hda_nid_t vmaster_nid;
+       unsigned int vmaster_tlv[4];
+       struct hda_vmaster_mute_hook vmaster_mute;
+
+       struct hda_loopback_check loopback;
+       struct snd_array loopback_list;
+
+       /* multi-io */
+       int multi_ios;
+       struct hda_multi_io multi_io[4];
+
+       /* hooks */
+       void (*init_hook)(struct hda_codec *codec);
+       void (*automute_hook)(struct hda_codec *codec);
+       void (*cap_sync_hook)(struct hda_codec *codec,
+                             struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol);
+
+       /* PCM hooks */
+       void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream,
+                                 int action);
+       void (*pcm_capture_hook)(struct hda_pcm_stream *hinfo,
+                                struct hda_codec *codec,
+                                struct snd_pcm_substream *substream,
+                                int action);
+
+       /* automute / autoswitch hooks */
+       void (*hp_automute_hook)(struct hda_codec *codec,
+                                struct hda_jack_callback *cb);
+       void (*line_automute_hook)(struct hda_codec *codec,
+                                  struct hda_jack_callback *cb);
+       void (*mic_autoswitch_hook)(struct hda_codec *codec,
+                                   struct hda_jack_callback *cb);
+
+       /* leds */
+       struct led_classdev *led_cdevs[NUM_AUDIO_LEDS];
+};
+
+/* values for add_stereo_mix_input flag */
+enum {
+       HDA_HINT_STEREO_MIX_DISABLE,    /* No stereo mix input */
+       HDA_HINT_STEREO_MIX_ENABLE,     /* Add stereo mix input */
+       HDA_HINT_STEREO_MIX_AUTO,       /* Add only if auto-mic is disabled */
+};
+
+int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
+
+int snd_hda_gen_init(struct hda_codec *codec);
+void snd_hda_gen_free(struct hda_codec *codec);
+
+int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
+struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
+struct nid_path *
+snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
+                    hda_nid_t to_nid, int anchor_nid);
+void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
+                          bool enable, bool add_aamix);
+
+struct snd_kcontrol_new *
+snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
+                    const struct snd_kcontrol_new *temp);
+
+int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
+                                 struct auto_pin_cfg *cfg);
+int snd_hda_gen_build_controls(struct hda_codec *codec);
+int snd_hda_gen_build_pcms(struct hda_codec *codec);
+
+/* standard jack event callbacks */
+void snd_hda_gen_hp_automute(struct hda_codec *codec,
+                            struct hda_jack_callback *jack);
+void snd_hda_gen_line_automute(struct hda_codec *codec,
+                              struct hda_jack_callback *jack);
+void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
+                               struct hda_jack_callback *jack);
+void snd_hda_gen_update_outputs(struct hda_codec *codec);
+
+int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
+unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
+                                          hda_nid_t nid,
+                                          unsigned int power_state);
+void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on);
+int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
+
+int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
+                                 int (*callback)(struct led_classdev *,
+                                                 enum led_brightness));
+int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
+                                    int (*callback)(struct led_classdev *,
+                                                    enum led_brightness));
+bool snd_hda_gen_shutup_speakers(struct hda_codec *codec);
+
+#endif /* __SOUND_HDA_GENERIC_H */
diff --git a/sound/hda/codecs/hdmi/Makefile b/sound/hda/codecs/hdmi/Makefile
new file mode 100644 (file)
index 0000000..371818d
--- /dev/null
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-codec-hdmi-y :=                hdmi.o eld.o
+
+obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
diff --git a/sound/hda/codecs/hdmi/eld.c b/sound/hda/codecs/hdmi/eld.c
new file mode 100644 (file)
index 0000000..d3e87b9
--- /dev/null
@@ -0,0 +1,402 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Generic routines and proc interface for ELD(EDID Like Data) information
+ *
+ * Copyright(c) 2008 Intel Corporation.
+ * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
+ *
+ * Authors:
+ *             Wu Fengguang <wfg@linux.intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <linux/unaligned.h>
+#include <sound/hda_chmap.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+
+enum cea_edid_versions {
+       CEA_EDID_VER_NONE       = 0,
+       CEA_EDID_VER_CEA861     = 1,
+       CEA_EDID_VER_CEA861A    = 2,
+       CEA_EDID_VER_CEA861BCD  = 3,
+       CEA_EDID_VER_RESERVED   = 4,
+};
+
+/*
+ * The following two lists are shared between
+ *     - HDMI audio InfoFrame (source to sink)
+ *     - CEA E-EDID Extension (sink to source)
+ */
+
+static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
+                                       int byte_index)
+{
+       unsigned int val;
+
+       val = snd_hda_codec_read(codec, nid, 0,
+                                       AC_VERB_GET_HDMI_ELDD, byte_index);
+#ifdef BE_PARANOID
+       codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
+#endif
+       return val;
+}
+
+int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
+{
+       return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
+                                                AC_DIPSIZE_ELD_BUF);
+}
+
+int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
+                    unsigned char *buf, int *eld_size)
+{
+       int i;
+       int ret = 0;
+       int size;
+
+       /*
+        * ELD size is initialized to zero in caller function. If no errors and
+        * ELD is valid, actual eld_size is assigned.
+        */
+
+       size = snd_hdmi_get_eld_size(codec, nid);
+       if (size == 0) {
+               /* wfg: workaround for ASUS P5E-VM HDMI board */
+               codec_info(codec, "HDMI: ELD buf size is 0, force 128\n");
+               size = 128;
+       }
+       if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
+               codec_info(codec, "HDMI: invalid ELD buf size %d\n", size);
+               return -ERANGE;
+       }
+
+       /* set ELD buffer */
+       for (i = 0; i < size; i++) {
+               unsigned int val = hdmi_get_eld_data(codec, nid, i);
+               /*
+                * Graphics driver might be writing to ELD buffer right now.
+                * Just abort. The caller will repoll after a while.
+                */
+               if (!(val & AC_ELDD_ELD_VALID)) {
+                       codec_info(codec, "HDMI: invalid ELD data byte %d\n", i);
+                       ret = -EINVAL;
+                       goto error;
+               }
+               val &= AC_ELDD_ELD_DATA;
+               /*
+                * The first byte cannot be zero. This can happen on some DVI
+                * connections. Some Intel chips may also need some 250ms delay
+                * to return non-zero ELD data, even when the graphics driver
+                * correctly writes ELD content before setting ELD_valid bit.
+                */
+               if (!val && !i) {
+                       codec_dbg(codec, "HDMI: 0 ELD data\n");
+                       ret = -EINVAL;
+                       goto error;
+               }
+               buf[i] = val;
+       }
+
+       *eld_size = size;
+error:
+       return ret;
+}
+
+#ifdef CONFIG_SND_PROC_FS
+void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
+                            struct snd_info_buffer *buffer,
+                            hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
+{
+       snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
+       snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
+       snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid);
+       snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id);
+       snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid);
+
+       if (!eld->eld_valid)
+               return;
+
+       snd_print_eld_info(&eld->info, buffer);
+}
+
+void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
+                            struct snd_info_buffer *buffer)
+{
+       struct snd_parsed_hdmi_eld *e = &eld->info;
+       char line[64];
+       char name[64];
+       char *sname;
+       long long val;
+       unsigned int n;
+
+       while (!snd_info_get_line(buffer, line, sizeof(line))) {
+               if (sscanf(line, "%s %llx", name, &val) != 2)
+                       continue;
+               /*
+                * We don't allow modification to these fields:
+                *      monitor_name manufacture_id product_id
+                *      eld_version edid_version
+                */
+               if (!strcmp(name, "monitor_present"))
+                       eld->monitor_present = val;
+               else if (!strcmp(name, "eld_valid"))
+                       eld->eld_valid = val;
+               else if (!strcmp(name, "connection_type"))
+                       e->conn_type = val;
+               else if (!strcmp(name, "port_id"))
+                       e->port_id = val;
+               else if (!strcmp(name, "support_hdcp"))
+                       e->support_hdcp = val;
+               else if (!strcmp(name, "support_ai"))
+                       e->support_ai = val;
+               else if (!strcmp(name, "audio_sync_delay"))
+                       e->aud_synch_delay = val;
+               else if (!strcmp(name, "speakers"))
+                       e->spk_alloc = val;
+               else if (!strcmp(name, "sad_count"))
+                       e->sad_count = val;
+               else if (!strncmp(name, "sad", 3)) {
+                       sname = name + 4;
+                       n = name[3] - '0';
+                       if (name[4] >= '0' && name[4] <= '9') {
+                               sname++;
+                               n = 10 * n + name[4] - '0';
+                       }
+                       if (n >= ELD_MAX_SAD)
+                               continue;
+                       if (!strcmp(sname, "_coding_type"))
+                               e->sad[n].format = val;
+                       else if (!strcmp(sname, "_channels"))
+                               e->sad[n].channels = val;
+                       else if (!strcmp(sname, "_rates"))
+                               e->sad[n].rates = val;
+                       else if (!strcmp(sname, "_bits"))
+                               e->sad[n].sample_bits = val;
+                       else if (!strcmp(sname, "_max_bitrate"))
+                               e->sad[n].max_bitrate = val;
+                       else if (!strcmp(sname, "_profile"))
+                               e->sad[n].profile = val;
+                       if (n >= e->sad_count)
+                               e->sad_count = n + 1;
+               }
+       }
+}
+#endif /* CONFIG_SND_PROC_FS */
+
+/* update PCM info based on ELD */
+void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e,
+                             struct hda_pcm_stream *hinfo)
+{
+       u32 rates;
+       u64 formats;
+       unsigned int maxbps;
+       unsigned int channels_max;
+       int i;
+
+       /* assume basic audio support (the basic audio flag is not in ELD;
+        * however, all audio capable sinks are required to support basic
+        * audio) */
+       rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+               SNDRV_PCM_RATE_48000;
+       formats = SNDRV_PCM_FMTBIT_S16_LE;
+       maxbps = 16;
+       channels_max = 2;
+       for (i = 0; i < e->sad_count; i++) {
+               struct snd_cea_sad *a = &e->sad[i];
+               rates |= a->rates;
+               if (a->channels > channels_max)
+                       channels_max = a->channels;
+               if (a->format == AUDIO_CODING_TYPE_LPCM) {
+                       if (a->sample_bits & ELD_PCM_BITS_20) {
+                               formats |= SNDRV_PCM_FMTBIT_S32_LE;
+                               if (maxbps < 20)
+                                       maxbps = 20;
+                       }
+                       if (a->sample_bits & ELD_PCM_BITS_24) {
+                               formats |= SNDRV_PCM_FMTBIT_S32_LE;
+                               if (maxbps < 24)
+                                       maxbps = 24;
+                       }
+               }
+       }
+
+       /* restrict the parameters by the values the codec provides */
+       hinfo->rates &= rates;
+       hinfo->formats &= formats;
+       hinfo->maxbps = min(hinfo->maxbps, maxbps);
+       hinfo->channels_max = min(hinfo->channels_max, channels_max);
+}
+
+
+/* ATI/AMD specific stuff (ELD emulation) */
+
+#define ATI_VERB_SET_AUDIO_DESCRIPTOR  0x776
+#define ATI_VERB_SET_SINK_INFO_INDEX   0x780
+#define ATI_VERB_GET_SPEAKER_ALLOCATION        0xf70
+#define ATI_VERB_GET_AUDIO_DESCRIPTOR  0xf76
+#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b
+#define ATI_VERB_GET_SINK_INFO_INDEX   0xf80
+#define ATI_VERB_GET_SINK_INFO_DATA    0xf81
+
+#define ATI_SPKALLOC_SPKALLOC          0x007f
+#define ATI_SPKALLOC_TYPE_HDMI         0x0100
+#define ATI_SPKALLOC_TYPE_DISPLAYPORT  0x0200
+
+/* first three bytes are just standard SAD */
+#define ATI_AUDIODESC_CHANNELS         0x00000007
+#define ATI_AUDIODESC_RATES            0x0000ff00
+#define ATI_AUDIODESC_LPCM_STEREO_RATES        0xff000000
+
+/* in standard HDMI VSDB format */
+#define ATI_DELAY_VIDEO_LATENCY                0x000000ff
+#define ATI_DELAY_AUDIO_LATENCY                0x0000ff00
+
+enum ati_sink_info_idx {
+       ATI_INFO_IDX_MANUFACTURER_ID    = 0,
+       ATI_INFO_IDX_PRODUCT_ID         = 1,
+       ATI_INFO_IDX_SINK_DESC_LEN      = 2,
+       ATI_INFO_IDX_PORT_ID_LOW        = 3,
+       ATI_INFO_IDX_PORT_ID_HIGH       = 4,
+       ATI_INFO_IDX_SINK_DESC_FIRST    = 5,
+       ATI_INFO_IDX_SINK_DESC_LAST     = 22, /* max len 18 bytes */
+};
+
+int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
+                        unsigned char *buf, int *eld_size, bool rev3_or_later)
+{
+       int spkalloc, ati_sad, aud_synch;
+       int sink_desc_len = 0;
+       int pos, i;
+
+       /* ATI/AMD does not have ELD, emulate it */
+
+       spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
+
+       if (spkalloc <= 0) {
+               codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
+               return -EINVAL;
+       }
+
+       memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);
+
+       /* version */
+       buf[0] = ELD_VER_CEA_861D << 3;
+
+       /* speaker allocation from EDID */
+       buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;
+
+       /* is DisplayPort? */
+       if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
+               buf[5] |= 0x04;
+
+       pos = ELD_FIXED_BYTES;
+
+       if (rev3_or_later) {
+               int sink_info;
+
+               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
+               sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+               put_unaligned_le32(sink_info, buf + 8);
+
+               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
+               sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+               put_unaligned_le32(sink_info, buf + 12);
+
+               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
+               sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+               put_unaligned_le16(sink_info, buf + 16);
+
+               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
+               sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+               put_unaligned_le16(sink_info, buf + 18);
+
+               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
+               sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+
+               if (sink_desc_len > ELD_MAX_MNL) {
+                       codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
+                                  sink_desc_len);
+                       sink_desc_len = ELD_MAX_MNL;
+               }
+
+               buf[4] |= sink_desc_len;
+
+               for (i = 0; i < sink_desc_len; i++) {
+                       snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
+                       buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
+               }
+       }
+
+       for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
+               if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
+                       continue; /* not handled by ATI/AMD */
+
+               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
+               ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);
+
+               if (ati_sad <= 0)
+                       continue;
+
+               if (ati_sad & ATI_AUDIODESC_RATES) {
+                       /* format is supported, copy SAD as-is */
+                       buf[pos++] = (ati_sad & 0x0000ff) >> 0;
+                       buf[pos++] = (ati_sad & 0x00ff00) >> 8;
+                       buf[pos++] = (ati_sad & 0xff0000) >> 16;
+               }
+
+               if (i == AUDIO_CODING_TYPE_LPCM
+                   && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
+                   && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
+                       /* for PCM there is a separate stereo rate mask */
+                       buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
+                       /* rates from the extra byte */
+                       buf[pos++] = (ati_sad & 0xff000000) >> 24;
+                       buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
+               }
+       }
+
+       if (pos == ELD_FIXED_BYTES + sink_desc_len) {
+               codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
+               return -EINVAL;
+       }
+
+       /*
+        * HDMI VSDB latency format:
+        * separately for both audio and video:
+        *  0          field not valid or unknown latency
+        *  [1..251]   msecs = (x-1)*2  (max 500ms with x = 251 = 0xfb)
+        *  255        audio/video not supported
+        *
+        * HDA latency format:
+        * single value indicating video latency relative to audio:
+        *  0          unknown or 0ms
+        *  [1..250]   msecs = x*2  (max 500ms with x = 250 = 0xfa)
+        *  [251..255] reserved
+        */
+       aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
+       if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
+               int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY);
+               int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8;
+
+               if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb &&
+                   video_latency_hdmi > audio_latency_hdmi)
+                       buf[6] = video_latency_hdmi - audio_latency_hdmi;
+               /* else unknown/invalid or 0ms or video ahead of audio, so use zero */
+       }
+
+       /* SAD count */
+       buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;
+
+       /* Baseline ELD block length is 4-byte aligned */
+       pos = round_up(pos, 4);
+
+       /* Baseline ELD length (4-byte header is not counted in) */
+       buf[2] = (pos - 4) / 4;
+
+       *eld_size = pos;
+
+       return 0;
+}
diff --git a/sound/hda/codecs/hdmi/hdmi.c b/sound/hda/codecs/hdmi/hdmi.c
new file mode 100644 (file)
index 0000000..3811eb1
--- /dev/null
@@ -0,0 +1,4695 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ *  hdmi.c - routines for HDMI/DisplayPort codecs
+ *
+ *  Copyright(c) 2008-2010 Intel Corporation
+ *  Copyright (c) 2006 ATI Technologies Inc.
+ *  Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
+ *  Copyright (c) 2008 Wei Ni <wni@nvidia.com>
+ *  Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
+ *
+ *  Authors:
+ *                     Wu Fengguang <wfg@linux.intel.com>
+ *
+ *  Maintained by:
+ *                     Wu Fengguang <wfg@linux.intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/asoundef.h>
+#include <sound/tlv.h>
+#include <sound/hdaudio.h>
+#include <sound/hda_i915.h>
+#include <sound/hda_chmap.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_jack.h"
+#include "hda_controller.h"
+
+static bool static_hdmi_pcm;
+module_param(static_hdmi_pcm, bool, 0644);
+MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
+
+static bool enable_acomp = true;
+module_param(enable_acomp, bool, 0444);
+MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)");
+
+static bool enable_silent_stream =
+IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM);
+module_param(enable_silent_stream, bool, 0644);
+MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices");
+
+static bool enable_all_pins;
+module_param(enable_all_pins, bool, 0444);
+MODULE_PARM_DESC(enable_all_pins, "Forcibly enable all pins");
+
+struct hdmi_spec_per_cvt {
+       hda_nid_t cvt_nid;
+       bool assigned;          /* the stream has been assigned */
+       bool silent_stream;     /* silent stream activated */
+       unsigned int channels_min;
+       unsigned int channels_max;
+       u32 rates;
+       u64 formats;
+       unsigned int maxbps;
+};
+
+/* max. connections to a widget */
+#define HDA_MAX_CONNECTIONS    32
+
+struct hdmi_spec_per_pin {
+       hda_nid_t pin_nid;
+       int dev_id;
+       /* pin idx, different device entries on the same pin use the same idx */
+       int pin_nid_idx;
+       int num_mux_nids;
+       hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
+       int mux_idx;
+       hda_nid_t cvt_nid;
+
+       struct hda_codec *codec;
+       struct hdmi_eld sink_eld;
+       struct mutex lock;
+       struct delayed_work work;
+       struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
+       int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
+       int prev_pcm_idx; /* previously assigned pcm index */
+       int repoll_count;
+       bool setup; /* the stream has been set up by prepare callback */
+       bool silent_stream;
+       int channels; /* current number of channels */
+       bool non_pcm;
+       bool chmap_set;         /* channel-map override by ALSA API? */
+       unsigned char chmap[8]; /* ALSA API channel-map */
+#ifdef CONFIG_SND_PROC_FS
+       struct snd_info_entry *proc_entry;
+#endif
+};
+
+/* operations used by generic code that can be overridden by patches */
+struct hdmi_ops {
+       int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
+                          int dev_id, unsigned char *buf, int *eld_size);
+
+       void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
+                                   int dev_id,
+                                   int ca, int active_channels, int conn_type);
+
+       /* enable/disable HBR (HD passthrough) */
+       int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid,
+                            int dev_id, bool hbr);
+
+       int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
+                           hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+                           int format);
+
+       void (*pin_cvt_fixup)(struct hda_codec *codec,
+                             struct hdmi_spec_per_pin *per_pin,
+                             hda_nid_t cvt_nid);
+};
+
+struct hdmi_pcm {
+       struct hda_pcm *pcm;
+       struct snd_jack *jack;
+       struct snd_kcontrol *eld_ctl;
+};
+
+enum {
+       SILENT_STREAM_OFF = 0,
+       SILENT_STREAM_KAE,      /* use standard HDA Keep-Alive */
+       SILENT_STREAM_I915,     /* Intel i915 extension */
+};
+
+struct hdmi_spec {
+       struct hda_codec *codec;
+       int num_cvts;
+       struct snd_array cvts; /* struct hdmi_spec_per_cvt */
+       hda_nid_t cvt_nids[4]; /* only for haswell fix */
+
+       /*
+        * num_pins is the number of virtual pins
+        * for example, there are 3 pins, and each pin
+        * has 4 device entries, then the num_pins is 12
+        */
+       int num_pins;
+       /*
+        * num_nids is the number of real pins
+        * In the above example, num_nids is 3
+        */
+       int num_nids;
+       /*
+        * dev_num is the number of device entries
+        * on each pin.
+        * In the above example, dev_num is 4
+        */
+       int dev_num;
+       struct snd_array pins; /* struct hdmi_spec_per_pin */
+       struct hdmi_pcm pcm_rec[8];
+       struct mutex pcm_lock;
+       struct mutex bind_lock; /* for audio component binding */
+       /* pcm_bitmap means which pcms have been assigned to pins*/
+       unsigned long pcm_bitmap;
+       int pcm_used;   /* counter of pcm_rec[] */
+       /* bitmap shows whether the pcm is opened in user space
+        * bit 0 means the first playback PCM (PCM3);
+        * bit 1 means the second playback PCM, and so on.
+        */
+       unsigned long pcm_in_use;
+
+       struct hdmi_eld temp_eld;
+       struct hdmi_ops ops;
+
+       bool dyn_pin_out;
+       bool static_pcm_mapping;
+       /* hdmi interrupt trigger control flag for Nvidia codec */
+       bool hdmi_intr_trig_ctrl;
+       bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */
+
+       bool intel_hsw_fixup;   /* apply Intel platform-specific fixups */
+       /*
+        * Non-generic VIA/NVIDIA specific
+        */
+       struct hda_multi_out multiout;
+       struct hda_pcm_stream pcm_playback;
+
+       bool use_acomp_notifier; /* use eld_notify callback for hotplug */
+       bool acomp_registered; /* audio component registered in this driver */
+       bool force_connect; /* force connectivity */
+       struct drm_audio_component_audio_ops drm_audio_ops;
+       int (*port2pin)(struct hda_codec *, int); /* reverse port/pin mapping */
+
+       struct hdac_chmap chmap;
+       hda_nid_t vendor_nid;
+       const int *port_map;
+       int port_num;
+       int silent_stream_type;
+};
+
+#ifdef CONFIG_SND_HDA_COMPONENT
+static inline bool codec_has_acomp(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       return spec->use_acomp_notifier;
+}
+#else
+#define codec_has_acomp(codec) false
+#endif
+
+struct hdmi_audio_infoframe {
+       u8 type; /* 0x84 */
+       u8 ver;  /* 0x01 */
+       u8 len;  /* 0x0a */
+
+       u8 checksum;
+
+       u8 CC02_CT47;   /* CC in bits 0:2, CT in 4:7 */
+       u8 SS01_SF24;
+       u8 CXT04;
+       u8 CA;
+       u8 LFEPBL01_LSV36_DM_INH7;
+};
+
+struct dp_audio_infoframe {
+       u8 type; /* 0x84 */
+       u8 len;  /* 0x1b */
+       u8 ver;  /* 0x11 << 2 */
+
+       u8 CC02_CT47;   /* match with HDMI infoframe from this on */
+       u8 SS01_SF24;
+       u8 CXT04;
+       u8 CA;
+       u8 LFEPBL01_LSV36_DM_INH7;
+};
+
+union audio_infoframe {
+       struct hdmi_audio_infoframe hdmi;
+       struct dp_audio_infoframe dp;
+       DECLARE_FLEX_ARRAY(u8, bytes);
+};
+
+/*
+ * HDMI routines
+ */
+
+#define get_pin(spec, idx) \
+       ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
+#define get_cvt(spec, idx) \
+       ((struct hdmi_spec_per_cvt  *)snd_array_elem(&spec->cvts, idx))
+/* obtain hdmi_pcm object assigned to idx */
+#define get_hdmi_pcm(spec, idx)        (&(spec)->pcm_rec[idx])
+/* obtain hda_pcm object assigned to idx */
+#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm)
+
+static int pin_id_to_pin_index(struct hda_codec *codec,
+                              hda_nid_t pin_nid, int dev_id)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+       struct hdmi_spec_per_pin *per_pin;
+
+       /*
+        * (dev_id == -1) means it is NON-MST pin
+        * return the first virtual pin on this port
+        */
+       if (dev_id == -1)
+               dev_id = 0;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               per_pin = get_pin(spec, pin_idx);
+               if ((per_pin->pin_nid == pin_nid) &&
+                       (per_pin->dev_id == dev_id))
+                       return pin_idx;
+       }
+
+       codec_warn(codec, "HDMI: pin NID 0x%x not registered\n", pin_nid);
+       return -EINVAL;
+}
+
+static int hinfo_to_pcm_index(struct hda_codec *codec,
+                       struct hda_pcm_stream *hinfo)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pcm_idx;
+
+       for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++)
+               if (get_pcm_rec(spec, pcm_idx)->stream == hinfo)
+                       return pcm_idx;
+
+       codec_warn(codec, "HDMI: hinfo %p not tied to a PCM\n", hinfo);
+       return -EINVAL;
+}
+
+static int hinfo_to_pin_index(struct hda_codec *codec,
+                             struct hda_pcm_stream *hinfo)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin;
+       int pin_idx;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               per_pin = get_pin(spec, pin_idx);
+               if (per_pin->pcm &&
+                       per_pin->pcm->pcm->stream == hinfo)
+                       return pin_idx;
+       }
+
+       codec_dbg(codec, "HDMI: hinfo %p (pcm %d) not registered\n", hinfo,
+                 hinfo_to_pcm_index(codec, hinfo));
+       return -EINVAL;
+}
+
+static struct hdmi_spec_per_pin *pcm_idx_to_pin(struct hdmi_spec *spec,
+                                               int pcm_idx)
+{
+       int i;
+       struct hdmi_spec_per_pin *per_pin;
+
+       for (i = 0; i < spec->num_pins; i++) {
+               per_pin = get_pin(spec, i);
+               if (per_pin->pcm_idx == pcm_idx)
+                       return per_pin;
+       }
+       return NULL;
+}
+
+static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int cvt_idx;
+
+       for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
+               if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
+                       return cvt_idx;
+
+       codec_warn(codec, "HDMI: cvt NID 0x%x not registered\n", cvt_nid);
+       return -EINVAL;
+}
+
+static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin;
+       struct hdmi_eld *eld;
+       int pcm_idx;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+
+       pcm_idx = kcontrol->private_value;
+       mutex_lock(&spec->pcm_lock);
+       per_pin = pcm_idx_to_pin(spec, pcm_idx);
+       if (!per_pin) {
+               /* no pin is bound to the pcm */
+               uinfo->count = 0;
+               goto unlock;
+       }
+       eld = &per_pin->sink_eld;
+       uinfo->count = eld->eld_valid ? eld->eld_size : 0;
+
+ unlock:
+       mutex_unlock(&spec->pcm_lock);
+       return 0;
+}
+
+static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin;
+       struct hdmi_eld *eld;
+       int pcm_idx;
+       int err = 0;
+
+       pcm_idx = kcontrol->private_value;
+       mutex_lock(&spec->pcm_lock);
+       per_pin = pcm_idx_to_pin(spec, pcm_idx);
+       if (!per_pin) {
+               /* no pin is bound to the pcm */
+               memset(ucontrol->value.bytes.data, 0,
+                      ARRAY_SIZE(ucontrol->value.bytes.data));
+               goto unlock;
+       }
+
+       eld = &per_pin->sink_eld;
+       if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
+           eld->eld_size > ELD_MAX_SIZE) {
+               snd_BUG();
+               err = -EINVAL;
+               goto unlock;
+       }
+
+       memset(ucontrol->value.bytes.data, 0,
+              ARRAY_SIZE(ucontrol->value.bytes.data));
+       if (eld->eld_valid)
+               memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
+                      eld->eld_size);
+
+ unlock:
+       mutex_unlock(&spec->pcm_lock);
+       return err;
+}
+
+static const struct snd_kcontrol_new eld_bytes_ctl = {
+       .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE |
+               SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK,
+       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
+       .name = "ELD",
+       .info = hdmi_eld_ctl_info,
+       .get = hdmi_eld_ctl_get,
+};
+
+static int hdmi_create_eld_ctl(struct hda_codec *codec, int pcm_idx,
+                       int device)
+{
+       struct snd_kcontrol *kctl;
+       struct hdmi_spec *spec = codec->spec;
+       int err;
+
+       kctl = snd_ctl_new1(&eld_bytes_ctl, codec);
+       if (!kctl)
+               return -ENOMEM;
+       kctl->private_value = pcm_idx;
+       kctl->id.device = device;
+
+       /* no pin nid is associated with the kctl now
+        * tbd: associate pin nid to eld ctl later
+        */
+       err = snd_hda_ctl_add(codec, 0, kctl);
+       if (err < 0)
+               return err;
+
+       get_hdmi_pcm(spec, pcm_idx)->eld_ctl = kctl;
+       return 0;
+}
+
+#ifdef BE_PARANOID
+static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
+                               int *packet_index, int *byte_index)
+{
+       int val;
+
+       val = snd_hda_codec_read(codec, pin_nid, 0,
+                                AC_VERB_GET_HDMI_DIP_INDEX, 0);
+
+       *packet_index = val >> 5;
+       *byte_index = val & 0x1f;
+}
+#endif
+
+static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
+                               int packet_index, int byte_index)
+{
+       int val;
+
+       val = (packet_index << 5) | (byte_index & 0x1f);
+
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
+}
+
+static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
+                               unsigned char val)
+{
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
+}
+
+static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_out;
+
+       /* Unmute */
+       if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
+               snd_hda_codec_write(codec, pin_nid, 0,
+                               AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+       if (spec->dyn_pin_out)
+               /* Disable pin out until stream is active */
+               pin_out = 0;
+       else
+               /* Enable pin out: some machines with GM965 gets broken output
+                * when the pin is disabled or changed while using with HDMI
+                */
+               pin_out = PIN_OUT;
+
+       snd_hda_codec_write(codec, pin_nid, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
+}
+
+/*
+ * ELD proc files
+ */
+
+#ifdef CONFIG_SND_PROC_FS
+static void print_eld_info(struct snd_info_entry *entry,
+                          struct snd_info_buffer *buffer)
+{
+       struct hdmi_spec_per_pin *per_pin = entry->private_data;
+
+       mutex_lock(&per_pin->lock);
+       snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer, per_pin->pin_nid,
+                               per_pin->dev_id, per_pin->cvt_nid);
+       mutex_unlock(&per_pin->lock);
+}
+
+static void write_eld_info(struct snd_info_entry *entry,
+                          struct snd_info_buffer *buffer)
+{
+       struct hdmi_spec_per_pin *per_pin = entry->private_data;
+
+       mutex_lock(&per_pin->lock);
+       snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer);
+       mutex_unlock(&per_pin->lock);
+}
+
+static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
+{
+       char name[32];
+       struct hda_codec *codec = per_pin->codec;
+       struct snd_info_entry *entry;
+       int err;
+
+       snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
+       err = snd_card_proc_new(codec->card, name, &entry);
+       if (err < 0)
+               return err;
+
+       snd_info_set_text_ops(entry, per_pin, print_eld_info);
+       entry->c.text.write = write_eld_info;
+       entry->mode |= 0200;
+       per_pin->proc_entry = entry;
+
+       return 0;
+}
+
+static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
+{
+       if (!per_pin->codec->bus->shutdown) {
+               snd_info_free_entry(per_pin->proc_entry);
+               per_pin->proc_entry = NULL;
+       }
+}
+#else
+static inline int eld_proc_new(struct hdmi_spec_per_pin *per_pin,
+                              int index)
+{
+       return 0;
+}
+static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
+{
+}
+#endif
+
+/*
+ * Audio InfoFrame routines
+ */
+
+/*
+ * Enable Audio InfoFrame Transmission
+ */
+static void hdmi_start_infoframe_trans(struct hda_codec *codec,
+                                      hda_nid_t pin_nid)
+{
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+                                               AC_DIPXMIT_BEST);
+}
+
+/*
+ * Disable Audio InfoFrame Transmission
+ */
+static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
+                                     hda_nid_t pin_nid)
+{
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
+                                               AC_DIPXMIT_DISABLE);
+}
+
+static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+#ifdef CONFIG_SND_DEBUG_VERBOSE
+       int i;
+       int size;
+
+       size = snd_hdmi_get_eld_size(codec, pin_nid);
+       codec_dbg(codec, "HDMI: ELD buf size is %d\n", size);
+
+       for (i = 0; i < 8; i++) {
+               size = snd_hda_codec_read(codec, pin_nid, 0,
+                                               AC_VERB_GET_HDMI_DIP_SIZE, i);
+               codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size);
+       }
+#endif
+}
+
+static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+#ifdef BE_PARANOID
+       int i, j;
+       int size;
+       int pi, bi;
+       for (i = 0; i < 8; i++) {
+               size = snd_hda_codec_read(codec, pin_nid, 0,
+                                               AC_VERB_GET_HDMI_DIP_SIZE, i);
+               if (size == 0)
+                       continue;
+
+               hdmi_set_dip_index(codec, pin_nid, i, 0x0);
+               for (j = 1; j < 1000; j++) {
+                       hdmi_write_dip_byte(codec, pin_nid, 0x0);
+                       hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
+                       if (pi != i)
+                               codec_dbg(codec, "dip index %d: %d != %d\n",
+                                               bi, pi, i);
+                       if (bi == 0) /* byte index wrapped around */
+                               break;
+               }
+               codec_dbg(codec,
+                       "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
+                       i, size, j);
+       }
+#endif
+}
+
+static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
+{
+       u8 *bytes = (u8 *)hdmi_ai;
+       u8 sum = 0;
+       int i;
+
+       hdmi_ai->checksum = 0;
+
+       for (i = 0; i < sizeof(*hdmi_ai); i++)
+               sum += bytes[i];
+
+       hdmi_ai->checksum = -sum;
+}
+
+static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
+                                     hda_nid_t pin_nid,
+                                     u8 *dip, int size)
+{
+       int i;
+
+       hdmi_debug_dip_size(codec, pin_nid);
+       hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
+
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       for (i = 0; i < size; i++)
+               hdmi_write_dip_byte(codec, pin_nid, dip[i]);
+}
+
+static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
+                                   u8 *dip, int size)
+{
+       u8 val;
+       int i;
+
+       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
+       if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
+                                                           != AC_DIPXMIT_BEST)
+               return false;
+
+       for (i = 0; i < size; i++) {
+               val = snd_hda_codec_read(codec, pin_nid, 0,
+                                        AC_VERB_GET_HDMI_DIP_DATA, 0);
+               if (val != dip[i])
+                       return false;
+       }
+
+       return true;
+}
+
+static int hdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
+                           int dev_id, unsigned char *buf, int *eld_size)
+{
+       snd_hda_set_dev_select(codec, nid, dev_id);
+
+       return snd_hdmi_get_eld(codec, nid, buf, eld_size);
+}
+
+static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
+                                    hda_nid_t pin_nid, int dev_id,
+                                    int ca, int active_channels,
+                                    int conn_type)
+{
+       struct hdmi_spec *spec = codec->spec;
+       union audio_infoframe ai;
+
+       memset(&ai, 0, sizeof(ai));
+       if ((conn_type == 0) || /* HDMI */
+               /* Nvidia DisplayPort: Nvidia HW expects same layout as HDMI */
+               (conn_type == 1 && spec->nv_dp_workaround)) {
+               struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
+
+               if (conn_type == 0) { /* HDMI */
+                       hdmi_ai->type           = 0x84;
+                       hdmi_ai->ver            = 0x01;
+                       hdmi_ai->len            = 0x0a;
+               } else {/* Nvidia DP */
+                       hdmi_ai->type           = 0x84;
+                       hdmi_ai->ver            = 0x1b;
+                       hdmi_ai->len            = 0x11 << 2;
+               }
+               hdmi_ai->CC02_CT47      = active_channels - 1;
+               hdmi_ai->CA             = ca;
+               hdmi_checksum_audio_infoframe(hdmi_ai);
+       } else if (conn_type == 1) { /* DisplayPort */
+               struct dp_audio_infoframe *dp_ai = &ai.dp;
+
+               dp_ai->type             = 0x84;
+               dp_ai->len              = 0x1b;
+               dp_ai->ver              = 0x11 << 2;
+               dp_ai->CC02_CT47        = active_channels - 1;
+               dp_ai->CA               = ca;
+       } else {
+               codec_dbg(codec, "HDMI: unknown connection type at pin NID 0x%x\n", pin_nid);
+               return;
+       }
+
+       snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
+       /*
+        * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
+        * sizeof(*dp_ai) to avoid partial match/update problems when
+        * the user switches between HDMI/DP monitors.
+        */
+       if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
+                                       sizeof(ai))) {
+               codec_dbg(codec, "%s: pin NID=0x%x channels=%d ca=0x%02x\n",
+                         __func__, pin_nid, active_channels, ca);
+               hdmi_stop_infoframe_trans(codec, pin_nid);
+               hdmi_fill_audio_infoframe(codec, pin_nid,
+                                           ai.bytes, sizeof(ai));
+               hdmi_start_infoframe_trans(codec, pin_nid);
+       }
+}
+
+static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
+                                      struct hdmi_spec_per_pin *per_pin,
+                                      bool non_pcm)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdac_chmap *chmap = &spec->chmap;
+       hda_nid_t pin_nid = per_pin->pin_nid;
+       int dev_id = per_pin->dev_id;
+       int channels = per_pin->channels;
+       int active_channels;
+       struct hdmi_eld *eld;
+       int ca;
+
+       if (!channels)
+               return;
+
+       snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
+       /* some HW (e.g. HSW+) needs reprogramming the amp at each time */
+       if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
+               snd_hda_codec_write(codec, pin_nid, 0,
+                                           AC_VERB_SET_AMP_GAIN_MUTE,
+                                           AMP_OUT_UNMUTE);
+
+       eld = &per_pin->sink_eld;
+
+       ca = snd_hdac_channel_allocation(&codec->core,
+                       eld->info.spk_alloc, channels,
+                       per_pin->chmap_set, non_pcm, per_pin->chmap);
+
+       active_channels = snd_hdac_get_active_channels(ca);
+
+       chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid,
+                                               active_channels);
+
+       /*
+        * always configure channel mapping, it may have been changed by the
+        * user in the meantime
+        */
+       snd_hdac_setup_channel_mapping(&spec->chmap,
+                               pin_nid, non_pcm, ca, channels,
+                               per_pin->chmap, per_pin->chmap_set);
+
+       spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id,
+                                     ca, active_channels, eld->info.conn_type);
+
+       per_pin->non_pcm = non_pcm;
+}
+
+/*
+ * Unsolicited events
+ */
+
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
+
+static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
+                                     int dev_id)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
+
+       if (pin_idx < 0)
+               return;
+       mutex_lock(&spec->pcm_lock);
+       hdmi_present_sense(get_pin(spec, pin_idx), 1);
+       mutex_unlock(&spec->pcm_lock);
+}
+
+static void jack_callback(struct hda_codec *codec,
+                         struct hda_jack_callback *jack)
+{
+       /* stop polling when notification is enabled */
+       if (codec_has_acomp(codec))
+               return;
+
+       check_presence_and_report(codec, jack->nid, jack->dev_id);
+}
+
+static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res,
+                                struct hda_jack_tbl *jack)
+{
+       jack->jack_dirty = 1;
+
+       codec_dbg(codec,
+               "HDMI hot plug event: Codec=%d NID=0x%x Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
+               codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA),
+               !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
+
+       check_presence_and_report(codec, jack->nid, jack->dev_id);
+}
+
+static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
+{
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+       int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
+       int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
+
+       codec_info(codec,
+               "HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
+               codec->addr,
+               tag,
+               subtag,
+               cp_state,
+               cp_ready);
+
+       /* TODO */
+       if (cp_state) {
+               ;
+       }
+       if (cp_ready) {
+               ;
+       }
+}
+
+
+static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
+       int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
+       struct hda_jack_tbl *jack;
+
+       if (codec_has_acomp(codec))
+               return;
+
+       if (codec->dp_mst) {
+               int dev_entry =
+                       (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
+
+               jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry);
+       } else {
+               jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0);
+       }
+
+       if (!jack) {
+               codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag);
+               return;
+       }
+
+       if (subtag == 0)
+               hdmi_intrinsic_event(codec, res, jack);
+       else
+               hdmi_non_intrinsic_event(codec, res);
+}
+
+static void haswell_verify_D0(struct hda_codec *codec,
+               hda_nid_t cvt_nid, hda_nid_t nid)
+{
+       int pwr;
+
+       /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
+        * thus pins could only choose converter 0 for use. Make sure the
+        * converters are in correct power state */
+       if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
+               snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
+       if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
+                                   AC_PWRST_D0);
+               msleep(40);
+               pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
+               pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
+               codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr);
+       }
+}
+
+/*
+ * Callbacks
+ */
+
+/* HBR should be Non-PCM, 8 channels */
+#define is_hbr_format(format) \
+       ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
+
+static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
+                             int dev_id, bool hbr)
+{
+       int pinctl, new_pinctl;
+
+       if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
+               snd_hda_set_dev_select(codec, pin_nid, dev_id);
+               pinctl = snd_hda_codec_read(codec, pin_nid, 0,
+                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+               if (pinctl < 0)
+                       return hbr ? -EINVAL : 0;
+
+               new_pinctl = pinctl & ~AC_PINCTL_EPT;
+               if (hbr)
+                       new_pinctl |= AC_PINCTL_EPT_HBR;
+               else
+                       new_pinctl |= AC_PINCTL_EPT_NATIVE;
+
+               codec_dbg(codec,
+                         "hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n",
+                           pin_nid,
+                           pinctl == new_pinctl ? "" : "new-",
+                           new_pinctl);
+
+               if (pinctl != new_pinctl)
+                       snd_hda_codec_write(codec, pin_nid, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                           new_pinctl);
+       } else if (hbr)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+                             hda_nid_t pin_nid, int dev_id,
+                             u32 stream_tag, int format)
+{
+       struct hdmi_spec *spec = codec->spec;
+       unsigned int param;
+       int err;
+
+       err = spec->ops.pin_hbr_setup(codec, pin_nid, dev_id,
+                                     is_hbr_format(format));
+
+       if (err) {
+               codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n");
+               return err;
+       }
+
+       if (spec->intel_hsw_fixup) {
+
+               /*
+                * on recent platforms IEC Coding Type is required for HBR
+                * support, read current Digital Converter settings and set
+                * ICT bitfield if needed.
+                */
+               param = snd_hda_codec_read(codec, cvt_nid, 0,
+                                          AC_VERB_GET_DIGI_CONVERT_1, 0);
+
+               param = (param >> 16) & ~(AC_DIG3_ICT);
+
+               /* on recent platforms ICT mode is required for HBR support */
+               if (is_hbr_format(format))
+                       param |= 0x1;
+
+               snd_hda_codec_write(codec, cvt_nid, 0,
+                                   AC_VERB_SET_DIGI_CONVERT_3, param);
+       }
+
+       snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
+       return 0;
+}
+
+/* Try to find an available converter
+ * If pin_idx is less then zero, just try to find an available converter.
+ * Otherwise, try to find an available converter and get the cvt mux index
+ * of the pin.
+ */
+static int hdmi_choose_cvt(struct hda_codec *codec,
+                          int pin_idx, int *cvt_id,
+                          bool silent)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin;
+       struct hdmi_spec_per_cvt *per_cvt = NULL;
+       int cvt_idx, mux_idx = 0;
+
+       /* pin_idx < 0 means no pin will be bound to the converter */
+       if (pin_idx < 0)
+               per_pin = NULL;
+       else
+               per_pin = get_pin(spec, pin_idx);
+
+       if (per_pin && per_pin->silent_stream) {
+               cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
+               per_cvt = get_cvt(spec, cvt_idx);
+               if (per_cvt->assigned && !silent)
+                       return -EBUSY;
+               if (cvt_id)
+                       *cvt_id = cvt_idx;
+               return 0;
+       }
+
+       /* Dynamically assign converter to stream */
+       for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+               per_cvt = get_cvt(spec, cvt_idx);
+
+               /* Must not already be assigned */
+               if (per_cvt->assigned || per_cvt->silent_stream)
+                       continue;
+               if (per_pin == NULL)
+                       break;
+               /* Must be in pin's mux's list of converters */
+               for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
+                       if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
+                               break;
+               /* Not in mux list */
+               if (mux_idx == per_pin->num_mux_nids)
+                       continue;
+               break;
+       }
+
+       /* No free converters */
+       if (cvt_idx == spec->num_cvts)
+               return -EBUSY;
+
+       if (per_pin != NULL)
+               per_pin->mux_idx = mux_idx;
+
+       if (cvt_id)
+               *cvt_id = cvt_idx;
+
+       return 0;
+}
+
+/* Assure the pin select the right convetor */
+static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
+                       struct hdmi_spec_per_pin *per_pin)
+{
+       hda_nid_t pin_nid = per_pin->pin_nid;
+       int mux_idx, curr;
+
+       mux_idx = per_pin->mux_idx;
+       curr = snd_hda_codec_read(codec, pin_nid, 0,
+                                         AC_VERB_GET_CONNECT_SEL, 0);
+       if (curr != mux_idx)
+               snd_hda_codec_write_cache(codec, pin_nid, 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           mux_idx);
+}
+
+/* get the mux index for the converter of the pins
+ * converter's mux index is the same for all pins on Intel platform
+ */
+static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
+                       hda_nid_t cvt_nid)
+{
+       int i;
+
+       for (i = 0; i < spec->num_cvts; i++)
+               if (spec->cvt_nids[i] == cvt_nid)
+                       return i;
+       return -EINVAL;
+}
+
+/* Intel HDMI workaround to fix audio routing issue:
+ * For some Intel display codecs, pins share the same connection list.
+ * So a conveter can be selected by multiple pins and playback on any of these
+ * pins will generate sound on the external display, because audio flows from
+ * the same converter to the display pipeline. Also muting one pin may make
+ * other pins have no sound output.
+ * So this function assures that an assigned converter for a pin is not selected
+ * by any other pins.
+ */
+static void intel_not_share_assigned_cvt(struct hda_codec *codec,
+                                        hda_nid_t pin_nid,
+                                        int dev_id, int mux_idx)
+{
+       struct hdmi_spec *spec = codec->spec;
+       hda_nid_t nid;
+       int cvt_idx, curr;
+       struct hdmi_spec_per_cvt *per_cvt;
+       struct hdmi_spec_per_pin *per_pin;
+       int pin_idx;
+
+       /* configure the pins connections */
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               int dev_id_saved;
+               int dev_num;
+
+               per_pin = get_pin(spec, pin_idx);
+               /*
+                * pin not connected to monitor
+                * no need to operate on it
+                */
+               if (!per_pin->pcm)
+                       continue;
+
+               if ((per_pin->pin_nid == pin_nid) &&
+                       (per_pin->dev_id == dev_id))
+                       continue;
+
+               /*
+                * if per_pin->dev_id >= dev_num,
+                * snd_hda_get_dev_select() will fail,
+                * and the following operation is unpredictable.
+                * So skip this situation.
+                */
+               dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
+               if (per_pin->dev_id >= dev_num)
+                       continue;
+
+               nid = per_pin->pin_nid;
+
+               /*
+                * Calling this function should not impact
+                * on the device entry selection
+                * So let's save the dev id for each pin,
+                * and restore it when return
+                */
+               dev_id_saved = snd_hda_get_dev_select(codec, nid);
+               snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
+               curr = snd_hda_codec_read(codec, nid, 0,
+                                         AC_VERB_GET_CONNECT_SEL, 0);
+               if (curr != mux_idx) {
+                       snd_hda_set_dev_select(codec, nid, dev_id_saved);
+                       continue;
+               }
+
+
+               /* choose an unassigned converter. The conveters in the
+                * connection list are in the same order as in the codec.
+                */
+               for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+                       per_cvt = get_cvt(spec, cvt_idx);
+                       if (!per_cvt->assigned) {
+                               codec_dbg(codec,
+                                         "choose cvt %d for pin NID 0x%x\n",
+                                         cvt_idx, nid);
+                               snd_hda_codec_write_cache(codec, nid, 0,
+                                           AC_VERB_SET_CONNECT_SEL,
+                                           cvt_idx);
+                               break;
+                       }
+               }
+               snd_hda_set_dev_select(codec, nid, dev_id_saved);
+       }
+}
+
+/* A wrapper of intel_not_share_asigned_cvt() */
+static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
+                       hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
+{
+       int mux_idx;
+       struct hdmi_spec *spec = codec->spec;
+
+       /* On Intel platform, the mapping of converter nid to
+        * mux index of the pins are always the same.
+        * The pin nid may be 0, this means all pins will not
+        * share the converter.
+        */
+       mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
+       if (mux_idx >= 0)
+               intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
+}
+
+/* skeleton caller of pin_cvt_fixup ops */
+static void pin_cvt_fixup(struct hda_codec *codec,
+                         struct hdmi_spec_per_pin *per_pin,
+                         hda_nid_t cvt_nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (spec->ops.pin_cvt_fixup)
+               spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid);
+}
+
+/* called in hdmi_pcm_open when no pin is assigned to the PCM */
+static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
+                        struct hda_codec *codec,
+                        struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int cvt_idx, pcm_idx;
+       struct hdmi_spec_per_cvt *per_cvt = NULL;
+       int err;
+
+       pcm_idx = hinfo_to_pcm_index(codec, hinfo);
+       if (pcm_idx < 0)
+               return -EINVAL;
+
+       err = hdmi_choose_cvt(codec, -1, &cvt_idx, false);
+       if (err)
+               return err;
+
+       per_cvt = get_cvt(spec, cvt_idx);
+       per_cvt->assigned = true;
+       hinfo->nid = per_cvt->cvt_nid;
+
+       pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid);
+
+       set_bit(pcm_idx, &spec->pcm_in_use);
+       /* todo: setup spdif ctls assign */
+
+       /* Initially set the converter's capabilities */
+       hinfo->channels_min = per_cvt->channels_min;
+       hinfo->channels_max = per_cvt->channels_max;
+       hinfo->rates = per_cvt->rates;
+       hinfo->formats = per_cvt->formats;
+       hinfo->maxbps = per_cvt->maxbps;
+
+       /* Store the updated parameters */
+       runtime->hw.channels_min = hinfo->channels_min;
+       runtime->hw.channels_max = hinfo->channels_max;
+       runtime->hw.formats = hinfo->formats;
+       runtime->hw.rates = hinfo->rates;
+
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+       return 0;
+}
+
+/*
+ * HDA PCM callbacks
+ */
+static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
+                        struct hda_codec *codec,
+                        struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       int pin_idx, cvt_idx, pcm_idx;
+       struct hdmi_spec_per_pin *per_pin;
+       struct hdmi_eld *eld;
+       struct hdmi_spec_per_cvt *per_cvt = NULL;
+       int err;
+
+       /* Validate hinfo */
+       pcm_idx = hinfo_to_pcm_index(codec, hinfo);
+       if (pcm_idx < 0)
+               return -EINVAL;
+
+       mutex_lock(&spec->pcm_lock);
+       pin_idx = hinfo_to_pin_index(codec, hinfo);
+       /* no pin is assigned to the PCM
+        * PA need pcm open successfully when probe
+        */
+       if (pin_idx < 0) {
+               err = hdmi_pcm_open_no_pin(hinfo, codec, substream);
+               goto unlock;
+       }
+
+       err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, false);
+       if (err < 0)
+               goto unlock;
+
+       per_cvt = get_cvt(spec, cvt_idx);
+       /* Claim converter */
+       per_cvt->assigned = true;
+
+       set_bit(pcm_idx, &spec->pcm_in_use);
+       per_pin = get_pin(spec, pin_idx);
+       per_pin->cvt_nid = per_cvt->cvt_nid;
+       hinfo->nid = per_cvt->cvt_nid;
+
+       /* flip stripe flag for the assigned stream if supported */
+       if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE)
+               azx_stream(get_azx_dev(substream))->stripe = 1;
+
+       snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
+       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+                           AC_VERB_SET_CONNECT_SEL,
+                           per_pin->mux_idx);
+
+       /* configure unused pins to choose other converters */
+       pin_cvt_fixup(codec, per_pin, 0);
+
+       snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid);
+
+       /* Initially set the converter's capabilities */
+       hinfo->channels_min = per_cvt->channels_min;
+       hinfo->channels_max = per_cvt->channels_max;
+       hinfo->rates = per_cvt->rates;
+       hinfo->formats = per_cvt->formats;
+       hinfo->maxbps = per_cvt->maxbps;
+
+       eld = &per_pin->sink_eld;
+       /* Restrict capabilities by ELD if this isn't disabled */
+       if (!static_hdmi_pcm && eld->eld_valid) {
+               snd_hdmi_eld_update_pcm_info(&eld->info, hinfo);
+               if (hinfo->channels_min > hinfo->channels_max ||
+                   !hinfo->rates || !hinfo->formats) {
+                       per_cvt->assigned = false;
+                       hinfo->nid = 0;
+                       snd_hda_spdif_ctls_unassign(codec, pcm_idx);
+                       err = -ENODEV;
+                       goto unlock;
+               }
+       }
+
+       /* Store the updated parameters */
+       runtime->hw.channels_min = hinfo->channels_min;
+       runtime->hw.channels_max = hinfo->channels_max;
+       runtime->hw.formats = hinfo->formats;
+       runtime->hw.rates = hinfo->rates;
+
+       snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+ unlock:
+       mutex_unlock(&spec->pcm_lock);
+       return err;
+}
+
+/*
+ * HDA/HDMI auto parsing
+ */
+static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+       hda_nid_t pin_nid = per_pin->pin_nid;
+       int dev_id = per_pin->dev_id;
+       int conns;
+
+       if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
+               codec_warn(codec,
+                          "HDMI: pin NID 0x%x wcaps %#x does not support connection list\n",
+                          pin_nid, get_wcaps(codec, pin_nid));
+               return -EINVAL;
+       }
+
+       snd_hda_set_dev_select(codec, pin_nid, dev_id);
+
+       if (spec->intel_hsw_fixup) {
+               conns = spec->num_cvts;
+               memcpy(per_pin->mux_nids, spec->cvt_nids,
+                      sizeof(hda_nid_t) * conns);
+       } else {
+               conns = snd_hda_get_raw_connections(codec, pin_nid,
+                                                   per_pin->mux_nids,
+                                                   HDA_MAX_CONNECTIONS);
+       }
+
+       /* all the device entries on the same pin have the same conn list */
+       per_pin->num_mux_nids = conns;
+
+       return 0;
+}
+
+static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
+                             struct hdmi_spec_per_pin *per_pin)
+{
+       int i;
+
+       for (i = 0; i < spec->pcm_used; i++) {
+               if (!test_bit(i, &spec->pcm_bitmap))
+                       return i;
+       }
+       return -EBUSY;
+}
+
+static void hdmi_attach_hda_pcm(struct hdmi_spec *spec,
+                               struct hdmi_spec_per_pin *per_pin)
+{
+       int idx;
+
+       /* pcm already be attached to the pin */
+       if (per_pin->pcm)
+               return;
+       /* try the previously used slot at first */
+       idx = per_pin->prev_pcm_idx;
+       if (idx >= 0) {
+               if (!test_bit(idx, &spec->pcm_bitmap))
+                       goto found;
+               per_pin->prev_pcm_idx = -1; /* no longer valid, clear it */
+       }
+       idx = hdmi_find_pcm_slot(spec, per_pin);
+       if (idx == -EBUSY)
+               return;
+ found:
+       per_pin->pcm_idx = idx;
+       per_pin->pcm = get_hdmi_pcm(spec, idx);
+       set_bit(idx, &spec->pcm_bitmap);
+}
+
+static void hdmi_detach_hda_pcm(struct hdmi_spec *spec,
+                               struct hdmi_spec_per_pin *per_pin)
+{
+       int idx;
+
+       /* pcm already be detached from the pin */
+       if (!per_pin->pcm)
+               return;
+       idx = per_pin->pcm_idx;
+       per_pin->pcm_idx = -1;
+       per_pin->prev_pcm_idx = idx; /* remember the previous index */
+       per_pin->pcm = NULL;
+       if (idx >= 0 && idx < spec->pcm_used)
+               clear_bit(idx, &spec->pcm_bitmap);
+}
+
+static int hdmi_get_pin_cvt_mux(struct hdmi_spec *spec,
+               struct hdmi_spec_per_pin *per_pin, hda_nid_t cvt_nid)
+{
+       int mux_idx;
+
+       for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
+               if (per_pin->mux_nids[mux_idx] == cvt_nid)
+                       break;
+       return mux_idx;
+}
+
+static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid);
+
+static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
+                          struct hdmi_spec_per_pin *per_pin)
+{
+       struct hda_codec *codec = per_pin->codec;
+       struct hda_pcm *pcm;
+       struct hda_pcm_stream *hinfo;
+       struct snd_pcm_substream *substream;
+       int mux_idx;
+       bool non_pcm;
+
+       if (per_pin->pcm_idx < 0 || per_pin->pcm_idx >= spec->pcm_used)
+               return;
+       pcm = get_pcm_rec(spec, per_pin->pcm_idx);
+       if (!pcm->pcm)
+               return;
+       if (!test_bit(per_pin->pcm_idx, &spec->pcm_in_use))
+               return;
+
+       /* hdmi audio only uses playback and one substream */
+       hinfo = pcm->stream;
+       substream = pcm->pcm->streams[0].substream;
+
+       per_pin->cvt_nid = hinfo->nid;
+
+       mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
+       if (mux_idx < per_pin->num_mux_nids) {
+               snd_hda_set_dev_select(codec, per_pin->pin_nid,
+                                  per_pin->dev_id);
+               snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+                               AC_VERB_SET_CONNECT_SEL,
+                               mux_idx);
+       }
+       snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
+
+       non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
+       if (substream->runtime)
+               per_pin->channels = substream->runtime->channels;
+       per_pin->setup = true;
+       per_pin->mux_idx = mux_idx;
+
+       hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
+}
+
+static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
+                          struct hdmi_spec_per_pin *per_pin)
+{
+       if (per_pin->pcm_idx >= 0 && per_pin->pcm_idx < spec->pcm_used)
+               snd_hda_spdif_ctls_unassign(per_pin->codec, per_pin->pcm_idx);
+
+       per_pin->chmap_set = false;
+       memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
+
+       per_pin->setup = false;
+       per_pin->channels = 0;
+}
+
+static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
+                                           struct hdmi_spec_per_pin *per_pin)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (per_pin->pcm_idx >= 0)
+               return spec->pcm_rec[per_pin->pcm_idx].jack;
+       else
+               return NULL;
+}
+
+/* update per_pin ELD from the given new ELD;
+ * setup info frame and notification accordingly
+ * also notify ELD kctl and report jack status changes
+ */
+static void update_eld(struct hda_codec *codec,
+                      struct hdmi_spec_per_pin *per_pin,
+                      struct hdmi_eld *eld,
+                      int repoll)
+{
+       struct hdmi_eld *pin_eld = &per_pin->sink_eld;
+       struct hdmi_spec *spec = codec->spec;
+       struct snd_jack *pcm_jack;
+       bool old_eld_valid = pin_eld->eld_valid;
+       bool eld_changed;
+       int pcm_idx;
+
+       if (eld->eld_valid) {
+               if (eld->eld_size <= 0 ||
+                   snd_parse_eld(hda_codec_dev(codec), &eld->info,
+                                 eld->eld_buffer, eld->eld_size) < 0) {
+                       eld->eld_valid = false;
+                       if (repoll) {
+                               schedule_delayed_work(&per_pin->work,
+                                                     msecs_to_jiffies(300));
+                               return;
+                       }
+               }
+       }
+
+       if (!eld->eld_valid || eld->eld_size <= 0 || eld->info.sad_count <= 0) {
+               eld->eld_valid = false;
+               eld->eld_size = 0;
+       }
+
+       /* for monitor disconnection, save pcm_idx firstly */
+       pcm_idx = per_pin->pcm_idx;
+
+       /*
+        * pcm_idx >=0 before update_eld() means it is in monitor
+        * disconnected event. Jack must be fetched before update_eld().
+        */
+       pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
+
+       if (!spec->static_pcm_mapping) {
+               if (eld->eld_valid) {
+                       hdmi_attach_hda_pcm(spec, per_pin);
+                       hdmi_pcm_setup_pin(spec, per_pin);
+               } else {
+                       hdmi_pcm_reset_pin(spec, per_pin);
+                       hdmi_detach_hda_pcm(spec, per_pin);
+               }
+       }
+
+       /* if pcm_idx == -1, it means this is in monitor connection event
+        * we can get the correct pcm_idx now.
+        */
+       if (pcm_idx == -1)
+               pcm_idx = per_pin->pcm_idx;
+       if (!pcm_jack)
+               pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
+
+       if (eld->eld_valid)
+               snd_show_eld(hda_codec_dev(codec), &eld->info);
+
+       eld_changed = (pin_eld->eld_valid != eld->eld_valid);
+       eld_changed |= (pin_eld->monitor_present != eld->monitor_present);
+       if (!eld_changed && eld->eld_valid && pin_eld->eld_valid)
+               if (pin_eld->eld_size != eld->eld_size ||
+                   memcmp(pin_eld->eld_buffer, eld->eld_buffer,
+                          eld->eld_size) != 0)
+                       eld_changed = true;
+
+       if (eld_changed) {
+               pin_eld->monitor_present = eld->monitor_present;
+               pin_eld->eld_valid = eld->eld_valid;
+               pin_eld->eld_size = eld->eld_size;
+               if (eld->eld_valid)
+                       memcpy(pin_eld->eld_buffer, eld->eld_buffer,
+                              eld->eld_size);
+               pin_eld->info = eld->info;
+       }
+
+       /*
+        * Re-setup pin and infoframe. This is needed e.g. when
+        * - sink is first plugged-in
+        * - transcoder can change during stream playback on Haswell
+        *   and this can make HW reset converter selection on a pin.
+        */
+       if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
+               pin_cvt_fixup(codec, per_pin, 0);
+               hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+       }
+
+       if (eld_changed && pcm_idx >= 0)
+               snd_ctl_notify(codec->card,
+                              SNDRV_CTL_EVENT_MASK_VALUE |
+                              SNDRV_CTL_EVENT_MASK_INFO,
+                              &get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
+
+       if (eld_changed && pcm_jack)
+               snd_jack_report(pcm_jack,
+                               (eld->monitor_present && eld->eld_valid) ?
+                               SND_JACK_AVOUT : 0);
+}
+
+/* update ELD and jack state via HD-audio verbs */
+static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
+                                        int repoll)
+{
+       struct hda_codec *codec = per_pin->codec;
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_eld *eld = &spec->temp_eld;
+       struct device *dev = hda_codec_dev(codec);
+       hda_nid_t pin_nid = per_pin->pin_nid;
+       int dev_id = per_pin->dev_id;
+       /*
+        * Always execute a GetPinSense verb here, even when called from
+        * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
+        * response's PD bit is not the real PD value, but indicates that
+        * the real PD value changed. An older version of the HD-audio
+        * specification worked this way. Hence, we just ignore the data in
+        * the unsolicited response to avoid custom WARs.
+        */
+       int present;
+       int ret;
+
+#ifdef CONFIG_PM
+       if (dev->power.runtime_status == RPM_SUSPENDING)
+               return;
+#endif
+
+       ret = snd_hda_power_up_pm(codec);
+       if (ret < 0 && pm_runtime_suspended(dev))
+               goto out;
+
+       present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
+
+       mutex_lock(&per_pin->lock);
+       eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
+       if (eld->monitor_present)
+               eld->eld_valid  = !!(present & AC_PINSENSE_ELDV);
+       else
+               eld->eld_valid = false;
+
+       codec_dbg(codec,
+               "HDMI status: Codec=%d NID=0x%x Presence_Detect=%d ELD_Valid=%d\n",
+               codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
+
+       if (eld->eld_valid) {
+               if (spec->ops.pin_get_eld(codec, pin_nid, dev_id,
+                                         eld->eld_buffer, &eld->eld_size) < 0)
+                       eld->eld_valid = false;
+       }
+
+       update_eld(codec, per_pin, eld, repoll);
+       mutex_unlock(&per_pin->lock);
+ out:
+       snd_hda_power_down_pm(codec);
+}
+
+#define I915_SILENT_RATE               48000
+#define I915_SILENT_CHANNELS           2
+#define I915_SILENT_FORMAT_BITS        16
+#define I915_SILENT_FMT_MASK           0xf
+
+static void silent_stream_enable_i915(struct hda_codec *codec,
+                                     struct hdmi_spec_per_pin *per_pin)
+{
+       unsigned int format;
+
+       snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
+                                per_pin->dev_id, I915_SILENT_RATE);
+
+       /* trigger silent stream generation in hw */
+       format = snd_hdac_stream_format(I915_SILENT_CHANNELS, I915_SILENT_FORMAT_BITS,
+                                       I915_SILENT_RATE);
+       snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
+                                  I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
+       usleep_range(100, 200);
+       snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
+
+       per_pin->channels = I915_SILENT_CHANNELS;
+       hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+}
+
+static void silent_stream_set_kae(struct hda_codec *codec,
+                                 struct hdmi_spec_per_pin *per_pin,
+                                 bool enable)
+{
+       unsigned int param;
+
+       codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid);
+
+       param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
+       param = (param >> 16) & 0xff;
+
+       if (enable)
+               param |= AC_DIG3_KAE;
+       else
+               param &= ~AC_DIG3_KAE;
+
+       snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param);
+}
+
+static void silent_stream_enable(struct hda_codec *codec,
+                                struct hdmi_spec_per_pin *per_pin)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_cvt *per_cvt;
+       int cvt_idx, pin_idx, err;
+       int keep_power = 0;
+
+       /*
+        * Power-up will call hdmi_present_sense, so the PM calls
+        * have to be done without mutex held.
+        */
+
+       err = snd_hda_power_up_pm(codec);
+       if (err < 0 && err != -EACCES) {
+               codec_err(codec,
+                         "Failed to power up codec for silent stream enable ret=[%d]\n", err);
+               snd_hda_power_down_pm(codec);
+               return;
+       }
+
+       mutex_lock(&per_pin->lock);
+
+       if (per_pin->setup) {
+               codec_dbg(codec, "hdmi: PCM already open, no silent stream\n");
+               err = -EBUSY;
+               goto unlock_out;
+       }
+
+       pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id);
+       err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, true);
+       if (err) {
+               codec_err(codec, "hdmi: no free converter to enable silent mode\n");
+               goto unlock_out;
+       }
+
+       per_cvt = get_cvt(spec, cvt_idx);
+       per_cvt->silent_stream = true;
+       per_pin->cvt_nid = per_cvt->cvt_nid;
+       per_pin->silent_stream = true;
+
+       codec_dbg(codec, "hdmi: enabling silent stream pin-NID=0x%x cvt-NID=0x%x\n",
+                 per_pin->pin_nid, per_cvt->cvt_nid);
+
+       snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
+       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+                                 AC_VERB_SET_CONNECT_SEL,
+                                 per_pin->mux_idx);
+
+       /* configure unused pins to choose other converters */
+       pin_cvt_fixup(codec, per_pin, 0);
+
+       switch (spec->silent_stream_type) {
+       case SILENT_STREAM_KAE:
+               silent_stream_enable_i915(codec, per_pin);
+               silent_stream_set_kae(codec, per_pin, true);
+               break;
+       case SILENT_STREAM_I915:
+               silent_stream_enable_i915(codec, per_pin);
+               keep_power = 1;
+               break;
+       default:
+               break;
+       }
+
+ unlock_out:
+       mutex_unlock(&per_pin->lock);
+
+       if (err || !keep_power)
+               snd_hda_power_down_pm(codec);
+}
+
+static void silent_stream_disable(struct hda_codec *codec,
+                                 struct hdmi_spec_per_pin *per_pin)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_cvt *per_cvt;
+       int cvt_idx, err;
+
+       err = snd_hda_power_up_pm(codec);
+       if (err < 0 && err != -EACCES) {
+               codec_err(codec,
+                         "Failed to power up codec for silent stream disable ret=[%d]\n",
+                         err);
+               snd_hda_power_down_pm(codec);
+               return;
+       }
+
+       mutex_lock(&per_pin->lock);
+       if (!per_pin->silent_stream)
+               goto unlock_out;
+
+       codec_dbg(codec, "HDMI: disable silent stream on pin-NID=0x%x cvt-NID=0x%x\n",
+                 per_pin->pin_nid, per_pin->cvt_nid);
+
+       cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
+       if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) {
+               per_cvt = get_cvt(spec, cvt_idx);
+               per_cvt->silent_stream = false;
+       }
+
+       if (spec->silent_stream_type == SILENT_STREAM_I915) {
+               /* release ref taken in silent_stream_enable() */
+               snd_hda_power_down_pm(codec);
+       } else if (spec->silent_stream_type == SILENT_STREAM_KAE) {
+               silent_stream_set_kae(codec, per_pin, false);
+       }
+
+       per_pin->cvt_nid = 0;
+       per_pin->silent_stream = false;
+
+ unlock_out:
+       mutex_unlock(&per_pin->lock);
+
+       snd_hda_power_down_pm(codec);
+}
+
+/* update ELD and jack state via audio component */
+static void sync_eld_via_acomp(struct hda_codec *codec,
+                              struct hdmi_spec_per_pin *per_pin)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_eld *eld = &spec->temp_eld;
+       bool monitor_prev, monitor_next;
+
+       mutex_lock(&per_pin->lock);
+       eld->monitor_present = false;
+       monitor_prev = per_pin->sink_eld.monitor_present;
+       eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
+                                     per_pin->dev_id, &eld->monitor_present,
+                                     eld->eld_buffer, ELD_MAX_SIZE);
+       eld->eld_valid = (eld->eld_size > 0);
+       update_eld(codec, per_pin, eld, 0);
+       monitor_next = per_pin->sink_eld.monitor_present;
+       mutex_unlock(&per_pin->lock);
+
+       if (spec->silent_stream_type) {
+               if (!monitor_prev && monitor_next)
+                       silent_stream_enable(codec, per_pin);
+               else if (monitor_prev && !monitor_next)
+                       silent_stream_disable(codec, per_pin);
+       }
+}
+
+static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
+{
+       struct hda_codec *codec = per_pin->codec;
+
+       if (!codec_has_acomp(codec))
+               hdmi_present_sense_via_verbs(per_pin, repoll);
+       else
+               sync_eld_via_acomp(codec, per_pin);
+}
+
+static void hdmi_repoll_eld(struct work_struct *work)
+{
+       struct hdmi_spec_per_pin *per_pin =
+       container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
+       struct hda_codec *codec = per_pin->codec;
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_jack_tbl *jack;
+
+       jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
+                                       per_pin->dev_id);
+       if (jack)
+               jack->jack_dirty = 1;
+
+       if (per_pin->repoll_count++ > 6)
+               per_pin->repoll_count = 0;
+
+       mutex_lock(&spec->pcm_lock);
+       hdmi_present_sense(per_pin, per_pin->repoll_count);
+       mutex_unlock(&spec->pcm_lock);
+}
+
+static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+       unsigned int caps, config;
+       int pin_idx;
+       struct hdmi_spec_per_pin *per_pin;
+       int err;
+       int dev_num, i;
+
+       caps = snd_hda_query_pin_caps(codec, pin_nid);
+       if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
+               return 0;
+
+       /*
+        * For DP MST audio, Configuration Default is the same for
+        * all device entries on the same pin
+        */
+       config = snd_hda_codec_get_pincfg(codec, pin_nid);
+       if (get_defcfg_connect(config) == AC_JACK_PORT_NONE &&
+           !spec->force_connect)
+               return 0;
+
+       /*
+        * To simplify the implementation, malloc all
+        * the virtual pins in the initialization statically
+        */
+       if (spec->intel_hsw_fixup) {
+               /*
+                * On Intel platforms, device entries count returned
+                * by AC_PAR_DEVLIST_LEN is dynamic, and depends on
+                * the type of receiver that is connected. Allocate pin
+                * structures based on worst case.
+                */
+               dev_num = spec->dev_num;
+       } else if (codec->dp_mst) {
+               dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
+               /*
+                * spec->dev_num is the maxinum number of device entries
+                * among all the pins
+                */
+               spec->dev_num = (spec->dev_num > dev_num) ?
+                       spec->dev_num : dev_num;
+       } else {
+               /*
+                * If the platform doesn't support DP MST,
+                * manually set dev_num to 1. This means
+                * the pin has only one device entry.
+                */
+               dev_num = 1;
+               spec->dev_num = 1;
+       }
+
+       for (i = 0; i < dev_num; i++) {
+               pin_idx = spec->num_pins;
+               per_pin = snd_array_new(&spec->pins);
+
+               if (!per_pin)
+                       return -ENOMEM;
+
+               per_pin->pcm = NULL;
+               per_pin->pcm_idx = -1;
+               per_pin->prev_pcm_idx = -1;
+               per_pin->pin_nid = pin_nid;
+               per_pin->pin_nid_idx = spec->num_nids;
+               per_pin->dev_id = i;
+               per_pin->non_pcm = false;
+               snd_hda_set_dev_select(codec, pin_nid, i);
+               err = hdmi_read_pin_conn(codec, pin_idx);
+               if (err < 0)
+                       return err;
+               if (!is_jack_detectable(codec, pin_nid))
+                       codec_warn(codec, "HDMI: pin NID 0x%x - jack not detectable\n", pin_nid);
+               spec->num_pins++;
+       }
+       spec->num_nids++;
+
+       return 0;
+}
+
+static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_cvt *per_cvt;
+       unsigned int chans;
+       int err;
+
+       chans = get_wcaps(codec, cvt_nid);
+       chans = get_wcaps_channels(chans);
+
+       per_cvt = snd_array_new(&spec->cvts);
+       if (!per_cvt)
+               return -ENOMEM;
+
+       per_cvt->cvt_nid = cvt_nid;
+       per_cvt->channels_min = 2;
+       if (chans <= 16) {
+               per_cvt->channels_max = chans;
+               if (chans > spec->chmap.channels_max)
+                       spec->chmap.channels_max = chans;
+       }
+
+       err = snd_hda_query_supported_pcm(codec, cvt_nid,
+                                         &per_cvt->rates,
+                                         &per_cvt->formats,
+                                         NULL,
+                                         &per_cvt->maxbps);
+       if (err < 0)
+               return err;
+
+       if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids))
+               spec->cvt_nids[spec->num_cvts] = cvt_nid;
+       spec->num_cvts++;
+
+       return 0;
+}
+
+static const struct snd_pci_quirk force_connect_list[] = {
+       SND_PCI_QUIRK(0x103c, 0x83e2, "HP EliteDesk 800 G4", 1),
+       SND_PCI_QUIRK(0x103c, 0x83ef, "HP MP9 G4 Retail System AMS", 1),
+       SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
+       SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
+       SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
+       SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
+       SND_PCI_QUIRK(0x1043, 0x86ae, "ASUS", 1),  /* Z170 PRO */
+       SND_PCI_QUIRK(0x1043, 0x86c7, "ASUS", 1),  /* Z170M PLUS */
+       SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
+       SND_PCI_QUIRK(0x8086, 0x2060, "Intel NUC5CPYB", 1),
+       SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
+       {}
+};
+
+static int hdmi_parse_codec(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       hda_nid_t start_nid;
+       unsigned int caps;
+       int i, nodes;
+       const struct snd_pci_quirk *q;
+
+       nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &start_nid);
+       if (!start_nid || nodes < 0) {
+               codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
+               return -EINVAL;
+       }
+
+       if (enable_all_pins)
+               spec->force_connect = true;
+
+       q = snd_pci_quirk_lookup(codec->bus->pci, force_connect_list);
+
+       if (q && q->value)
+               spec->force_connect = true;
+
+       /*
+        * hdmi_add_pin() assumes total amount of converters to
+        * be known, so first discover all converters
+        */
+       for (i = 0; i < nodes; i++) {
+               hda_nid_t nid = start_nid + i;
+
+               caps = get_wcaps(codec, nid);
+
+               if (!(caps & AC_WCAP_DIGITAL))
+                       continue;
+
+               if (get_wcaps_type(caps) == AC_WID_AUD_OUT)
+                       hdmi_add_cvt(codec, nid);
+       }
+
+       /* discover audio pins */
+       for (i = 0; i < nodes; i++) {
+               hda_nid_t nid = start_nid + i;
+
+               caps = get_wcaps(codec, nid);
+
+               if (!(caps & AC_WCAP_DIGITAL))
+                       continue;
+
+               if (get_wcaps_type(caps) == AC_WID_PIN)
+                       hdmi_add_pin(codec, nid);
+       }
+
+       return 0;
+}
+
+/*
+ */
+static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
+{
+       struct hda_spdif_out *spdif;
+       bool non_pcm;
+
+       mutex_lock(&codec->spdif_mutex);
+       spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
+       /* Add sanity check to pass klockwork check.
+        * This should never happen.
+        */
+       if (WARN_ON(spdif == NULL)) {
+               mutex_unlock(&codec->spdif_mutex);
+               return true;
+       }
+       non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO);
+       mutex_unlock(&codec->spdif_mutex);
+       return non_pcm;
+}
+
+/*
+ * HDMI callbacks
+ */
+
+static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                          struct hda_codec *codec,
+                                          unsigned int stream_tag,
+                                          unsigned int format,
+                                          struct snd_pcm_substream *substream)
+{
+       hda_nid_t cvt_nid = hinfo->nid;
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+       struct hdmi_spec_per_pin *per_pin;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       bool non_pcm;
+       int pinctl, stripe;
+       int err = 0;
+
+       mutex_lock(&spec->pcm_lock);
+       pin_idx = hinfo_to_pin_index(codec, hinfo);
+       if (pin_idx < 0) {
+               /* when pcm is not bound to a pin skip pin setup and return 0
+                * to make audio playback be ongoing
+                */
+               pin_cvt_fixup(codec, NULL, cvt_nid);
+               snd_hda_codec_setup_stream(codec, cvt_nid,
+                                       stream_tag, 0, format);
+               goto unlock;
+       }
+
+       per_pin = get_pin(spec, pin_idx);
+
+       /* Verify pin:cvt selections to avoid silent audio after S3.
+        * After S3, the audio driver restores pin:cvt selections
+        * but this can happen before gfx is ready and such selection
+        * is overlooked by HW. Thus multiple pins can share a same
+        * default convertor and mute control will affect each other,
+        * which can cause a resumed audio playback become silent
+        * after S3.
+        */
+       pin_cvt_fixup(codec, per_pin, 0);
+
+       /* Call sync_audio_rate to set the N/CTS/M manually if necessary */
+       /* Todo: add DP1.2 MST audio support later */
+       if (codec_has_acomp(codec))
+               snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
+                                        per_pin->dev_id, runtime->rate);
+
+       non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
+       mutex_lock(&per_pin->lock);
+       per_pin->channels = substream->runtime->channels;
+       per_pin->setup = true;
+
+       if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) {
+               stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core,
+                                                       substream);
+               snd_hda_codec_write(codec, cvt_nid, 0,
+                                   AC_VERB_SET_STRIPE_CONTROL,
+                                   stripe);
+       }
+
+       hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
+       mutex_unlock(&per_pin->lock);
+       if (spec->dyn_pin_out) {
+               snd_hda_set_dev_select(codec, per_pin->pin_nid,
+                                      per_pin->dev_id);
+               pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   pinctl | PIN_OUT);
+       }
+
+       /* snd_hda_set_dev_select() has been called before */
+       err = spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid,
+                                    per_pin->dev_id, stream_tag, format);
+ unlock:
+       mutex_unlock(&spec->pcm_lock);
+       return err;
+}
+
+static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                            struct hda_codec *codec,
+                                            struct snd_pcm_substream *substream)
+{
+       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
+       return 0;
+}
+
+static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
+                         struct hda_codec *codec,
+                         struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int cvt_idx, pin_idx, pcm_idx;
+       struct hdmi_spec_per_cvt *per_cvt;
+       struct hdmi_spec_per_pin *per_pin;
+       int pinctl;
+       int err = 0;
+
+       mutex_lock(&spec->pcm_lock);
+       if (hinfo->nid) {
+               pcm_idx = hinfo_to_pcm_index(codec, hinfo);
+               if (snd_BUG_ON(pcm_idx < 0)) {
+                       err = -EINVAL;
+                       goto unlock;
+               }
+               cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid);
+               if (snd_BUG_ON(cvt_idx < 0)) {
+                       err = -EINVAL;
+                       goto unlock;
+               }
+               per_cvt = get_cvt(spec, cvt_idx);
+               per_cvt->assigned = false;
+               hinfo->nid = 0;
+
+               azx_stream(get_azx_dev(substream))->stripe = 0;
+
+               snd_hda_spdif_ctls_unassign(codec, pcm_idx);
+               clear_bit(pcm_idx, &spec->pcm_in_use);
+               pin_idx = hinfo_to_pin_index(codec, hinfo);
+               /*
+                * In such a case, return 0 to match the behavior in
+                * hdmi_pcm_open()
+                */
+               if (pin_idx < 0)
+                       goto unlock;
+
+               per_pin = get_pin(spec, pin_idx);
+
+               if (spec->dyn_pin_out) {
+                       snd_hda_set_dev_select(codec, per_pin->pin_nid,
+                                              per_pin->dev_id);
+                       pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                           pinctl & ~PIN_OUT);
+               }
+
+               mutex_lock(&per_pin->lock);
+               per_pin->chmap_set = false;
+               memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
+
+               per_pin->setup = false;
+               per_pin->channels = 0;
+               mutex_unlock(&per_pin->lock);
+       }
+
+unlock:
+       mutex_unlock(&spec->pcm_lock);
+
+       return err;
+}
+
+static const struct hda_pcm_ops generic_ops = {
+       .open = hdmi_pcm_open,
+       .close = hdmi_pcm_close,
+       .prepare = generic_hdmi_playback_pcm_prepare,
+       .cleanup = generic_hdmi_playback_pcm_cleanup,
+};
+
+static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
+{
+       struct hda_codec *codec = hdac_to_hda_codec(hdac);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+       if (!per_pin)
+               return 0;
+
+       return per_pin->sink_eld.info.spk_alloc;
+}
+
+static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
+                                       unsigned char *chmap)
+{
+       struct hda_codec *codec = hdac_to_hda_codec(hdac);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+       /* chmap is already set to 0 in caller */
+       if (!per_pin)
+               return;
+
+       memcpy(chmap, per_pin->chmap, ARRAY_SIZE(per_pin->chmap));
+}
+
+static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
+                               unsigned char *chmap, int prepared)
+{
+       struct hda_codec *codec = hdac_to_hda_codec(hdac);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+       if (!per_pin)
+               return;
+       mutex_lock(&per_pin->lock);
+       per_pin->chmap_set = true;
+       memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap));
+       if (prepared)
+               hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
+       mutex_unlock(&per_pin->lock);
+}
+
+static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
+{
+       struct hda_codec *codec = hdac_to_hda_codec(hdac);
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
+
+       return per_pin ? true:false;
+}
+
+static int generic_hdmi_build_pcms(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int idx, pcm_num;
+
+       /* limit the PCM devices to the codec converters or available PINs */
+       pcm_num = min(spec->num_cvts, spec->num_pins);
+       codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num);
+
+       for (idx = 0; idx < pcm_num; idx++) {
+               struct hdmi_spec_per_cvt *per_cvt;
+               struct hda_pcm *info;
+               struct hda_pcm_stream *pstr;
+
+               info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
+               if (!info)
+                       return -ENOMEM;
+
+               spec->pcm_rec[idx].pcm = info;
+               spec->pcm_used++;
+               info->pcm_type = HDA_PCM_TYPE_HDMI;
+               info->own_chmap = true;
+
+               pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+               pstr->substreams = 1;
+               pstr->ops = generic_ops;
+
+               per_cvt = get_cvt(spec, 0);
+               pstr->channels_min = per_cvt->channels_min;
+               pstr->channels_max = per_cvt->channels_max;
+
+               /* pcm number is less than pcm_rec array size */
+               if (spec->pcm_used >= ARRAY_SIZE(spec->pcm_rec))
+                       break;
+               /* other pstr fields are set in open */
+       }
+
+       return 0;
+}
+
+static void free_hdmi_jack_priv(struct snd_jack *jack)
+{
+       struct hdmi_pcm *pcm = jack->private_data;
+
+       pcm->jack = NULL;
+}
+
+static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
+{
+       char hdmi_str[32] = "HDMI/DP";
+       struct hdmi_spec *spec = codec->spec;
+       struct snd_jack *jack;
+       int pcmdev = get_pcm_rec(spec, pcm_idx)->device;
+       int err;
+
+       if (pcmdev > 0)
+               sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
+
+       err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack,
+                          true, false);
+       if (err < 0)
+               return err;
+
+       spec->pcm_rec[pcm_idx].jack = jack;
+       jack->private_data = &spec->pcm_rec[pcm_idx];
+       jack->private_free = free_hdmi_jack_priv;
+       return 0;
+}
+
+static int generic_hdmi_build_controls(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int dev, err;
+       int pin_idx, pcm_idx;
+
+       for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
+               if (!get_pcm_rec(spec, pcm_idx)->pcm) {
+                       /* no PCM: mark this for skipping permanently */
+                       set_bit(pcm_idx, &spec->pcm_bitmap);
+                       continue;
+               }
+
+               err = generic_hdmi_build_jack(codec, pcm_idx);
+               if (err < 0)
+                       return err;
+
+               /* create the spdif for each pcm
+                * pin will be bound when monitor is connected
+                */
+               err = snd_hda_create_dig_out_ctls(codec,
+                                         0, spec->cvt_nids[0],
+                                         HDA_PCM_TYPE_HDMI);
+               if (err < 0)
+                       return err;
+               snd_hda_spdif_ctls_unassign(codec, pcm_idx);
+
+               dev = get_pcm_rec(spec, pcm_idx)->device;
+               if (dev != SNDRV_PCM_INVALID_DEVICE) {
+                       /* add control for ELD Bytes */
+                       err = hdmi_create_eld_ctl(codec, pcm_idx, dev);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+               struct hdmi_eld *pin_eld = &per_pin->sink_eld;
+
+               if (spec->static_pcm_mapping) {
+                       hdmi_attach_hda_pcm(spec, per_pin);
+                       hdmi_pcm_setup_pin(spec, per_pin);
+               }
+
+               pin_eld->eld_valid = false;
+               hdmi_present_sense(per_pin, 0);
+       }
+
+       /* add channel maps */
+       for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
+               struct hda_pcm *pcm;
+
+               pcm = get_pcm_rec(spec, pcm_idx);
+               if (!pcm || !pcm->pcm)
+                       break;
+               err = snd_hdac_add_chmap_ctls(pcm->pcm, pcm_idx, &spec->chmap);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+static int generic_hdmi_init_per_pins(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+               per_pin->codec = codec;
+               mutex_init(&per_pin->lock);
+               INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
+               eld_proc_new(per_pin, pin_idx);
+       }
+       return 0;
+}
+
+static int generic_hdmi_init(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+
+       mutex_lock(&spec->bind_lock);
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+               hda_nid_t pin_nid = per_pin->pin_nid;
+               int dev_id = per_pin->dev_id;
+
+               snd_hda_set_dev_select(codec, pin_nid, dev_id);
+               hdmi_init_pin(codec, pin_nid);
+               if (codec_has_acomp(codec))
+                       continue;
+               snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, dev_id,
+                                                       jack_callback);
+       }
+       mutex_unlock(&spec->bind_lock);
+       return 0;
+}
+
+static void hdmi_array_init(struct hdmi_spec *spec, int nums)
+{
+       snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
+       snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
+}
+
+static void hdmi_array_free(struct hdmi_spec *spec)
+{
+       snd_array_free(&spec->pins);
+       snd_array_free(&spec->cvts);
+}
+
+static void generic_spec_free(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (spec) {
+               hdmi_array_free(spec);
+               kfree(spec);
+               codec->spec = NULL;
+       }
+       codec->dp_mst = false;
+}
+
+static void generic_hdmi_free(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx, pcm_idx;
+
+       if (spec->acomp_registered) {
+               snd_hdac_acomp_exit(&codec->bus->core);
+       } else if (codec_has_acomp(codec)) {
+               snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
+       }
+       codec->relaxed_resume = 0;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+               cancel_delayed_work_sync(&per_pin->work);
+               eld_proc_free(per_pin);
+       }
+
+       for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
+               if (spec->pcm_rec[pcm_idx].jack == NULL)
+                       continue;
+               snd_device_free(codec->card, spec->pcm_rec[pcm_idx].jack);
+       }
+
+       generic_spec_free(codec);
+}
+
+static int generic_hdmi_suspend(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+               cancel_delayed_work_sync(&per_pin->work);
+       }
+       return 0;
+}
+
+static int generic_hdmi_resume(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx;
+
+       codec->patch_ops.init(codec);
+       snd_hda_regmap_sync(codec);
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+               hdmi_present_sense(per_pin, 1);
+       }
+       return 0;
+}
+
+static const struct hda_codec_ops generic_hdmi_patch_ops = {
+       .init                   = generic_hdmi_init,
+       .free                   = generic_hdmi_free,
+       .build_pcms             = generic_hdmi_build_pcms,
+       .build_controls         = generic_hdmi_build_controls,
+       .unsol_event            = hdmi_unsol_event,
+       .suspend                = generic_hdmi_suspend,
+       .resume                 = generic_hdmi_resume,
+};
+
+static const struct hdmi_ops generic_standard_hdmi_ops = {
+       .pin_get_eld                            = hdmi_pin_get_eld,
+       .pin_setup_infoframe                    = hdmi_pin_setup_infoframe,
+       .pin_hbr_setup                          = hdmi_pin_hbr_setup,
+       .setup_stream                           = hdmi_setup_stream,
+};
+
+/* allocate codec->spec and assign/initialize generic parser ops */
+static int alloc_generic_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+
+       spec->codec = codec;
+       spec->ops = generic_standard_hdmi_ops;
+       spec->dev_num = 1;      /* initialize to 1 */
+       mutex_init(&spec->pcm_lock);
+       mutex_init(&spec->bind_lock);
+       snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
+
+       spec->chmap.ops.get_chmap = hdmi_get_chmap;
+       spec->chmap.ops.set_chmap = hdmi_set_chmap;
+       spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached;
+       spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc;
+
+       codec->spec = spec;
+       hdmi_array_init(spec, 4);
+
+       codec->patch_ops = generic_hdmi_patch_ops;
+
+       return 0;
+}
+
+/* generic HDMI parser */
+static int patch_generic_hdmi(struct hda_codec *codec)
+{
+       int err;
+
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+
+       err = hdmi_parse_codec(codec);
+       if (err < 0) {
+               generic_spec_free(codec);
+               return err;
+       }
+
+       generic_hdmi_init_per_pins(codec);
+       return 0;
+}
+
+/*
+ * generic audio component binding
+ */
+
+/* turn on / off the unsol event jack detection dynamically */
+static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid,
+                                 int dev_id, bool use_acomp)
+{
+       struct hda_jack_tbl *tbl;
+
+       tbl = snd_hda_jack_tbl_get_mst(codec, nid, dev_id);
+       if (tbl) {
+               /* clear unsol even if component notifier is used, or re-enable
+                * if notifier is cleared
+                */
+               unsigned int val = use_acomp ? 0 : (AC_USRSP_EN | tbl->tag);
+               snd_hda_codec_write_cache(codec, nid, 0,
+                                         AC_VERB_SET_UNSOLICITED_ENABLE, val);
+       }
+}
+
+/* set up / clear component notifier dynamically */
+static void generic_acomp_notifier_set(struct drm_audio_component *acomp,
+                                      bool use_acomp)
+{
+       struct hdmi_spec *spec;
+       int i;
+
+       spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops);
+       mutex_lock(&spec->bind_lock);
+       spec->use_acomp_notifier = use_acomp;
+       spec->codec->relaxed_resume = use_acomp;
+       spec->codec->bus->keep_power = 0;
+       /* reprogram each jack detection logic depending on the notifier */
+       for (i = 0; i < spec->num_pins; i++)
+               reprogram_jack_detect(spec->codec,
+                                     get_pin(spec, i)->pin_nid,
+                                     get_pin(spec, i)->dev_id,
+                                     use_acomp);
+       mutex_unlock(&spec->bind_lock);
+}
+
+/* enable / disable the notifier via master bind / unbind */
+static int generic_acomp_master_bind(struct device *dev,
+                                    struct drm_audio_component *acomp)
+{
+       generic_acomp_notifier_set(acomp, true);
+       return 0;
+}
+
+static void generic_acomp_master_unbind(struct device *dev,
+                                       struct drm_audio_component *acomp)
+{
+       generic_acomp_notifier_set(acomp, false);
+}
+
+/* check whether both HD-audio and DRM PCI devices belong to the same bus */
+static int match_bound_vga(struct device *dev, int subtype, void *data)
+{
+       struct hdac_bus *bus = data;
+       struct pci_dev *pci, *master;
+
+       if (!dev_is_pci(dev) || !dev_is_pci(bus->dev))
+               return 0;
+       master = to_pci_dev(bus->dev);
+       pci = to_pci_dev(dev);
+       return master->bus == pci->bus;
+}
+
+/* audio component notifier for AMD/Nvidia HDMI codecs */
+static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
+{
+       struct hda_codec *codec = audio_ptr;
+       struct hdmi_spec *spec = codec->spec;
+       hda_nid_t pin_nid = spec->port2pin(codec, port);
+
+       if (!pin_nid)
+               return;
+       if (get_wcaps_type(get_wcaps(codec, pin_nid)) != AC_WID_PIN)
+               return;
+       /* skip notification during system suspend (but not in runtime PM);
+        * the state will be updated at resume
+        */
+       if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
+               return;
+
+       check_presence_and_report(codec, pin_nid, dev_id);
+}
+
+/* set up the private drm_audio_ops from the template */
+static void setup_drm_audio_ops(struct hda_codec *codec,
+                               const struct drm_audio_component_audio_ops *ops)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       spec->drm_audio_ops.audio_ptr = codec;
+       /* intel_audio_codec_enable() or intel_audio_codec_disable()
+        * will call pin_eld_notify with using audio_ptr pointer
+        * We need make sure audio_ptr is really setup
+        */
+       wmb();
+       spec->drm_audio_ops.pin2port = ops->pin2port;
+       spec->drm_audio_ops.pin_eld_notify = ops->pin_eld_notify;
+       spec->drm_audio_ops.master_bind = ops->master_bind;
+       spec->drm_audio_ops.master_unbind = ops->master_unbind;
+}
+
+/* initialize the generic HDMI audio component */
+static void generic_acomp_init(struct hda_codec *codec,
+                              const struct drm_audio_component_audio_ops *ops,
+                              int (*port2pin)(struct hda_codec *, int))
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (!enable_acomp) {
+               codec_info(codec, "audio component disabled by module option\n");
+               return;
+       }
+
+       spec->port2pin = port2pin;
+       setup_drm_audio_ops(codec, ops);
+       if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops,
+                                match_bound_vga, 0)) {
+               spec->acomp_registered = true;
+       }
+}
+
+/*
+ * Intel codec parsers and helpers
+ */
+
+#define INTEL_GET_VENDOR_VERB  0xf81
+#define INTEL_SET_VENDOR_VERB  0x781
+#define INTEL_EN_DP12          0x02    /* enable DP 1.2 features */
+#define INTEL_EN_ALL_PIN_CVTS  0x01    /* enable 2nd & 3rd pins and convertors */
+
+static void intel_haswell_enable_all_pins(struct hda_codec *codec,
+                                         bool update_tree)
+{
+       unsigned int vendor_param;
+       struct hdmi_spec *spec = codec->spec;
+
+       vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+                               INTEL_GET_VENDOR_VERB, 0);
+       if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
+               return;
+
+       vendor_param |= INTEL_EN_ALL_PIN_CVTS;
+       vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+                               INTEL_SET_VENDOR_VERB, vendor_param);
+       if (vendor_param == -1)
+               return;
+
+       if (update_tree)
+               snd_hda_codec_update_widgets(codec);
+}
+
+static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
+{
+       unsigned int vendor_param;
+       struct hdmi_spec *spec = codec->spec;
+
+       vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
+                               INTEL_GET_VENDOR_VERB, 0);
+       if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
+               return;
+
+       /* enable DP1.2 mode */
+       vendor_param |= INTEL_EN_DP12;
+       snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
+       snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
+                               INTEL_SET_VENDOR_VERB, vendor_param);
+}
+
+/* Haswell needs to re-issue the vendor-specific verbs before turning to D0.
+ * Otherwise you may get severe h/w communication errors.
+ */
+static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
+                               unsigned int power_state)
+{
+       if (power_state == AC_PWRST_D0) {
+               intel_haswell_enable_all_pins(codec, false);
+               intel_haswell_fixup_enable_dp12(codec);
+       }
+
+       snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
+       snd_hda_codec_set_power_to_all(codec, fg, power_state);
+}
+
+/* There is a fixed mapping between audio pin node and display port.
+ * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
+ * Pin Widget 5 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 6 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 7 - PORT D (port = 3 in i915 driver)
+ *
+ * on VLV, ILK:
+ * Pin Widget 4 - PORT B (port = 1 in i915 driver)
+ * Pin Widget 5 - PORT C (port = 2 in i915 driver)
+ * Pin Widget 6 - PORT D (port = 3 in i915 driver)
+ */
+static int intel_base_nid(struct hda_codec *codec)
+{
+       switch (codec->core.vendor_id) {
+       case 0x80860054: /* ILK */
+       case 0x80862804: /* ILK */
+       case 0x80862882: /* VLV */
+               return 4;
+       default:
+               return 5;
+       }
+}
+
+static int intel_pin2port(void *audio_ptr, int pin_nid)
+{
+       struct hda_codec *codec = audio_ptr;
+       struct hdmi_spec *spec = codec->spec;
+       int base_nid, i;
+
+       if (!spec->port_num) {
+               base_nid = intel_base_nid(codec);
+               if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
+                       return -1;
+               return pin_nid - base_nid + 1;
+       }
+
+       /*
+        * looking for the pin number in the mapping table and return
+        * the index which indicate the port number
+        */
+       for (i = 0; i < spec->port_num; i++) {
+               if (pin_nid == spec->port_map[i])
+                       return i;
+       }
+
+       codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid);
+       return -1;
+}
+
+static int intel_port2pin(struct hda_codec *codec, int port)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       if (!spec->port_num) {
+               /* we assume only from port-B to port-D */
+               if (port < 1 || port > 3)
+                       return 0;
+               return port + intel_base_nid(codec) - 1;
+       }
+
+       if (port < 0 || port >= spec->port_num)
+               return 0;
+       return spec->port_map[port];
+}
+
+static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
+{
+       struct hda_codec *codec = audio_ptr;
+       int pin_nid;
+       int dev_id = pipe;
+
+       pin_nid = intel_port2pin(codec, port);
+       if (!pin_nid)
+               return;
+       /* skip notification during system suspend (but not in runtime PM);
+        * the state will be updated at resume
+        */
+       if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
+               return;
+
+       snd_hdac_i915_set_bclk(&codec->bus->core);
+       check_presence_and_report(codec, pin_nid, dev_id);
+}
+
+static const struct drm_audio_component_audio_ops intel_audio_ops = {
+       .pin2port = intel_pin2port,
+       .pin_eld_notify = intel_pin_eld_notify,
+};
+
+/* register i915 component pin_eld_notify callback */
+static void register_i915_notifier(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       spec->use_acomp_notifier = true;
+       spec->port2pin = intel_port2pin;
+       setup_drm_audio_ops(codec, &intel_audio_ops);
+       snd_hdac_acomp_register_notifier(&codec->bus->core,
+                                       &spec->drm_audio_ops);
+       /* no need for forcible resume for jack check thanks to notifier */
+       codec->relaxed_resume = 1;
+}
+
+/* setup_stream ops override for HSW+ */
+static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+                                hda_nid_t pin_nid, int dev_id, u32 stream_tag,
+                                int format)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);
+       struct hdmi_spec_per_pin *per_pin;
+       int res;
+
+       if (pin_idx < 0)
+               per_pin = NULL;
+       else
+               per_pin = get_pin(spec, pin_idx);
+
+       haswell_verify_D0(codec, cvt_nid, pin_nid);
+
+       if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+               silent_stream_set_kae(codec, per_pin, false);
+               /* wait for pending transfers in codec to clear */
+               usleep_range(100, 200);
+       }
+
+       res = hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+                               stream_tag, format);
+
+       if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
+               usleep_range(100, 200);
+               silent_stream_set_kae(codec, per_pin, true);
+       }
+
+       return res;
+}
+
+/* pin_cvt_fixup ops override for HSW+ and VLV+ */
+static void i915_pin_cvt_fixup(struct hda_codec *codec,
+                              struct hdmi_spec_per_pin *per_pin,
+                              hda_nid_t cvt_nid)
+{
+       if (per_pin) {
+               haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid);
+               snd_hda_set_dev_select(codec, per_pin->pin_nid,
+                              per_pin->dev_id);
+               intel_verify_pin_cvt_connect(codec, per_pin);
+               intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
+                                    per_pin->dev_id, per_pin->mux_idx);
+       } else {
+               intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
+       }
+}
+
+static int i915_adlp_hdmi_suspend(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       bool silent_streams = false;
+       int pin_idx, res;
+
+       res = generic_hdmi_suspend(codec);
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+               if (per_pin->silent_stream) {
+                       silent_streams = true;
+                       break;
+               }
+       }
+
+       if (silent_streams && spec->silent_stream_type == SILENT_STREAM_KAE) {
+               /*
+                * stream-id should remain programmed when codec goes
+                * to runtime suspend
+                */
+               codec->no_stream_clean_at_suspend = 1;
+
+               /*
+                * the system might go to S3, in which case keep-alive
+                * must be reprogrammed upon resume
+                */
+               codec->forced_resume = 1;
+
+               codec_dbg(codec, "HDMI: KAE active at suspend\n");
+       } else {
+               codec->no_stream_clean_at_suspend = 0;
+               codec->forced_resume = 0;
+       }
+
+       return res;
+}
+
+static int i915_adlp_hdmi_resume(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx, res;
+
+       res = generic_hdmi_resume(codec);
+
+       /* KAE not programmed at suspend, nothing to do here */
+       if (!codec->no_stream_clean_at_suspend)
+               return res;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+               /*
+                * If system was in suspend with monitor connected,
+                * the codec setting may have been lost. Re-enable
+                * keep-alive.
+                */
+               if (per_pin->silent_stream) {
+                       unsigned int param;
+
+                       param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
+                                                  AC_VERB_GET_CONV, 0);
+                       if (!param) {
+                               codec_dbg(codec, "HDMI: KAE: restore stream id\n");
+                               silent_stream_enable_i915(codec, per_pin);
+                       }
+
+                       param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
+                                                  AC_VERB_GET_DIGI_CONVERT_1, 0);
+                       if (!(param & (AC_DIG3_KAE << 16))) {
+                               codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n");
+                               silent_stream_set_kae(codec, per_pin, true);
+                       }
+               }
+       }
+
+       return res;
+}
+
+/* precondition and allocation for Intel codecs */
+static int alloc_intel_hdmi(struct hda_codec *codec)
+{
+       int err;
+
+       /* requires i915 binding */
+       if (!codec->bus->core.audio_component) {
+               codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
+               /* set probe_id here to prevent generic fallback binding */
+               codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
+               return -ENODEV;
+       }
+
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+       /* no need to handle unsol events */
+       codec->patch_ops.unsol_event = NULL;
+       return 0;
+}
+
+/* parse and post-process for Intel codecs */
+static int parse_intel_hdmi(struct hda_codec *codec)
+{
+       int err, retries = 3;
+
+       do {
+               err = hdmi_parse_codec(codec);
+       } while (err < 0 && retries--);
+
+       if (err < 0) {
+               generic_spec_free(codec);
+               return err;
+       }
+
+       generic_hdmi_init_per_pins(codec);
+       register_i915_notifier(codec);
+       return 0;
+}
+
+/* Intel Haswell and onwards; audio component with eld notifier */
+static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
+                                const int *port_map, int port_num, int dev_num,
+                                bool send_silent_stream)
+{
+       struct hdmi_spec *spec;
+       int err;
+
+       err = alloc_intel_hdmi(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+       codec->dp_mst = true;
+       spec->vendor_nid = vendor_nid;
+       spec->port_map = port_map;
+       spec->port_num = port_num;
+       spec->intel_hsw_fixup = true;
+       spec->dev_num = dev_num;
+
+       intel_haswell_enable_all_pins(codec, true);
+       intel_haswell_fixup_enable_dp12(codec);
+
+       codec->display_power_control = 1;
+
+       codec->patch_ops.set_power_state = haswell_set_power_state;
+       codec->depop_delay = 0;
+       codec->auto_runtime_pm = 1;
+
+       spec->ops.setup_stream = i915_hsw_setup_stream;
+       spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+
+       /*
+        * Enable silent stream feature, if it is enabled via
+        * module param or Kconfig option
+        */
+       if (send_silent_stream)
+               spec->silent_stream_type = SILENT_STREAM_I915;
+
+       return parse_intel_hdmi(codec);
+}
+
+static int patch_i915_hsw_hdmi(struct hda_codec *codec)
+{
+       return intel_hsw_common_init(codec, 0x08, NULL, 0, 3,
+                                    enable_silent_stream);
+}
+
+static int patch_i915_glk_hdmi(struct hda_codec *codec)
+{
+       /*
+        * Silent stream calls audio component .get_power() from
+        * .pin_eld_notify(). On GLK this will deadlock in i915 due
+        * to the audio vs. CDCLK workaround.
+        */
+       return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false);
+}
+
+static int patch_i915_icl_hdmi(struct hda_codec *codec)
+{
+       /*
+        * pin to port mapping table where the value indicate the pin number and
+        * the index indicate the port number.
+        */
+       static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb};
+
+       return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3,
+                                    enable_silent_stream);
+}
+
+static int patch_i915_tgl_hdmi(struct hda_codec *codec)
+{
+       /*
+        * pin to port mapping table where the value indicate the pin number and
+        * the index indicate the port number.
+        */
+       static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+       return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4,
+                                    enable_silent_stream);
+}
+
+static int patch_i915_adlp_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int res;
+
+       res = patch_i915_tgl_hdmi(codec);
+       if (!res) {
+               spec = codec->spec;
+
+               if (spec->silent_stream_type) {
+                       spec->silent_stream_type = SILENT_STREAM_KAE;
+
+                       codec->patch_ops.resume = i915_adlp_hdmi_resume;
+                       codec->patch_ops.suspend = i915_adlp_hdmi_suspend;
+               }
+       }
+
+       return res;
+}
+
+/* Intel Baytrail and Braswell; with eld notifier */
+static int patch_i915_byt_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err;
+
+       err = alloc_intel_hdmi(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+
+       /* For Valleyview/Cherryview, only the display codec is in the display
+        * power well and can use link_power ops to request/release the power.
+        */
+       codec->display_power_control = 1;
+
+       codec->depop_delay = 0;
+       codec->auto_runtime_pm = 1;
+
+       spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
+
+       return parse_intel_hdmi(codec);
+}
+
+/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
+static int patch_i915_cpt_hdmi(struct hda_codec *codec)
+{
+       int err;
+
+       err = alloc_intel_hdmi(codec);
+       if (err < 0)
+               return err;
+       return parse_intel_hdmi(codec);
+}
+
+/*
+ * Shared non-generic implementations
+ */
+
+static int simple_playback_build_pcms(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info;
+       unsigned int chans;
+       struct hda_pcm_stream *pstr;
+       struct hdmi_spec_per_cvt *per_cvt;
+
+       per_cvt = get_cvt(spec, 0);
+       chans = get_wcaps(codec, per_cvt->cvt_nid);
+       chans = get_wcaps_channels(chans);
+
+       info = snd_hda_codec_pcm_new(codec, "HDMI 0");
+       if (!info)
+               return -ENOMEM;
+       spec->pcm_rec[0].pcm = info;
+       info->pcm_type = HDA_PCM_TYPE_HDMI;
+       pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
+       *pstr = spec->pcm_playback;
+       pstr->nid = per_cvt->cvt_nid;
+       if (pstr->channels_max <= 2 && chans && chans <= 16)
+               pstr->channels_max = chans;
+
+       return 0;
+}
+
+/* unsolicited event for jack sensing */
+static void simple_hdmi_unsol_event(struct hda_codec *codec,
+                                   unsigned int res)
+{
+       snd_hda_jack_set_dirty_all(codec);
+       snd_hda_jack_report_sync(codec);
+}
+
+/* generic_hdmi_build_jack can be used for simple_hdmi, too,
+ * as long as spec->pins[] is set correctly
+ */
+#define simple_hdmi_build_jack generic_hdmi_build_jack
+
+static int simple_playback_build_controls(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_cvt *per_cvt;
+       int err;
+
+       per_cvt = get_cvt(spec, 0);
+       err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid,
+                                         per_cvt->cvt_nid,
+                                         HDA_PCM_TYPE_HDMI);
+       if (err < 0)
+               return err;
+       return simple_hdmi_build_jack(codec, 0);
+}
+
+static int simple_playback_init(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
+       hda_nid_t pin = per_pin->pin_nid;
+
+       snd_hda_codec_write(codec, pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       /* some codecs require to unmute the pin */
+       if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
+               snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
+                                   AMP_OUT_UNMUTE);
+       snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id);
+       return 0;
+}
+
+static void simple_playback_free(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+
+       hdmi_array_free(spec);
+       kfree(spec);
+}
+
+/*
+ * Nvidia specific implementations
+ */
+
+#define Nv_VERB_SET_Channel_Allocation          0xF79
+#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
+#define Nv_VERB_SET_Audio_Protection_On         0xF98
+#define Nv_VERB_SET_Audio_Protection_Off        0xF99
+
+#define nvhdmi_master_con_nid_7x       0x04
+#define nvhdmi_master_pin_nid_7x       0x05
+
+static const hda_nid_t nvhdmi_con_nids_7x[4] = {
+       /*front, rear, clfe, rear_surr */
+       0x6, 0x8, 0xa, 0xc,
+};
+
+static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
+       /* set audio protect on */
+       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+       /* enable digital output on pin widget */
+       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       {} /* terminator */
+};
+
+static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
+       /* set audio protect on */
+       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
+       /* enable digital output on pin widget */
+       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
+       {} /* terminator */
+};
+
+#ifdef LIMITED_RATE_FMT_SUPPORT
+/* support only the safe format and rate */
+#define SUPPORTED_RATES                SNDRV_PCM_RATE_48000
+#define SUPPORTED_MAXBPS       16
+#define SUPPORTED_FORMATS      SNDRV_PCM_FMTBIT_S16_LE
+#else
+/* support all rates and formats */
+#define SUPPORTED_RATES \
+       (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
+       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
+        SNDRV_PCM_RATE_192000)
+#define SUPPORTED_MAXBPS       24
+#define SUPPORTED_FORMATS \
+       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
+#endif
+
+static int nvhdmi_7x_init_2ch(struct hda_codec *codec)
+{
+       snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
+       return 0;
+}
+
+static int nvhdmi_7x_init_8ch(struct hda_codec *codec)
+{
+       snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
+       return 0;
+}
+
+static const unsigned int channels_2_6_8[] = {
+       2, 6, 8
+};
+
+static const unsigned int channels_2_8[] = {
+       2, 8
+};
+
+static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
+       .count = ARRAY_SIZE(channels_2_6_8),
+       .list = channels_2_6_8,
+       .mask = 0,
+};
+
+static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
+       .count = ARRAY_SIZE(channels_2_8),
+       .list = channels_2_8,
+       .mask = 0,
+};
+
+static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       const struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
+
+       switch (codec->preset->vendor_id) {
+       case 0x10de0002:
+       case 0x10de0003:
+       case 0x10de0005:
+       case 0x10de0006:
+               hw_constraints_channels = &hw_constraints_2_8_channels;
+               break;
+       case 0x10de0007:
+               hw_constraints_channels = &hw_constraints_2_6_8_channels;
+               break;
+       default:
+               break;
+       }
+
+       if (hw_constraints_channels != NULL) {
+               snd_pcm_hw_constraint_list(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_CHANNELS,
+                               hw_constraints_channels);
+       } else {
+               snd_pcm_hw_constraint_step(substream->runtime, 0,
+                                          SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+       }
+
+       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                      struct hda_codec *codec,
+                                      unsigned int stream_tag,
+                                      unsigned int format,
+                                      struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
+                                            stream_tag, format, substream);
+}
+
+static const struct hda_pcm_stream simple_pcm_playback = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 2,
+       .ops = {
+               .open = simple_playback_pcm_open,
+               .close = simple_playback_pcm_close,
+               .prepare = simple_playback_pcm_prepare
+       },
+};
+
+static const struct hda_codec_ops simple_hdmi_patch_ops = {
+       .build_controls = simple_playback_build_controls,
+       .build_pcms = simple_playback_build_pcms,
+       .init = simple_playback_init,
+       .free = simple_playback_free,
+       .unsol_event = simple_hdmi_unsol_event,
+};
+
+static int patch_simple_hdmi(struct hda_codec *codec,
+                            hda_nid_t cvt_nid, hda_nid_t pin_nid)
+{
+       struct hdmi_spec *spec;
+       struct hdmi_spec_per_cvt *per_cvt;
+       struct hdmi_spec_per_pin *per_pin;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+
+       spec->codec = codec;
+       codec->spec = spec;
+       hdmi_array_init(spec, 1);
+
+       spec->multiout.num_dacs = 0;  /* no analog */
+       spec->multiout.max_channels = 2;
+       spec->multiout.dig_out_nid = cvt_nid;
+       spec->num_cvts = 1;
+       spec->num_pins = 1;
+       per_pin = snd_array_new(&spec->pins);
+       per_cvt = snd_array_new(&spec->cvts);
+       if (!per_pin || !per_cvt) {
+               simple_playback_free(codec);
+               return -ENOMEM;
+       }
+       per_cvt->cvt_nid = cvt_nid;
+       per_pin->pin_nid = pin_nid;
+       spec->pcm_playback = simple_pcm_playback;
+
+       codec->patch_ops = simple_hdmi_patch_ops;
+
+       return 0;
+}
+
+static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
+                                                   int channels)
+{
+       unsigned int chanmask;
+       int chan = channels ? (channels - 1) : 1;
+
+       switch (channels) {
+       default:
+       case 0:
+       case 2:
+               chanmask = 0x00;
+               break;
+       case 4:
+               chanmask = 0x08;
+               break;
+       case 6:
+               chanmask = 0x0b;
+               break;
+       case 8:
+               chanmask = 0x13;
+               break;
+       }
+
+       /* Set the audio infoframe channel allocation and checksum fields.  The
+        * channel count is computed implicitly by the hardware. */
+       snd_hda_codec_write(codec, 0x1, 0,
+                       Nv_VERB_SET_Channel_Allocation, chanmask);
+
+       snd_hda_codec_write(codec, 0x1, 0,
+                       Nv_VERB_SET_Info_Frame_Checksum,
+                       (0x71 - chan - chanmask));
+}
+
+static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i;
+
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
+                       0, AC_VERB_SET_CHANNEL_STREAMID, 0);
+       for (i = 0; i < 4; i++) {
+               /* set the stream id */
+               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+                               AC_VERB_SET_CHANNEL_STREAMID, 0);
+               /* set the stream format */
+               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
+                               AC_VERB_SET_STREAM_FORMAT, 0);
+       }
+
+       /* The audio hardware sends a channel count of 0x7 (8ch) when all the
+        * streams are disabled. */
+       nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
+
+       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
+}
+
+static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                    struct hda_codec *codec,
+                                    unsigned int stream_tag,
+                                    unsigned int format,
+                                    struct snd_pcm_substream *substream)
+{
+       int chs;
+       unsigned int dataDCC2, channel_id;
+       int i;
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_spdif_out *spdif;
+       struct hdmi_spec_per_cvt *per_cvt;
+
+       mutex_lock(&codec->spdif_mutex);
+       per_cvt = get_cvt(spec, 0);
+       spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
+
+       chs = substream->runtime->channels;
+
+       dataDCC2 = 0x2;
+
+       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
+       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
+
+       /* set the stream id */
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+                       AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
+
+       /* set the stream format */
+       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
+                       AC_VERB_SET_STREAM_FORMAT, format);
+
+       /* turn on again (if needed) */
+       /* enable and set the channel status audio/data flag */
+       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               spdif->ctls & 0xff);
+               snd_hda_codec_write(codec,
+                               nvhdmi_master_con_nid_7x,
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+       }
+
+       for (i = 0; i < 4; i++) {
+               if (chs == 2)
+                       channel_id = 0;
+               else
+                       channel_id = i * 2;
+
+               /* turn off SPDIF once;
+                *otherwise the IEC958 bits won't be updated
+                */
+               if (codec->spdif_status_reset &&
+               (spdif->ctls & AC_DIG1_ENABLE))
+                       snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_DIGI_CONVERT_1,
+                               spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
+               /* set the stream id */
+               snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_CHANNEL_STREAMID,
+                               (stream_tag << 4) | channel_id);
+               /* set the stream format */
+               snd_hda_codec_write(codec,
+                               nvhdmi_con_nids_7x[i],
+                               0,
+                               AC_VERB_SET_STREAM_FORMAT,
+                               format);
+               /* turn on again (if needed) */
+               /* enable and set the channel status audio/data flag */
+               if (codec->spdif_status_reset &&
+               (spdif->ctls & AC_DIG1_ENABLE)) {
+                       snd_hda_codec_write(codec,
+                                       nvhdmi_con_nids_7x[i],
+                                       0,
+                                       AC_VERB_SET_DIGI_CONVERT_1,
+                                       spdif->ctls & 0xff);
+                       snd_hda_codec_write(codec,
+                                       nvhdmi_con_nids_7x[i],
+                                       0,
+                                       AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
+               }
+       }
+
+       nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
+
+       mutex_unlock(&codec->spdif_mutex);
+       return 0;
+}
+
+static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
+       .substreams = 1,
+       .channels_min = 2,
+       .channels_max = 8,
+       .nid = nvhdmi_master_con_nid_7x,
+       .rates = SUPPORTED_RATES,
+       .maxbps = SUPPORTED_MAXBPS,
+       .formats = SUPPORTED_FORMATS,
+       .ops = {
+               .open = simple_playback_pcm_open,
+               .close = nvhdmi_8ch_7x_pcm_close,
+               .prepare = nvhdmi_8ch_7x_pcm_prepare
+       },
+};
+
+static int patch_nvhdmi_2ch(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x,
+                                   nvhdmi_master_pin_nid_7x);
+       if (err < 0)
+               return err;
+
+       codec->patch_ops.init = nvhdmi_7x_init_2ch;
+       /* override the PCM rates, etc, as the codec doesn't give full list */
+       spec = codec->spec;
+       spec->pcm_playback.rates = SUPPORTED_RATES;
+       spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
+       spec->pcm_playback.formats = SUPPORTED_FORMATS;
+       spec->nv_dp_workaround = true;
+       return 0;
+}
+
+static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int err = simple_playback_build_pcms(codec);
+       if (!err) {
+               struct hda_pcm *info = get_pcm_rec(spec, 0);
+               info->own_chmap = true;
+       }
+       return err;
+}
+
+static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       struct hda_pcm *info;
+       struct snd_pcm_chmap *chmap;
+       int err;
+
+       err = simple_playback_build_controls(codec);
+       if (err < 0)
+               return err;
+
+       /* add channel maps */
+       info = get_pcm_rec(spec, 0);
+       err = snd_pcm_add_chmap_ctls(info->pcm,
+                                    SNDRV_PCM_STREAM_PLAYBACK,
+                                    snd_pcm_alt_chmaps, 8, 0, &chmap);
+       if (err < 0)
+               return err;
+       switch (codec->preset->vendor_id) {
+       case 0x10de0002:
+       case 0x10de0003:
+       case 0x10de0005:
+       case 0x10de0006:
+               chmap->channel_mask = (1U << 2) | (1U << 8);
+               break;
+       case 0x10de0007:
+               chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
+       }
+       return 0;
+}
+
+static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err = patch_nvhdmi_2ch(codec);
+       if (err < 0)
+               return err;
+       spec = codec->spec;
+       spec->multiout.max_channels = 8;
+       spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
+       codec->patch_ops.init = nvhdmi_7x_init_8ch;
+       codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
+       codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
+
+       /* Initialize the audio infoframe channel mask and checksum to something
+        * valid */
+       nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
+
+       return 0;
+}
+
+/*
+ * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
+ * - 0x10de0015
+ * - 0x10de0040
+ */
+static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
+               struct hdac_cea_channel_speaker_allocation *cap, int channels)
+{
+       if (cap->ca_index == 0x00 && channels == 2)
+               return SNDRV_CTL_TLVT_CHMAP_FIXED;
+
+       /* If the speaker allocation matches the channel count, it is OK. */
+       if (cap->channels != channels)
+               return -1;
+
+       /* all channels are remappable freely */
+       return SNDRV_CTL_TLVT_CHMAP_VAR;
+}
+
+static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
+               int ca, int chs, unsigned char *map)
+{
+       if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
+               return -EINVAL;
+
+       return 0;
+}
+
+/* map from pin NID to port; port is 0-based */
+/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */
+static int nvhdmi_pin2port(void *audio_ptr, int pin_nid)
+{
+       return pin_nid - 4;
+}
+
+/* reverse-map from port to pin NID: see above */
+static int nvhdmi_port2pin(struct hda_codec *codec, int port)
+{
+       return port + 4;
+}
+
+static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = {
+       .pin2port = nvhdmi_pin2port,
+       .pin_eld_notify = generic_acomp_pin_eld_notify,
+       .master_bind = generic_acomp_master_bind,
+       .master_unbind = generic_acomp_master_unbind,
+};
+
+static int patch_nvhdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err;
+
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+       codec->dp_mst = true;
+
+       spec = codec->spec;
+
+       err = hdmi_parse_codec(codec);
+       if (err < 0) {
+               generic_spec_free(codec);
+               return err;
+       }
+
+       generic_hdmi_init_per_pins(codec);
+
+       spec->dyn_pin_out = true;
+
+       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+               nvhdmi_chmap_cea_alloc_validate_get_type;
+       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+       spec->nv_dp_workaround = true;
+
+       codec->link_down_at_suspend = 1;
+
+       generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin);
+
+       return 0;
+}
+
+static int patch_nvhdmi_legacy(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err;
+
+       err = patch_generic_hdmi(codec);
+       if (err)
+               return err;
+
+       spec = codec->spec;
+       spec->dyn_pin_out = true;
+
+       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+               nvhdmi_chmap_cea_alloc_validate_get_type;
+       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+       spec->nv_dp_workaround = true;
+
+       codec->link_down_at_suspend = 1;
+
+       return 0;
+}
+
+/*
+ * The HDA codec on NVIDIA Tegra contains two scratch registers that are
+ * accessed using vendor-defined verbs. These registers can be used for
+ * interoperability between the HDA and HDMI drivers.
+ */
+
+/* Audio Function Group node */
+#define NVIDIA_AFG_NID 0x01
+
+/*
+ * The SCRATCH0 register is used to notify the HDMI codec of changes in audio
+ * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to
+ * be raised in the HDMI codec. The remainder of the bits is arbitrary. This
+ * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an
+ * additional bit (at position 30) to signal the validity of the format.
+ *
+ * | 31      | 30    | 29  16 | 15   0 |
+ * +---------+-------+--------+--------+
+ * | TRIGGER | VALID | UNUSED | FORMAT |
+ * +-----------------------------------|
+ *
+ * Note that for the trigger bit to take effect it needs to change value
+ * (i.e. it needs to be toggled). The trigger bit is not applicable from
+ * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt
+ * trigger to hdmi.
+ */
+#define NVIDIA_SET_HOST_INTR           0xf80
+#define NVIDIA_GET_SCRATCH0            0xfa6
+#define NVIDIA_SET_SCRATCH0_BYTE0      0xfa7
+#define NVIDIA_SET_SCRATCH0_BYTE1      0xfa8
+#define NVIDIA_SET_SCRATCH0_BYTE2      0xfa9
+#define NVIDIA_SET_SCRATCH0_BYTE3      0xfaa
+#define NVIDIA_SCRATCH_TRIGGER (1 << 7)
+#define NVIDIA_SCRATCH_VALID   (1 << 6)
+
+#define NVIDIA_GET_SCRATCH1            0xfab
+#define NVIDIA_SET_SCRATCH1_BYTE0      0xfac
+#define NVIDIA_SET_SCRATCH1_BYTE1      0xfad
+#define NVIDIA_SET_SCRATCH1_BYTE2      0xfae
+#define NVIDIA_SET_SCRATCH1_BYTE3      0xfaf
+
+/*
+ * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0,
+ * the format is invalidated so that the HDMI codec can be disabled.
+ */
+static void tegra_hdmi_set_format(struct hda_codec *codec,
+                                 hda_nid_t cvt_nid,
+                                 unsigned int format)
+{
+       unsigned int value;
+       unsigned int nid = NVIDIA_AFG_NID;
+       struct hdmi_spec *spec = codec->spec;
+
+       /*
+        * Tegra HDA codec design from TEGRA234 chip onwards support DP MST.
+        * This resulted in moving scratch registers from audio function
+        * group to converter widget context. So CVT NID should be used for
+        * scratch register read/write for DP MST supported Tegra HDA codec.
+        */
+       if (codec->dp_mst)
+               nid = cvt_nid;
+
+       /* bits [31:30] contain the trigger and valid bits */
+       value = snd_hda_codec_read(codec, nid, 0,
+                                  NVIDIA_GET_SCRATCH0, 0);
+       value = (value >> 24) & 0xff;
+
+       /* bits [15:0] are used to store the HDA format */
+       snd_hda_codec_write(codec, nid, 0,
+                           NVIDIA_SET_SCRATCH0_BYTE0,
+                           (format >> 0) & 0xff);
+       snd_hda_codec_write(codec, nid, 0,
+                           NVIDIA_SET_SCRATCH0_BYTE1,
+                           (format >> 8) & 0xff);
+
+       /* bits [16:24] are unused */
+       snd_hda_codec_write(codec, nid, 0,
+                           NVIDIA_SET_SCRATCH0_BYTE2, 0);
+
+       /*
+        * Bit 30 signals that the data is valid and hence that HDMI audio can
+        * be enabled.
+        */
+       if (format == 0)
+               value &= ~NVIDIA_SCRATCH_VALID;
+       else
+               value |= NVIDIA_SCRATCH_VALID;
+
+       if (spec->hdmi_intr_trig_ctrl) {
+               /*
+                * For Tegra HDA Codec design from TEGRA234 onwards, the
+                * Interrupt to hdmi driver is triggered by writing
+                * non-zero values to verb 0xF80 instead of 31st bit of
+                * scratch register.
+                */
+               snd_hda_codec_write(codec, nid, 0,
+                               NVIDIA_SET_SCRATCH0_BYTE3, value);
+               snd_hda_codec_write(codec, nid, 0,
+                               NVIDIA_SET_HOST_INTR, 0x1);
+       } else {
+               /*
+                * Whenever the 31st trigger bit is toggled, an interrupt is raised
+                * in the HDMI codec. The HDMI driver will use that as trigger
+                * to update its configuration.
+                */
+               value ^= NVIDIA_SCRATCH_TRIGGER;
+
+               snd_hda_codec_write(codec, nid, 0,
+                               NVIDIA_SET_SCRATCH0_BYTE3, value);
+       }
+}
+
+static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 unsigned int stream_tag,
+                                 unsigned int format,
+                                 struct snd_pcm_substream *substream)
+{
+       int err;
+
+       err = generic_hdmi_playback_pcm_prepare(hinfo, codec, stream_tag,
+                                               format, substream);
+       if (err < 0)
+               return err;
+
+       /* notify the HDMI codec of the format change */
+       tegra_hdmi_set_format(codec, hinfo->nid, format);
+
+       return 0;
+}
+
+static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream)
+{
+       /* invalidate the format in the HDMI codec */
+       tegra_hdmi_set_format(codec, hinfo->nid, 0);
+
+       return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream);
+}
+
+static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type)
+{
+       struct hdmi_spec *spec = codec->spec;
+       unsigned int i;
+
+       for (i = 0; i < spec->num_pins; i++) {
+               struct hda_pcm *pcm = get_pcm_rec(spec, i);
+
+               if (pcm->pcm_type == type)
+                       return pcm;
+       }
+
+       return NULL;
+}
+
+static int tegra_hdmi_build_pcms(struct hda_codec *codec)
+{
+       struct hda_pcm_stream *stream;
+       struct hda_pcm *pcm;
+       int err;
+
+       err = generic_hdmi_build_pcms(codec);
+       if (err < 0)
+               return err;
+
+       pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI);
+       if (!pcm)
+               return -ENODEV;
+
+       /*
+        * Override ->prepare() and ->cleanup() operations to notify the HDMI
+        * codec about format changes.
+        */
+       stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
+       stream->ops.prepare = tegra_hdmi_pcm_prepare;
+       stream->ops.cleanup = tegra_hdmi_pcm_cleanup;
+
+       return 0;
+}
+
+static int tegra_hdmi_init(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int i, err;
+
+       err = hdmi_parse_codec(codec);
+       if (err < 0) {
+               generic_spec_free(codec);
+               return err;
+       }
+
+       for (i = 0; i < spec->num_cvts; i++)
+               snd_hda_codec_write(codec, spec->cvt_nids[i], 0,
+                                       AC_VERB_SET_DIGI_CONVERT_1,
+                                       AC_DIG1_ENABLE);
+
+       generic_hdmi_init_per_pins(codec);
+
+       codec->depop_delay = 10;
+       codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
+       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+               nvhdmi_chmap_cea_alloc_validate_get_type;
+       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+
+       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+               nvhdmi_chmap_cea_alloc_validate_get_type;
+       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
+       spec->nv_dp_workaround = true;
+
+       return 0;
+}
+
+static int patch_tegra_hdmi(struct hda_codec *codec)
+{
+       int err;
+
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+
+       return tegra_hdmi_init(codec);
+}
+
+static int patch_tegra234_hdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       int err;
+
+       err = alloc_generic_hdmi(codec);
+       if (err < 0)
+               return err;
+
+       codec->dp_mst = true;
+       spec = codec->spec;
+       spec->dyn_pin_out = true;
+       spec->hdmi_intr_trig_ctrl = true;
+
+       return tegra_hdmi_init(codec);
+}
+
+/*
+ * ATI/AMD-specific implementations
+ */
+
+#define is_amdhdmi_rev3_or_later(codec) \
+       ((codec)->core.vendor_id == 0x1002aa01 && \
+        ((codec)->core.revision_id & 0xff00) >= 0x0300)
+#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
+
+/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
+#define ATI_VERB_SET_CHANNEL_ALLOCATION        0x771
+#define ATI_VERB_SET_DOWNMIX_INFO      0x772
+#define ATI_VERB_SET_MULTICHANNEL_01   0x777
+#define ATI_VERB_SET_MULTICHANNEL_23   0x778
+#define ATI_VERB_SET_MULTICHANNEL_45   0x779
+#define ATI_VERB_SET_MULTICHANNEL_67   0x77a
+#define ATI_VERB_SET_HBR_CONTROL       0x77c
+#define ATI_VERB_SET_MULTICHANNEL_1    0x785
+#define ATI_VERB_SET_MULTICHANNEL_3    0x786
+#define ATI_VERB_SET_MULTICHANNEL_5    0x787
+#define ATI_VERB_SET_MULTICHANNEL_7    0x788
+#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789
+#define ATI_VERB_GET_CHANNEL_ALLOCATION        0xf71
+#define ATI_VERB_GET_DOWNMIX_INFO      0xf72
+#define ATI_VERB_GET_MULTICHANNEL_01   0xf77
+#define ATI_VERB_GET_MULTICHANNEL_23   0xf78
+#define ATI_VERB_GET_MULTICHANNEL_45   0xf79
+#define ATI_VERB_GET_MULTICHANNEL_67   0xf7a
+#define ATI_VERB_GET_HBR_CONTROL       0xf7c
+#define ATI_VERB_GET_MULTICHANNEL_1    0xf85
+#define ATI_VERB_GET_MULTICHANNEL_3    0xf86
+#define ATI_VERB_GET_MULTICHANNEL_5    0xf87
+#define ATI_VERB_GET_MULTICHANNEL_7    0xf88
+#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89
+
+/* AMD specific HDA cvt verbs */
+#define ATI_VERB_SET_RAMP_RATE         0x770
+#define ATI_VERB_GET_RAMP_RATE         0xf70
+
+#define ATI_OUT_ENABLE 0x1
+
+#define ATI_MULTICHANNEL_MODE_PAIRED   0
+#define ATI_MULTICHANNEL_MODE_SINGLE   1
+
+#define ATI_HBR_CAPABLE 0x01
+#define ATI_HBR_ENABLE 0x10
+
+static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
+                              int dev_id, unsigned char *buf, int *eld_size)
+{
+       WARN_ON(dev_id != 0);
+       /* call hda_eld.c ATI/AMD-specific function */
+       return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size,
+                                   is_amdhdmi_rev3_or_later(codec));
+}
+
+static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
+                                       hda_nid_t pin_nid, int dev_id, int ca,
+                                       int active_channels, int conn_type)
+{
+       WARN_ON(dev_id != 0);
+       snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
+}
+
+static int atihdmi_paired_swap_fc_lfe(int pos)
+{
+       /*
+        * ATI/AMD have automatic FC/LFE swap built-in
+        * when in pairwise mapping mode.
+        */
+
+       switch (pos) {
+               /* see channel_allocations[].speakers[] */
+               case 2: return 3;
+               case 3: return 2;
+               default: break;
+       }
+
+       return pos;
+}
+
+static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
+                       int ca, int chs, unsigned char *map)
+{
+       struct hdac_cea_channel_speaker_allocation *cap;
+       int i, j;
+
+       /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
+
+       cap = snd_hdac_get_ch_alloc_from_ca(ca);
+       for (i = 0; i < chs; ++i) {
+               int mask = snd_hdac_chmap_to_spk_mask(map[i]);
+               bool ok = false;
+               bool companion_ok = false;
+
+               if (!mask)
+                       continue;
+
+               for (j = 0 + i % 2; j < 8; j += 2) {
+                       int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);
+                       if (cap->speakers[chan_idx] == mask) {
+                               /* channel is in a supported position */
+                               ok = true;
+
+                               if (i % 2 == 0 && i + 1 < chs) {
+                                       /* even channel, check the odd companion */
+                                       int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
+                                       int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]);
+                                       int comp_mask_act = cap->speakers[comp_chan_idx];
+
+                                       if (comp_mask_req == comp_mask_act)
+                                               companion_ok = true;
+                                       else
+                                               return -EINVAL;
+                               }
+                               break;
+                       }
+               }
+
+               if (!ok)
+                       return -EINVAL;
+
+               if (companion_ok)
+                       i++; /* companion channel already checked */
+       }
+
+       return 0;
+}
+
+static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac,
+               hda_nid_t pin_nid, int hdmi_slot, int stream_channel)
+{
+       struct hda_codec *codec = hdac_to_hda_codec(hdac);
+       int verb;
+       int ati_channel_setup = 0;
+
+       if (hdmi_slot > 7)
+               return -EINVAL;
+
+       if (!has_amd_full_remap_support(codec)) {
+               hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);
+
+               /* In case this is an odd slot but without stream channel, do not
+                * disable the slot since the corresponding even slot could have a
+                * channel. In case neither have a channel, the slot pair will be
+                * disabled when this function is called for the even slot. */
+               if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
+                       return 0;
+
+               hdmi_slot -= hdmi_slot % 2;
+
+               if (stream_channel != 0xf)
+                       stream_channel -= stream_channel % 2;
+       }
+
+       verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;
+
+       /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */
+
+       if (stream_channel != 0xf)
+               ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;
+
+       return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
+}
+
+static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac,
+                               hda_nid_t pin_nid, int asp_slot)
+{
+       struct hda_codec *codec = hdac_to_hda_codec(hdac);
+       bool was_odd = false;
+       int ati_asp_slot = asp_slot;
+       int verb;
+       int ati_channel_setup;
+
+       if (asp_slot > 7)
+               return -EINVAL;
+
+       if (!has_amd_full_remap_support(codec)) {
+               ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
+               if (ati_asp_slot % 2 != 0) {
+                       ati_asp_slot -= 1;
+                       was_odd = true;
+               }
+       }
+
+       verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;
+
+       ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);
+
+       if (!(ati_channel_setup & ATI_OUT_ENABLE))
+               return 0xf;
+
+       return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
+}
+
+static int atihdmi_paired_chmap_cea_alloc_validate_get_type(
+               struct hdac_chmap *chmap,
+               struct hdac_cea_channel_speaker_allocation *cap,
+               int channels)
+{
+       int c;
+
+       /*
+        * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
+        * we need to take that into account (a single channel may take 2
+        * channel slots if we need to carry a silent channel next to it).
+        * On Rev3+ AMD codecs this function is not used.
+        */
+       int chanpairs = 0;
+
+       /* We only produce even-numbered channel count TLVs */
+       if ((channels % 2) != 0)
+               return -1;
+
+       for (c = 0; c < 7; c += 2) {
+               if (cap->speakers[c] || cap->speakers[c+1])
+                       chanpairs++;
+       }
+
+       if (chanpairs * 2 != channels)
+               return -1;
+
+       return SNDRV_CTL_TLVT_CHMAP_PAIRED;
+}
+
+static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
+               struct hdac_cea_channel_speaker_allocation *cap,
+               unsigned int *chmap, int channels)
+{
+       /* produce paired maps for pre-rev3 ATI/AMD codecs */
+       int count = 0;
+       int c;
+
+       for (c = 7; c >= 0; c--) {
+               int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
+               int spk = cap->speakers[chan];
+               if (!spk) {
+                       /* add N/A channel if the companion channel is occupied */
+                       if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
+                               chmap[count++] = SNDRV_CHMAP_NA;
+
+                       continue;
+               }
+
+               chmap[count++] = snd_hdac_spk_to_chmap(spk);
+       }
+
+       WARN_ON(count != channels);
+}
+
+static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
+                                int dev_id, bool hbr)
+{
+       int hbr_ctl, hbr_ctl_new;
+
+       WARN_ON(dev_id != 0);
+
+       hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
+       if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
+               if (hbr)
+                       hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
+               else
+                       hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
+
+               codec_dbg(codec,
+                         "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n",
+                               pin_nid,
+                               hbr_ctl == hbr_ctl_new ? "" : "new-",
+                               hbr_ctl_new);
+
+               if (hbr_ctl != hbr_ctl_new)
+                       snd_hda_codec_write(codec, pin_nid, 0,
+                                               ATI_VERB_SET_HBR_CONTROL,
+                                               hbr_ctl_new);
+
+       } else if (hbr)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
+                               hda_nid_t pin_nid, int dev_id,
+                               u32 stream_tag, int format)
+{
+       if (is_amdhdmi_rev3_or_later(codec)) {
+               int ramp_rate = 180; /* default as per AMD spec */
+               /* disable ramp-up/down for non-pcm as per AMD spec */
+               if (format & AC_FMT_TYPE_NON_PCM)
+                       ramp_rate = 0;
+
+               snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
+       }
+
+       return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
+                                stream_tag, format);
+}
+
+
+static int atihdmi_init(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec = codec->spec;
+       int pin_idx, err;
+
+       err = generic_hdmi_init(codec);
+
+       if (err)
+               return err;
+
+       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
+
+               /* make sure downmix information in infoframe is zero */
+               snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);
+
+               /* enable channel-wise remap mode if supported */
+               if (has_amd_full_remap_support(codec))
+                       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+                                           ATI_VERB_SET_MULTICHANNEL_MODE,
+                                           ATI_MULTICHANNEL_MODE_SINGLE);
+       }
+       codec->auto_runtime_pm = 1;
+
+       return 0;
+}
+
+/* map from pin NID to port; port is 0-based */
+/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */
+static int atihdmi_pin2port(void *audio_ptr, int pin_nid)
+{
+       return pin_nid / 2 - 1;
+}
+
+/* reverse-map from port to pin NID: see above */
+static int atihdmi_port2pin(struct hda_codec *codec, int port)
+{
+       return port * 2 + 3;
+}
+
+static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
+       .pin2port = atihdmi_pin2port,
+       .pin_eld_notify = generic_acomp_pin_eld_notify,
+       .master_bind = generic_acomp_master_bind,
+       .master_unbind = generic_acomp_master_unbind,
+};
+
+static int patch_atihdmi(struct hda_codec *codec)
+{
+       struct hdmi_spec *spec;
+       struct hdmi_spec_per_cvt *per_cvt;
+       int err, cvt_idx;
+
+       err = patch_generic_hdmi(codec);
+
+       if (err)
+               return err;
+
+       codec->patch_ops.init = atihdmi_init;
+
+       spec = codec->spec;
+
+       spec->static_pcm_mapping = true;
+
+       spec->ops.pin_get_eld = atihdmi_pin_get_eld;
+       spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
+       spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
+       spec->ops.setup_stream = atihdmi_setup_stream;
+
+       spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
+       spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;
+
+       if (!has_amd_full_remap_support(codec)) {
+               /* override to ATI/AMD-specific versions with pairwise mapping */
+               spec->chmap.ops.chmap_cea_alloc_validate_get_type =
+                       atihdmi_paired_chmap_cea_alloc_validate_get_type;
+               spec->chmap.ops.cea_alloc_to_tlv_chmap =
+                               atihdmi_paired_cea_alloc_to_tlv_chmap;
+               spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate;
+       }
+
+       /* ATI/AMD converters do not advertise all of their capabilities */
+       for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
+               per_cvt = get_cvt(spec, cvt_idx);
+               per_cvt->channels_max = max(per_cvt->channels_max, 8u);
+               per_cvt->rates |= SUPPORTED_RATES;
+               per_cvt->formats |= SUPPORTED_FORMATS;
+               per_cvt->maxbps = max(per_cvt->maxbps, 24u);
+       }
+
+       spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
+
+       /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
+        * the link-down as is.  Tell the core to allow it.
+        */
+       codec->link_down_at_suspend = 1;
+
+       generic_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin);
+
+       return 0;
+}
+
+/* VIA HDMI Implementation */
+#define VIAHDMI_CVT_NID        0x02    /* audio converter1 */
+#define VIAHDMI_PIN_NID        0x03    /* HDMI output pin1 */
+
+static int patch_via_hdmi(struct hda_codec *codec)
+{
+       return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
+}
+
+static int patch_gf_hdmi(struct hda_codec *codec)
+{
+       int err;
+
+       err = patch_generic_hdmi(codec);
+       if (err)
+               return err;
+
+       /*
+        * Glenfly GPUs have two codecs, stream switches from one codec to
+        * another, need to do actual clean-ups in codec_cleanup_stream
+        */
+       codec->no_sticky_stream = 1;
+       return 0;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_hdmi[] = {
+HDA_CODEC_ENTRY(0x00147a47, "Loongson HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI",      patch_atihdmi),
+HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI",      patch_atihdmi),
+HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI",  patch_atihdmi),
+HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI",       patch_atihdmi),
+HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI",      patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI",     patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",   patch_nvhdmi_8ch_7x),
+HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",      patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP",  patch_nvhdmi_legacy),
+/* 17 is known to be absent */
+HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP",  patch_nvhdmi_legacy),
+HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI",    patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI",   patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI",   patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP",        patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
+HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP",  patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP",        patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP",  patch_tegra234_hdmi),
+HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",      patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP",  patch_nvhdmi),
+HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",      patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI",   patch_nvhdmi_2ch),
+HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP",        patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x67663d83, "Arise 83 HDMI/DP",        patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x67663d84, "Arise 84 HDMI/DP",        patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x67663d85, "Arise 85 HDMI/DP",        patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x67663d86, "Arise 86 HDMI/DP",        patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x67663d87, "Arise 87 HDMI/DP",        patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",   patch_via_hdmi),
+HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",   patch_via_hdmi),
+HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f87, "ZX-100S HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f88, "KX-5000 HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f89, "KX-5000 HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f8a, "KX-6000 HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f8b, "KX-6000 HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f8c, "KX-6000G HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f8d, "KX-6000G HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f8e, "KX-7000 HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f8f, "KX-7000 HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x1d179f90, "KX-7000 HDMI/DP", patch_gf_hdmi),
+HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI",   patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi),
+HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI",   patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI",    patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI",  patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI",   patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI",        patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi),
+HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",    patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",  patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",    patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",    patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",   patch_i915_hsw_hdmi),
+HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi),
+HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
+HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI",    patch_i915_icl_hdmi),
+HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI",  patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI",        patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI",  patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI", patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI",        patch_i915_tgl_hdmi),
+HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
+HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI",        patch_i915_icl_hdmi),
+HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI",        patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI", patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI",      patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI", patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI",       patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI",       patch_i915_adlp_hdmi),
+HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
+HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",        patch_i915_byt_hdmi),
+HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",   patch_i915_byt_hdmi),
+HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI",  patch_generic_hdmi),
+/* special ID for generic HDMI */
+HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),
+{} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("HDMI HD-audio codec");
+MODULE_ALIAS("snd-hda-codec-intelhdmi");
+MODULE_ALIAS("snd-hda-codec-nvhdmi");
+MODULE_ALIAS("snd-hda-codec-atihdmi");
+
+static struct hda_codec_driver hdmi_driver = {
+       .id = snd_hda_id_hdmi,
+};
+
+module_hda_codec_driver(hdmi_driver);
diff --git a/sound/hda/codecs/helpers/hp_x360.c b/sound/hda/codecs/helpers/hp_x360.c
new file mode 100644 (file)
index 0000000..969542c
--- /dev/null
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Fixes for HP X360 laptops with top B&O speakers
+ * to be included from codec driver
+ */
+
+static void alc295_fixup_hp_top_speakers(struct hda_codec *codec,
+               const struct hda_fixup *fix, int action)
+{
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x17, 0x90170110 },
+               { }
+       };
+       static const struct coef_fw alc295_hp_speakers_coefs[] = {
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003f), WRITE_COEF(0x28, 0x1000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0004), WRITE_COEF(0x28, 0x0600), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0006), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0xc0c0), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0008), WRITE_COEF(0x28, 0xb000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x002e), WRITE_COEF(0x28, 0x0800), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x00c1), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x0320), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0039), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003b), WRITE_COEF(0x28, 0xffff), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003c), WRITE_COEF(0x28, 0xffd0), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0080), WRITE_COEF(0x28, 0x0880), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x0dfe), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0018), WRITE_COEF(0x28, 0x0219), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x005d), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x9142), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c0), WRITE_COEF(0x28, 0x01ce), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c1), WRITE_COEF(0x28, 0xed0c), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c2), WRITE_COEF(0x28, 0x1c00), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c3), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c4), WRITE_COEF(0x28, 0x0200), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c5), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c6), WRITE_COEF(0x28, 0x0399), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c7), WRITE_COEF(0x28, 0x2330), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c8), WRITE_COEF(0x28, 0x1e5d), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c9), WRITE_COEF(0x28, 0x6eff), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00ca), WRITE_COEF(0x28, 0x01c0), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cb), WRITE_COEF(0x28, 0xed0c), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cc), WRITE_COEF(0x28, 0x1c00), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cd), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00ce), WRITE_COEF(0x28, 0x0200), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cf), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d0), WRITE_COEF(0x28, 0x0399), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d1), WRITE_COEF(0x28, 0x2330), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d2), WRITE_COEF(0x28, 0x1e5d), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d3), WRITE_COEF(0x28, 0x6eff), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0062), WRITE_COEF(0x28, 0x8000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0063), WRITE_COEF(0x28, 0x5f5f), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0064), WRITE_COEF(0x28, 0x1000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0065), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0066), WRITE_COEF(0x28, 0x4004), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0067), WRITE_COEF(0x28, 0x0802), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0068), WRITE_COEF(0x28, 0x890f), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0069), WRITE_COEF(0x28, 0xe021), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0070), WRITE_COEF(0x28, 0x8012), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0071), WRITE_COEF(0x28, 0x3450), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0072), WRITE_COEF(0x28, 0x0123), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0073), WRITE_COEF(0x28, 0x4543), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0074), WRITE_COEF(0x28, 0x2100), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0075), WRITE_COEF(0x28, 0x4321), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0076), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0050), WRITE_COEF(0x28, 0x8200), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0051), WRITE_COEF(0x28, 0x0707), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0052), WRITE_COEF(0x28, 0x4090), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0090), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x721f), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0012), WRITE_COEF(0x28, 0xebeb), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x009e), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0060), WRITE_COEF(0x28, 0x2213), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0006), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003f), WRITE_COEF(0x28, 0x3000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0004), WRITE_COEF(0x28, 0x0500), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0040), WRITE_COEF(0x28, 0x800c), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0046), WRITE_COEF(0x28, 0xc22e), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x004b), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
+               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0050), WRITE_COEF(0x28, 0x82ec), WRITE_COEF(0x29, 0xb024),
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               alc295_fixup_disable_dac3(codec, fix, action);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               alc_process_coef_fw(codec, alc295_hp_speakers_coefs);
+               break;
+       }
+}
diff --git a/sound/hda/codecs/helpers/ideapad_hotkey_led.c b/sound/hda/codecs/helpers/ideapad_hotkey_led.c
new file mode 100644 (file)
index 0000000..c10d979
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Ideapad helper functions for Lenovo Ideapad LED control,
+ * It should be included from codec driver.
+ */
+
+#if IS_ENABLED(CONFIG_IDEAPAD_LAPTOP)
+
+#include <linux/acpi.h>
+#include <linux/leds.h>
+
+static bool is_ideapad(struct hda_codec *codec)
+{
+       return (codec->core.subsystem_id >> 16 == 0x17aa) &&
+              (acpi_dev_found("LHK2019") || acpi_dev_found("VPC2004"));
+}
+
+static void hda_fixup_ideapad_acpi(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               if (!is_ideapad(codec))
+                       return;
+               snd_hda_gen_add_mute_led_cdev(codec, NULL);
+               snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+       }
+}
+
+#else /* CONFIG_IDEAPAD_LAPTOP */
+
+static void hda_fixup_ideapad_acpi(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+}
+
+#endif /* CONFIG_IDEAPAD_LAPTOP */
diff --git a/sound/hda/codecs/helpers/ideapad_s740.c b/sound/hda/codecs/helpers/ideapad_s740.c
new file mode 100644 (file)
index 0000000..564b908
--- /dev/null
@@ -0,0 +1,492 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Fixes for Lenovo Ideapad S740, to be included from codec driver */
+
+static const struct hda_verb alc285_ideapad_s740_coefs[] = {
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x10 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0320 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0041 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0041 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001d },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x004e },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001d },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x004e },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x002a },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x002a },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0046 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0046 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0044 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0044 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
+{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+{}
+};
+
+static void alc285_fixup_ideapad_s740_coef(struct hda_codec *codec,
+                                          const struct hda_fixup *fix,
+                                          int action)
+{
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_add_verbs(codec, alc285_ideapad_s740_coefs);
+               break;
+       }
+}
diff --git a/sound/hda/codecs/helpers/thinkpad.c b/sound/hda/codecs/helpers/thinkpad.c
new file mode 100644 (file)
index 0000000..de4d8de
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Helper functions for Thinkpad LED control;
+ * to be included from codec driver
+ */
+
+#if IS_ENABLED(CONFIG_THINKPAD_ACPI)
+
+#include <linux/acpi.h>
+#include <linux/leds.h>
+
+static bool is_thinkpad(struct hda_codec *codec)
+{
+       return (codec->core.subsystem_id >> 16 == 0x17aa) &&
+              (acpi_dev_found("LEN0068") || acpi_dev_found("LEN0268") ||
+               acpi_dev_found("IBM0068"));
+}
+
+static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               if (!is_thinkpad(codec))
+                       return;
+               snd_hda_gen_add_mute_led_cdev(codec, NULL);
+               snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+       }
+}
+
+#else /* CONFIG_THINKPAD_ACPI */
+
+static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+}
+
+#endif /* CONFIG_THINKPAD_ACPI */
diff --git a/sound/hda/codecs/realtek.c b/sound/hda/codecs/realtek.c
new file mode 100644 (file)
index 0000000..eea42bf
--- /dev/null
@@ -0,0 +1,13795 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for Realtek ALC codecs
+ *
+ * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
+ *                    PeiSen Hou <pshou@realtek.com.tw>
+ *                    Takashi Iwai <tiwai@suse.de>
+ *                    Jonathan Woithe <jwoithe@just42.net>
+ */
+
+#include <linux/acpi.h>
+#include <linux/cleanup.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/leds.h>
+#include <linux/ctype.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "generic.h"
+#include "side-codecs/hda_component.h"
+
+/* keep halting ALC5505 DSP, for power saving */
+#define HALT_REALTEK_ALC5505
+
+/* extra amp-initialization sequence types */
+enum {
+       ALC_INIT_UNDEFINED,
+       ALC_INIT_NONE,
+       ALC_INIT_DEFAULT,
+};
+
+enum {
+       ALC_HEADSET_MODE_UNKNOWN,
+       ALC_HEADSET_MODE_UNPLUGGED,
+       ALC_HEADSET_MODE_HEADSET,
+       ALC_HEADSET_MODE_MIC,
+       ALC_HEADSET_MODE_HEADPHONE,
+};
+
+enum {
+       ALC_HEADSET_TYPE_UNKNOWN,
+       ALC_HEADSET_TYPE_CTIA,
+       ALC_HEADSET_TYPE_OMTP,
+};
+
+enum {
+       ALC_KEY_MICMUTE_INDEX,
+};
+
+struct alc_customize_define {
+       unsigned int  sku_cfg;
+       unsigned char port_connectivity;
+       unsigned char check_sum;
+       unsigned char customization;
+       unsigned char external_amp;
+       unsigned int  enable_pcbeep:1;
+       unsigned int  platform_type:1;
+       unsigned int  swap:1;
+       unsigned int  override:1;
+       unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
+};
+
+struct alc_coef_led {
+       unsigned int idx;
+       unsigned int mask;
+       unsigned int on;
+       unsigned int off;
+};
+
+struct alc_spec {
+       struct hda_gen_spec gen; /* must be at head */
+
+       /* codec parameterization */
+       struct alc_customize_define cdefine;
+       unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
+       /* GPIO bits */
+       unsigned int gpio_mask;
+       unsigned int gpio_dir;
+       unsigned int gpio_data;
+       bool gpio_write_delay;  /* add a delay before writing gpio_data */
+
+       /* mute LED for HP laptops, see vref_mute_led_set() */
+       int mute_led_polarity;
+       int micmute_led_polarity;
+       hda_nid_t mute_led_nid;
+       hda_nid_t cap_mute_led_nid;
+
+       unsigned int gpio_mute_led_mask;
+       unsigned int gpio_mic_led_mask;
+       struct alc_coef_led mute_led_coef;
+       struct alc_coef_led mic_led_coef;
+       struct mutex coef_mutex;
+
+       hda_nid_t headset_mic_pin;
+       hda_nid_t headphone_mic_pin;
+       int current_headset_mode;
+       int current_headset_type;
+
+       /* hooks */
+       void (*init_hook)(struct hda_codec *codec);
+       void (*power_hook)(struct hda_codec *codec);
+       void (*shutup)(struct hda_codec *codec);
+
+       int init_amp;
+       int codec_variant;      /* flag for other variants */
+       unsigned int has_alc5505_dsp:1;
+       unsigned int no_depop_delay:1;
+       unsigned int done_hp_init:1;
+       unsigned int no_shutup_pins:1;
+       unsigned int ultra_low_power:1;
+       unsigned int has_hs_key:1;
+       unsigned int no_internal_mic_pin:1;
+       unsigned int en_3kpull_low:1;
+       int num_speaker_amps;
+
+       /* for PLL fix */
+       hda_nid_t pll_nid;
+       unsigned int pll_coef_idx, pll_coef_bit;
+       unsigned int coef0;
+       struct input_dev *kb_dev;
+       u8 alc_mute_keycode_map[1];
+
+       /* component binding */
+       struct hda_component_parent comps;
+};
+
+/*
+ * COEF access helper functions
+ */
+
+static void coef_mutex_lock(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       snd_hda_power_up_pm(codec);
+       mutex_lock(&spec->coef_mutex);
+}
+
+static void coef_mutex_unlock(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       mutex_unlock(&spec->coef_mutex);
+       snd_hda_power_down_pm(codec);
+}
+
+static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx)
+{
+       unsigned int val;
+
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+       val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
+       return val;
+}
+
+static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                              unsigned int coef_idx)
+{
+       unsigned int val;
+
+       coef_mutex_lock(codec);
+       val = __alc_read_coefex_idx(codec, nid, coef_idx);
+       coef_mutex_unlock(codec);
+       return val;
+}
+
+#define alc_read_coef_idx(codec, coef_idx) \
+       alc_read_coefex_idx(codec, 0x20, coef_idx)
+
+static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                  unsigned int coef_idx, unsigned int coef_val)
+{
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
+}
+
+static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                unsigned int coef_idx, unsigned int coef_val)
+{
+       coef_mutex_lock(codec);
+       __alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
+       coef_mutex_unlock(codec);
+}
+
+#define alc_write_coef_idx(codec, coef_idx, coef_val) \
+       alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
+
+static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                   unsigned int coef_idx, unsigned int mask,
+                                   unsigned int bits_set)
+{
+       unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
+
+       if (val != -1)
+               __alc_write_coefex_idx(codec, nid, coef_idx,
+                                      (val & ~mask) | bits_set);
+}
+
+static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
+                                 unsigned int coef_idx, unsigned int mask,
+                                 unsigned int bits_set)
+{
+       coef_mutex_lock(codec);
+       __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
+       coef_mutex_unlock(codec);
+}
+
+#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)   \
+       alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
+
+/* a special bypass for COEF 0; read the cached value at the second time */
+static unsigned int alc_get_coef0(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (!spec->coef0)
+               spec->coef0 = alc_read_coef_idx(codec, 0);
+       return spec->coef0;
+}
+
+/* coef writes/updates batch */
+struct coef_fw {
+       unsigned char nid;
+       unsigned char idx;
+       unsigned short mask;
+       unsigned short val;
+};
+
+#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
+       { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
+#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
+#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
+#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
+
+static void alc_process_coef_fw(struct hda_codec *codec,
+                               const struct coef_fw *fw)
+{
+       coef_mutex_lock(codec);
+       for (; fw->nid; fw++) {
+               if (fw->mask == (unsigned short)-1)
+                       __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
+               else
+                       __alc_update_coefex_idx(codec, fw->nid, fw->idx,
+                                               fw->mask, fw->val);
+       }
+       coef_mutex_unlock(codec);
+}
+
+/*
+ * GPIO setup tables, used in initialization
+ */
+
+/* Enable GPIO mask and set output */
+static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->gpio_mask |= mask;
+       spec->gpio_dir |= mask;
+       spec->gpio_data |= mask;
+}
+
+static void alc_write_gpio_data(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                           spec->gpio_data);
+}
+
+static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
+                                bool on)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int oldval = spec->gpio_data;
+
+       if (on)
+               spec->gpio_data |= mask;
+       else
+               spec->gpio_data &= ~mask;
+       if (oldval != spec->gpio_data)
+               alc_write_gpio_data(codec);
+}
+
+static void alc_write_gpio(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (!spec->gpio_mask)
+               return;
+
+       snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
+       snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
+       if (spec->gpio_write_delay)
+               msleep(1);
+       alc_write_gpio_data(codec);
+}
+
+static void alc_fixup_gpio(struct hda_codec *codec, int action,
+                          unsigned int mask)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               alc_setup_gpio(codec, mask);
+}
+
+static void alc_fixup_gpio1(struct hda_codec *codec,
+                           const struct hda_fixup *fix, int action)
+{
+       alc_fixup_gpio(codec, action, 0x01);
+}
+
+static void alc_fixup_gpio2(struct hda_codec *codec,
+                           const struct hda_fixup *fix, int action)
+{
+       alc_fixup_gpio(codec, action, 0x02);
+}
+
+static void alc_fixup_gpio3(struct hda_codec *codec,
+                           const struct hda_fixup *fix, int action)
+{
+       alc_fixup_gpio(codec, action, 0x03);
+}
+
+static void alc_fixup_gpio4(struct hda_codec *codec,
+                           const struct hda_fixup *fix, int action)
+{
+       alc_fixup_gpio(codec, action, 0x04);
+}
+
+static void alc_fixup_micmute_led(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+}
+
+/*
+ * Fix hardware PLL issue
+ * On some codecs, the analog PLL gating control must be off while
+ * the default value is 1.
+ */
+static void alc_fix_pll(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->pll_nid)
+               alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
+                                     1 << spec->pll_coef_bit, 0);
+}
+
+static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
+                            unsigned int coef_idx, unsigned int coef_bit)
+{
+       struct alc_spec *spec = codec->spec;
+       spec->pll_nid = nid;
+       spec->pll_coef_idx = coef_idx;
+       spec->pll_coef_bit = coef_bit;
+       alc_fix_pll(codec);
+}
+
+/* update the master volume per volume-knob's unsol event */
+static void alc_update_knob_master(struct hda_codec *codec,
+                                  struct hda_jack_callback *jack)
+{
+       unsigned int val;
+       struct snd_kcontrol *kctl;
+       struct snd_ctl_elem_value *uctl;
+
+       kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
+       if (!kctl)
+               return;
+       uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
+       if (!uctl)
+               return;
+       val = snd_hda_codec_read(codec, jack->nid, 0,
+                                AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
+       val &= HDA_AMP_VOLMASK;
+       uctl->value.integer.value[0] = val;
+       uctl->value.integer.value[1] = val;
+       kctl->put(kctl, uctl);
+       kfree(uctl);
+}
+
+static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
+{
+       /* For some reason, the res given from ALC880 is broken.
+          Here we adjust it properly. */
+       snd_hda_jack_unsol_event(codec, res >> 2);
+}
+
+/* Change EAPD to verb control */
+static void alc_fill_eapd_coef(struct hda_codec *codec)
+{
+       int coef;
+
+       coef = alc_get_coef0(codec);
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0262:
+               alc_update_coef_idx(codec, 0x7, 0, 1<<5);
+               break;
+       case 0x10ec0267:
+       case 0x10ec0268:
+               alc_update_coef_idx(codec, 0x7, 0, 1<<13);
+               break;
+       case 0x10ec0269:
+               if ((coef & 0x00f0) == 0x0010)
+                       alc_update_coef_idx(codec, 0xd, 0, 1<<14);
+               if ((coef & 0x00f0) == 0x0020)
+                       alc_update_coef_idx(codec, 0x4, 1<<15, 0);
+               if ((coef & 0x00f0) == 0x0030)
+                       alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+               break;
+       case 0x10ec0280:
+       case 0x10ec0284:
+       case 0x10ec0290:
+       case 0x10ec0292:
+               alc_update_coef_idx(codec, 0x4, 1<<15, 0);
+               break;
+       case 0x10ec0225:
+       case 0x10ec0295:
+       case 0x10ec0299:
+               alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
+               fallthrough;
+       case 0x10ec0215:
+       case 0x10ec0236:
+       case 0x10ec0245:
+       case 0x10ec0256:
+       case 0x10ec0257:
+       case 0x10ec0285:
+       case 0x10ec0289:
+               alc_update_coef_idx(codec, 0x36, 1<<13, 0);
+               fallthrough;
+       case 0x10ec0230:
+       case 0x10ec0233:
+       case 0x10ec0235:
+       case 0x10ec0255:
+       case 0x19e58326:
+       case 0x10ec0282:
+       case 0x10ec0283:
+       case 0x10ec0286:
+       case 0x10ec0288:
+       case 0x10ec0298:
+       case 0x10ec0300:
+               alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+               break;
+       case 0x10ec0275:
+               alc_update_coef_idx(codec, 0xe, 0, 1<<0);
+               break;
+       case 0x10ec0287:
+               alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+               alc_write_coef_idx(codec, 0x8, 0x4ab7);
+               break;
+       case 0x10ec0293:
+               alc_update_coef_idx(codec, 0xa, 1<<13, 0);
+               break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+               alc_write_coef_idx(codec, 0x6e, 0x0c25);
+               fallthrough;
+       case 0x10ec0294:
+       case 0x10ec0700:
+       case 0x10ec0701:
+       case 0x10ec0703:
+       case 0x10ec0711:
+               alc_update_coef_idx(codec, 0x10, 1<<15, 0);
+               break;
+       case 0x10ec0662:
+               if ((coef & 0x00f0) == 0x0030)
+                       alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
+               break;
+       case 0x10ec0272:
+       case 0x10ec0273:
+       case 0x10ec0663:
+       case 0x10ec0665:
+       case 0x10ec0670:
+       case 0x10ec0671:
+       case 0x10ec0672:
+               alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
+               break;
+       case 0x10ec0222:
+       case 0x10ec0623:
+               alc_update_coef_idx(codec, 0x19, 1<<13, 0);
+               break;
+       case 0x10ec0668:
+               alc_update_coef_idx(codec, 0x7, 3<<13, 0);
+               break;
+       case 0x10ec0867:
+               alc_update_coef_idx(codec, 0x4, 1<<10, 0);
+               break;
+       case 0x10ec0888:
+               if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030)
+                       alc_update_coef_idx(codec, 0x7, 1<<5, 0);
+               break;
+       case 0x10ec0892:
+       case 0x10ec0897:
+               alc_update_coef_idx(codec, 0x7, 1<<5, 0);
+               break;
+       case 0x10ec0899:
+       case 0x10ec0900:
+       case 0x10ec0b00:
+       case 0x10ec1168:
+       case 0x10ec1220:
+               alc_update_coef_idx(codec, 0x7, 1<<1, 0);
+               break;
+       }
+}
+
+/* additional initialization for ALC888 variants */
+static void alc888_coef_init(struct hda_codec *codec)
+{
+       switch (alc_get_coef0(codec) & 0x00f0) {
+       /* alc888-VA */
+       case 0x00:
+       /* alc888-VB */
+       case 0x10:
+               alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */
+               break;
+       }
+}
+
+/* turn on/off EAPD control (only if available) */
+static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
+{
+       if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+               return;
+       if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
+                                   on ? 2 : 0);
+}
+
+/* turn on/off EAPD controls of the codec */
+static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
+{
+       /* We currently only handle front, HP */
+       static const hda_nid_t pins[] = {
+               0x0f, 0x10, 0x14, 0x15, 0x17, 0
+       };
+       const hda_nid_t *p;
+       for (p = pins; *p; p++)
+               set_eapd(codec, *p, on);
+}
+
+static int find_ext_mic_pin(struct hda_codec *codec);
+
+static void alc_headset_mic_no_shutup(struct hda_codec *codec)
+{
+       const struct hda_pincfg *pin;
+       int mic_pin = find_ext_mic_pin(codec);
+       int i;
+
+       /* don't shut up pins when unloading the driver; otherwise it breaks
+        * the default pin setup at the next load of the driver
+        */
+       if (codec->bus->shutdown)
+               return;
+
+       snd_array_for_each(&codec->init_pins, i, pin) {
+               /* use read here for syncing after issuing each verb */
+               if (pin->nid != mic_pin)
+                       snd_hda_codec_read(codec, pin->nid, 0,
+                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
+       }
+
+       codec->pins_shutup = 1;
+}
+
+static void alc_shutup_pins(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->no_shutup_pins)
+               return;
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x10ec0257:
+       case 0x19e58326:
+       case 0x10ec0283:
+       case 0x10ec0285:
+       case 0x10ec0286:
+       case 0x10ec0287:
+       case 0x10ec0288:
+       case 0x10ec0295:
+       case 0x10ec0298:
+               alc_headset_mic_no_shutup(codec);
+               break;
+       default:
+               snd_hda_shutup_pins(codec);
+               break;
+       }
+}
+
+/* generic shutup callback;
+ * just turning off EAPD and a little pause for avoiding pop-noise
+ */
+static void alc_eapd_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_auto_setup_eapd(codec, false);
+       if (!spec->no_depop_delay)
+               msleep(200);
+       alc_shutup_pins(codec);
+}
+
+/* generic EAPD initialization */
+static void alc_auto_init_amp(struct hda_codec *codec, int type)
+{
+       alc_auto_setup_eapd(codec, true);
+       alc_write_gpio(codec);
+       switch (type) {
+       case ALC_INIT_DEFAULT:
+               switch (codec->core.vendor_id) {
+               case 0x10ec0260:
+                       alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
+                       break;
+               case 0x10ec0880:
+               case 0x10ec0882:
+               case 0x10ec0883:
+               case 0x10ec0885:
+                       alc_update_coef_idx(codec, 7, 0, 0x2030);
+                       break;
+               case 0x10ec0888:
+                       alc888_coef_init(codec);
+                       break;
+               }
+               break;
+       }
+}
+
+/* get a primary headphone pin if available */
+static hda_nid_t alc_get_hp_pin(struct alc_spec *spec)
+{
+       if (spec->gen.autocfg.hp_pins[0])
+               return spec->gen.autocfg.hp_pins[0];
+       if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
+               return spec->gen.autocfg.line_out_pins[0];
+       return 0;
+}
+
+/*
+ * Realtek SSID verification
+ */
+
+/* Could be any non-zero and even value. When used as fixup, tells
+ * the driver to ignore any present sku defines.
+ */
+#define ALC_FIXUP_SKU_IGNORE (2)
+
+static void alc_fixup_sku_ignore(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->cdefine.fixup = 1;
+               spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
+       }
+}
+
+static void alc_fixup_no_depop_delay(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PROBE) {
+               spec->no_depop_delay = 1;
+               codec->depop_delay = 0;
+       }
+}
+
+static int alc_auto_parse_customize_define(struct hda_codec *codec)
+{
+       unsigned int ass, tmp, i;
+       unsigned nid = 0;
+       struct alc_spec *spec = codec->spec;
+
+       spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
+
+       if (spec->cdefine.fixup) {
+               ass = spec->cdefine.sku_cfg;
+               if (ass == ALC_FIXUP_SKU_IGNORE)
+                       return -1;
+               goto do_sku;
+       }
+
+       if (!codec->bus->pci)
+               return -1;
+       ass = codec->core.subsystem_id & 0xffff;
+       if (ass != codec->bus->pci->subsystem_device && (ass & 1))
+               goto do_sku;
+
+       nid = 0x1d;
+       if (codec->core.vendor_id == 0x10ec0260)
+               nid = 0x17;
+       ass = snd_hda_codec_get_pincfg(codec, nid);
+
+       if (!(ass & 1)) {
+               codec_info(codec, "%s: SKU not ready 0x%08x\n",
+                          codec->core.chip_name, ass);
+               return -1;
+       }
+
+       /* check sum */
+       tmp = 0;
+       for (i = 1; i < 16; i++) {
+               if ((ass >> i) & 1)
+                       tmp++;
+       }
+       if (((ass >> 16) & 0xf) != tmp)
+               return -1;
+
+       spec->cdefine.port_connectivity = ass >> 30;
+       spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
+       spec->cdefine.check_sum = (ass >> 16) & 0xf;
+       spec->cdefine.customization = ass >> 8;
+do_sku:
+       spec->cdefine.sku_cfg = ass;
+       spec->cdefine.external_amp = (ass & 0x38) >> 3;
+       spec->cdefine.platform_type = (ass & 0x4) >> 2;
+       spec->cdefine.swap = (ass & 0x2) >> 1;
+       spec->cdefine.override = ass & 0x1;
+
+       codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
+                  nid, spec->cdefine.sku_cfg);
+       codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
+                  spec->cdefine.port_connectivity);
+       codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
+       codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
+       codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
+       codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
+       codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
+       codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
+       codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
+
+       return 0;
+}
+
+/* return the position of NID in the list, or -1 if not found */
+static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+       int i;
+       for (i = 0; i < nums; i++)
+               if (list[i] == nid)
+                       return i;
+       return -1;
+}
+/* return true if the given NID is found in the list */
+static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
+{
+       return find_idx_in_nid_list(nid, list, nums) >= 0;
+}
+
+/* check subsystem ID and set up device-specific initialization;
+ * return 1 if initialized, 0 if invalid SSID
+ */
+/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
+ *     31 ~ 16 :       Manufacture ID
+ *     15 ~ 8  :       SKU ID
+ *     7  ~ 0  :       Assembly ID
+ *     port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
+ */
+static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
+{
+       unsigned int ass, tmp, i;
+       unsigned nid;
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->cdefine.fixup) {
+               ass = spec->cdefine.sku_cfg;
+               if (ass == ALC_FIXUP_SKU_IGNORE)
+                       return 0;
+               goto do_sku;
+       }
+
+       ass = codec->core.subsystem_id & 0xffff;
+       if (codec->bus->pci &&
+           ass != codec->bus->pci->subsystem_device && (ass & 1))
+               goto do_sku;
+
+       /* invalid SSID, check the special NID pin defcfg instead */
+       /*
+        * 31~30        : port connectivity
+        * 29~21        : reserve
+        * 20           : PCBEEP input
+        * 19~16        : Check sum (15:1)
+        * 15~1         : Custom
+        * 0            : override
+       */
+       nid = 0x1d;
+       if (codec->core.vendor_id == 0x10ec0260)
+               nid = 0x17;
+       ass = snd_hda_codec_get_pincfg(codec, nid);
+       codec_dbg(codec,
+                 "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
+                  ass, nid);
+       if (!(ass & 1))
+               return 0;
+       if ((ass >> 30) != 1)   /* no physical connection */
+               return 0;
+
+       /* check sum */
+       tmp = 0;
+       for (i = 1; i < 16; i++) {
+               if ((ass >> i) & 1)
+                       tmp++;
+       }
+       if (((ass >> 16) & 0xf) != tmp)
+               return 0;
+do_sku:
+       codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
+                  ass & 0xffff, codec->core.vendor_id);
+       /*
+        * 0 : override
+        * 1 :  Swap Jack
+        * 2 : 0 --> Desktop, 1 --> Laptop
+        * 3~5 : External Amplifier control
+        * 7~6 : Reserved
+       */
+       tmp = (ass & 0x38) >> 3;        /* external Amp control */
+       if (spec->init_amp == ALC_INIT_UNDEFINED) {
+               switch (tmp) {
+               case 1:
+                       alc_setup_gpio(codec, 0x01);
+                       break;
+               case 3:
+                       alc_setup_gpio(codec, 0x02);
+                       break;
+               case 7:
+                       alc_setup_gpio(codec, 0x04);
+                       break;
+               case 5:
+               default:
+                       spec->init_amp = ALC_INIT_DEFAULT;
+                       break;
+               }
+       }
+
+       /* is laptop or Desktop and enable the function "Mute internal speaker
+        * when the external headphone out jack is plugged"
+        */
+       if (!(ass & 0x8000))
+               return 1;
+       /*
+        * 10~8 : Jack location
+        * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
+        * 14~13: Resvered
+        * 15   : 1 --> enable the function "Mute internal speaker
+        *              when the external headphone out jack is plugged"
+        */
+       if (!alc_get_hp_pin(spec)) {
+               hda_nid_t nid;
+               tmp = (ass >> 11) & 0x3;        /* HP to chassis */
+               nid = ports[tmp];
+               if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
+                                     spec->gen.autocfg.line_outs))
+                       return 1;
+               spec->gen.autocfg.hp_pins[0] = nid;
+       }
+       return 1;
+}
+
+/* Check the validity of ALC subsystem-id
+ * ports contains an array of 4 pin NIDs for port-A, E, D and I */
+static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
+{
+       if (!alc_subsystem_id(codec, ports)) {
+               struct alc_spec *spec = codec->spec;
+               if (spec->init_amp == ALC_INIT_UNDEFINED) {
+                       codec_dbg(codec,
+                                 "realtek: Enable default setup for auto mode as fallback\n");
+                       spec->init_amp = ALC_INIT_DEFAULT;
+               }
+       }
+}
+
+/* inverted digital-mic */
+static void alc_fixup_inv_dmic(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->gen.inv_dmic_split = 1;
+}
+
+
+static int alc_build_controls(struct hda_codec *codec)
+{
+       int err;
+
+       err = snd_hda_gen_build_controls(codec);
+       if (err < 0)
+               return err;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
+       return 0;
+}
+
+
+/*
+ * Common callbacks
+ */
+
+static void alc_pre_init(struct hda_codec *codec)
+{
+       alc_fill_eapd_coef(codec);
+}
+
+#define is_s3_resume(codec) \
+       ((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
+#define is_s4_resume(codec) \
+       ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
+#define is_s4_suspend(codec) \
+       ((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)
+
+static int alc_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       /* hibernation resume needs the full chip initialization */
+       if (is_s4_resume(codec))
+               alc_pre_init(codec);
+
+       if (spec->init_hook)
+               spec->init_hook(codec);
+
+       spec->gen.skip_verbs = 1; /* applied in below */
+       snd_hda_gen_init(codec);
+       alc_fix_pll(codec);
+       alc_auto_init_amp(codec, spec->init_amp);
+       snd_hda_apply_verbs(codec); /* apply verbs here after own init */
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+       return 0;
+}
+
+/* forward declaration */
+static const struct component_master_ops comp_master_ops;
+
+static void alc_free(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec)
+               hda_component_manager_free(&spec->comps, &comp_master_ops);
+
+       snd_hda_gen_free(codec);
+}
+
+static inline void alc_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (!snd_hda_get_bool_hint(codec, "shutup"))
+               return; /* disabled explicitly by hints */
+
+       if (spec && spec->shutup)
+               spec->shutup(codec);
+       else
+               alc_shutup_pins(codec);
+}
+
+static void alc_power_eapd(struct hda_codec *codec)
+{
+       alc_auto_setup_eapd(codec, false);
+}
+
+static int alc_suspend(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       alc_shutup(codec);
+       if (spec && spec->power_hook)
+               spec->power_hook(codec);
+       return 0;
+}
+
+static int alc_resume(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (!spec->no_depop_delay)
+               msleep(150); /* to avoid pop noise */
+       codec->patch_ops.init(codec);
+       snd_hda_regmap_sync(codec);
+       hda_call_check_power_status(codec, 0x01);
+       return 0;
+}
+
+/*
+ */
+static const struct hda_codec_ops alc_patch_ops = {
+       .build_controls = alc_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = alc_init,
+       .free = alc_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .resume = alc_resume,
+       .suspend = alc_suspend,
+       .check_power_status = snd_hda_gen_check_power_status,
+};
+
+
+#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
+
+/*
+ * Rename codecs appropriately from COEF value or subvendor id
+ */
+struct alc_codec_rename_table {
+       unsigned int vendor_id;
+       unsigned short coef_mask;
+       unsigned short coef_bits;
+       const char *name;
+};
+
+struct alc_codec_rename_pci_table {
+       unsigned int codec_vendor_id;
+       unsigned short pci_subvendor;
+       unsigned short pci_subdevice;
+       const char *name;
+};
+
+static const struct alc_codec_rename_table rename_tbl[] = {
+       { 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
+       { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
+       { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
+       { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
+       { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
+       { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
+       { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
+       { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
+       { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
+       { 0x10ec0662, 0xffff, 0x4020, "ALC656" },
+       { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
+       { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
+       { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
+       { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
+       { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
+       { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
+       { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
+       { } /* terminator */
+};
+
+static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
+       { 0x10ec0280, 0x1028, 0, "ALC3220" },
+       { 0x10ec0282, 0x1028, 0, "ALC3221" },
+       { 0x10ec0283, 0x1028, 0, "ALC3223" },
+       { 0x10ec0288, 0x1028, 0, "ALC3263" },
+       { 0x10ec0292, 0x1028, 0, "ALC3226" },
+       { 0x10ec0293, 0x1028, 0, "ALC3235" },
+       { 0x10ec0255, 0x1028, 0, "ALC3234" },
+       { 0x10ec0668, 0x1028, 0, "ALC3661" },
+       { 0x10ec0275, 0x1028, 0, "ALC3260" },
+       { 0x10ec0899, 0x1028, 0, "ALC3861" },
+       { 0x10ec0298, 0x1028, 0, "ALC3266" },
+       { 0x10ec0236, 0x1028, 0, "ALC3204" },
+       { 0x10ec0256, 0x1028, 0, "ALC3246" },
+       { 0x10ec0225, 0x1028, 0, "ALC3253" },
+       { 0x10ec0295, 0x1028, 0, "ALC3254" },
+       { 0x10ec0299, 0x1028, 0, "ALC3271" },
+       { 0x10ec0670, 0x1025, 0, "ALC669X" },
+       { 0x10ec0676, 0x1025, 0, "ALC679X" },
+       { 0x10ec0282, 0x1043, 0, "ALC3229" },
+       { 0x10ec0233, 0x1043, 0, "ALC3236" },
+       { 0x10ec0280, 0x103c, 0, "ALC3228" },
+       { 0x10ec0282, 0x103c, 0, "ALC3227" },
+       { 0x10ec0286, 0x103c, 0, "ALC3242" },
+       { 0x10ec0290, 0x103c, 0, "ALC3241" },
+       { 0x10ec0668, 0x103c, 0, "ALC3662" },
+       { 0x10ec0283, 0x17aa, 0, "ALC3239" },
+       { 0x10ec0292, 0x17aa, 0, "ALC3232" },
+       { 0x10ec0257, 0x12f0, 0, "ALC3328" },
+       { } /* terminator */
+};
+
+static int alc_codec_rename_from_preset(struct hda_codec *codec)
+{
+       const struct alc_codec_rename_table *p;
+       const struct alc_codec_rename_pci_table *q;
+
+       for (p = rename_tbl; p->vendor_id; p++) {
+               if (p->vendor_id != codec->core.vendor_id)
+                       continue;
+               if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
+                       return alc_codec_rename(codec, p->name);
+       }
+
+       if (!codec->bus->pci)
+               return 0;
+       for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
+               if (q->codec_vendor_id != codec->core.vendor_id)
+                       continue;
+               if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
+                       continue;
+               if (!q->pci_subdevice ||
+                   q->pci_subdevice == codec->bus->pci->subsystem_device)
+                       return alc_codec_rename(codec, q->name);
+       }
+
+       return 0;
+}
+
+
+/*
+ * Digital-beep handlers
+ */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new alc_beep_mixer[] = {
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
+       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
+};
+
+/* set up and create beep controls */
+static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid,
+                       int idx, int dir)
+{
+       struct snd_kcontrol_new *knew;
+       unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
+               knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+                                           &alc_beep_mixer[i]);
+               if (!knew)
+                       return -ENOMEM;
+               knew->private_value = beep_amp;
+       }
+       return 0;
+}
+
+static const struct snd_pci_quirk beep_allow_list[] = {
+       SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
+       SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
+       SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
+       SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
+       SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
+       SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
+       SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
+       SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
+       /* denylist -- no beep available */
+       SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0),
+       SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),
+       {}
+};
+
+static inline int has_cdefine_beep(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       const struct snd_pci_quirk *q;
+       q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list);
+       if (q)
+               return q->value;
+       return spec->cdefine.enable_pcbeep;
+}
+#else
+#define set_beep_amp(spec, nid, idx, dir)      0
+#define has_cdefine_beep(codec)                0
+#endif
+
+/* parse the BIOS configuration and set up the alc_spec */
+/* return 1 if successful, 0 if the proper config is not found,
+ * or a negative error code
+ */
+static int alc_parse_auto_config(struct hda_codec *codec,
+                                const hda_nid_t *ignore_nids,
+                                const hda_nid_t *ssid_nids)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+       int err;
+
+       err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
+                                      spec->parse_flags);
+       if (err < 0)
+               return err;
+
+       if (ssid_nids)
+               alc_ssid_check(codec, ssid_nids);
+
+       err = snd_hda_gen_parse_auto_config(codec, cfg);
+       if (err < 0)
+               return err;
+
+       return 1;
+}
+
+/* common preparation job for alc_spec */
+static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
+{
+       struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       int err;
+
+       if (!spec)
+               return -ENOMEM;
+       codec->spec = spec;
+       snd_hda_gen_spec_init(&spec->gen);
+       spec->gen.mixer_nid = mixer_nid;
+       spec->gen.own_eapd_ctl = 1;
+       codec->single_adc_amp = 1;
+       /* FIXME: do we need this for all Realtek codec models? */
+       codec->spdif_status_reset = 1;
+       codec->forced_resume = 1;
+       codec->patch_ops = alc_patch_ops;
+       mutex_init(&spec->coef_mutex);
+
+       err = alc_codec_rename_from_preset(codec);
+       if (err < 0) {
+               kfree(spec);
+               return err;
+       }
+       return 0;
+}
+
+static int alc880_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
+}
+
+/*
+ * ALC880 fix-ups
+ */
+enum {
+       ALC880_FIXUP_GPIO1,
+       ALC880_FIXUP_GPIO2,
+       ALC880_FIXUP_MEDION_RIM,
+       ALC880_FIXUP_LG,
+       ALC880_FIXUP_LG_LW25,
+       ALC880_FIXUP_W810,
+       ALC880_FIXUP_EAPD_COEF,
+       ALC880_FIXUP_TCL_S700,
+       ALC880_FIXUP_VOL_KNOB,
+       ALC880_FIXUP_FUJITSU,
+       ALC880_FIXUP_F1734,
+       ALC880_FIXUP_UNIWILL,
+       ALC880_FIXUP_UNIWILL_DIG,
+       ALC880_FIXUP_Z71V,
+       ALC880_FIXUP_ASUS_W5A,
+       ALC880_FIXUP_3ST_BASE,
+       ALC880_FIXUP_3ST,
+       ALC880_FIXUP_3ST_DIG,
+       ALC880_FIXUP_5ST_BASE,
+       ALC880_FIXUP_5ST,
+       ALC880_FIXUP_5ST_DIG,
+       ALC880_FIXUP_6ST_BASE,
+       ALC880_FIXUP_6ST,
+       ALC880_FIXUP_6ST_DIG,
+       ALC880_FIXUP_6ST_AUTOMUTE,
+};
+
+/* enable the volume-knob widget support on NID 0x21 */
+static void alc880_fixup_vol_knob(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PROBE)
+               snd_hda_jack_detect_enable_callback(codec, 0x21,
+                                                   alc_update_knob_master);
+}
+
+static const struct hda_fixup alc880_fixups[] = {
+       [ALC880_FIXUP_GPIO1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio1,
+       },
+       [ALC880_FIXUP_GPIO2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio2,
+       },
+       [ALC880_FIXUP_MEDION_RIM] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_GPIO2,
+       },
+       [ALC880_FIXUP_LG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* disable bogus unused pins */
+                       { 0x16, 0x411111f0 },
+                       { 0x18, 0x411111f0 },
+                       { 0x1a, 0x411111f0 },
+                       { }
+               }
+       },
+       [ALC880_FIXUP_LG_LW25] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x0181344f }, /* line-in */
+                       { 0x1b, 0x0321403f }, /* headphone */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_W810] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* disable bogus unused pins */
+                       { 0x17, 0x411111f0 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_GPIO2,
+       },
+       [ALC880_FIXUP_EAPD_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
+                       {}
+               },
+       },
+       [ALC880_FIXUP_TCL_S700] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3070 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_GPIO2,
+       },
+       [ALC880_FIXUP_VOL_KNOB] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc880_fixup_vol_knob,
+       },
+       [ALC880_FIXUP_FUJITSU] = {
+               /* override all pins as BIOS on old Amilo is broken */
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x0121401f }, /* HP */
+                       { 0x15, 0x99030120 }, /* speaker */
+                       { 0x16, 0x99030130 }, /* bass speaker */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x411111f0 }, /* N/A */
+                       { 0x19, 0x01a19950 }, /* mic-in */
+                       { 0x1a, 0x411111f0 }, /* N/A */
+                       { 0x1b, 0x411111f0 }, /* N/A */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x01454140 }, /* SPDIF out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_VOL_KNOB,
+       },
+       [ALC880_FIXUP_F1734] = {
+               /* almost compatible with FUJITSU, but no bass and SPDIF */
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x0121401f }, /* HP */
+                       { 0x15, 0x99030120 }, /* speaker */
+                       { 0x16, 0x411111f0 }, /* N/A */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x411111f0 }, /* N/A */
+                       { 0x19, 0x01a19950 }, /* mic-in */
+                       { 0x1a, 0x411111f0 }, /* N/A */
+                       { 0x1b, 0x411111f0 }, /* N/A */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_VOL_KNOB,
+       },
+       [ALC880_FIXUP_UNIWILL] = {
+               /* need to fix HP and speaker pins to be parsed correctly */
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x0121411f }, /* HP */
+                       { 0x15, 0x99030120 }, /* speaker */
+                       { 0x16, 0x99030130 }, /* bass speaker */
+                       { }
+               },
+       },
+       [ALC880_FIXUP_UNIWILL_DIG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* disable bogus unused pins */
+                       { 0x17, 0x411111f0 },
+                       { 0x19, 0x411111f0 },
+                       { 0x1b, 0x411111f0 },
+                       { 0x1f, 0x411111f0 },
+                       { }
+               }
+       },
+       [ALC880_FIXUP_Z71V] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* set up the whole pins as BIOS is utterly broken */
+                       { 0x14, 0x99030120 }, /* speaker */
+                       { 0x15, 0x0121411f }, /* HP */
+                       { 0x16, 0x411111f0 }, /* N/A */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x01a19950 }, /* mic-in */
+                       { 0x19, 0x411111f0 }, /* N/A */
+                       { 0x1a, 0x01813031 }, /* line-in */
+                       { 0x1b, 0x411111f0 }, /* N/A */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0x0144111e }, /* SPDIF */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_ASUS_W5A] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* set up the whole pins as BIOS is utterly broken */
+                       { 0x14, 0x0121411f }, /* HP */
+                       { 0x15, 0x411111f0 }, /* N/A */
+                       { 0x16, 0x411111f0 }, /* N/A */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x90a60160 }, /* mic */
+                       { 0x19, 0x411111f0 }, /* N/A */
+                       { 0x1a, 0x411111f0 }, /* N/A */
+                       { 0x1b, 0x411111f0 }, /* N/A */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       { 0x1e, 0xb743111e }, /* SPDIF out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_GPIO1,
+       },
+       [ALC880_FIXUP_3ST_BASE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x01014010 }, /* line-out */
+                       { 0x15, 0x411111f0 }, /* N/A */
+                       { 0x16, 0x411111f0 }, /* N/A */
+                       { 0x17, 0x411111f0 }, /* N/A */
+                       { 0x18, 0x01a19c30 }, /* mic-in */
+                       { 0x19, 0x0121411f }, /* HP */
+                       { 0x1a, 0x01813031 }, /* line-in */
+                       { 0x1b, 0x02a19c40 }, /* front-mic */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       /* 0x1e is filled in below */
+                       { 0x1f, 0x411111f0 }, /* N/A */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_3ST] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_3ST_BASE,
+       },
+       [ALC880_FIXUP_3ST_DIG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1e, 0x0144111e }, /* SPDIF */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_3ST_BASE,
+       },
+       [ALC880_FIXUP_5ST_BASE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x01014010 }, /* front */
+                       { 0x15, 0x411111f0 }, /* N/A */
+                       { 0x16, 0x01011411 }, /* CLFE */
+                       { 0x17, 0x01016412 }, /* surr */
+                       { 0x18, 0x01a19c30 }, /* mic-in */
+                       { 0x19, 0x0121411f }, /* HP */
+                       { 0x1a, 0x01813031 }, /* line-in */
+                       { 0x1b, 0x02a19c40 }, /* front-mic */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       /* 0x1e is filled in below */
+                       { 0x1f, 0x411111f0 }, /* N/A */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_5ST] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_5ST_BASE,
+       },
+       [ALC880_FIXUP_5ST_DIG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1e, 0x0144111e }, /* SPDIF */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_5ST_BASE,
+       },
+       [ALC880_FIXUP_6ST_BASE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x01014010 }, /* front */
+                       { 0x15, 0x01016412 }, /* surr */
+                       { 0x16, 0x01011411 }, /* CLFE */
+                       { 0x17, 0x01012414 }, /* side */
+                       { 0x18, 0x01a19c30 }, /* mic-in */
+                       { 0x19, 0x02a19c40 }, /* front-mic */
+                       { 0x1a, 0x01813031 }, /* line-in */
+                       { 0x1b, 0x0121411f }, /* HP */
+                       { 0x1c, 0x411111f0 }, /* N/A */
+                       { 0x1d, 0x411111f0 }, /* N/A */
+                       /* 0x1e is filled in below */
+                       { 0x1f, 0x411111f0 }, /* N/A */
+                       { }
+               }
+       },
+       [ALC880_FIXUP_6ST] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1e, 0x411111f0 }, /* N/A */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_6ST_BASE,
+       },
+       [ALC880_FIXUP_6ST_DIG] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1e, 0x0144111e }, /* SPDIF */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC880_FIXUP_6ST_BASE,
+       },
+       [ALC880_FIXUP_6ST_AUTOMUTE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x0121401f }, /* HP with jack detect */
+                       { }
+               },
+               .chained_before = true,
+               .chain_id = ALC880_FIXUP_6ST_BASE,
+       },
+};
+
+static const struct hda_quirk alc880_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
+       SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
+       SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
+       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
+       SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
+       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
+       SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
+       SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
+       SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
+       SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
+       SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
+       SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
+       SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
+       SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
+       SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
+       SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
+       SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
+       SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
+       SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
+       SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
+       SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
+       SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
+
+       /* Below is the copied entries from alc880_quirks.c.
+        * It's not quite sure whether BIOS sets the correct pin-config table
+        * on these machines, thus they are kept to be compatible with
+        * the old static quirks.  Once when it's confirmed to work without
+        * these overrides, it'd be better to remove.
+        */
+       SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
+       SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
+       SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
+       SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
+       SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
+       SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
+       SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
+       SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
+       SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
+       /* default Intel */
+       SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
+       SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
+       SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
+       {}
+};
+
+static const struct hda_model_fixup alc880_fixup_models[] = {
+       {.id = ALC880_FIXUP_3ST, .name = "3stack"},
+       {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
+       {.id = ALC880_FIXUP_5ST, .name = "5stack"},
+       {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
+       {.id = ALC880_FIXUP_6ST, .name = "6stack"},
+       {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
+       {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
+       {}
+};
+
+
+/*
+ * OK, here we have finally the patch for ALC880
+ */
+static int patch_alc880(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err;
+
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->gen.need_dac_fix = 1;
+       spec->gen.beep_nid = 0x01;
+
+       codec->patch_ops.unsol_event = alc880_unsol_event;
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
+                      alc880_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       /* automatic parse from the BIOS config */
+       err = alc880_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!spec->gen.no_analog) {
+               err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+               if (err < 0)
+                       goto error;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+
+/*
+ * ALC260 support
+ */
+static int alc260_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
+       static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
+       return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
+}
+
+/*
+ * Pin config fixes
+ */
+enum {
+       ALC260_FIXUP_HP_DC5750,
+       ALC260_FIXUP_HP_PIN_0F,
+       ALC260_FIXUP_COEF,
+       ALC260_FIXUP_GPIO1,
+       ALC260_FIXUP_GPIO1_TOGGLE,
+       ALC260_FIXUP_REPLACER,
+       ALC260_FIXUP_HP_B1900,
+       ALC260_FIXUP_KN1,
+       ALC260_FIXUP_FSC_S7020,
+       ALC260_FIXUP_FSC_S7020_JWSE,
+       ALC260_FIXUP_VAIO_PINS,
+};
+
+static void alc260_gpio1_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
+}
+
+static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PROBE) {
+               /* although the machine has only one output pin, we need to
+                * toggle GPIO1 according to the jack state
+                */
+               spec->gen.automute_hook = alc260_gpio1_automute;
+               spec->gen.detect_hp = 1;
+               spec->gen.automute_speaker = 1;
+               spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
+               snd_hda_jack_detect_enable_callback(codec, 0x0f,
+                                                   snd_hda_gen_hp_automute);
+               alc_setup_gpio(codec, 0x01);
+       }
+}
+
+static void alc260_fixup_kn1(struct hda_codec *codec,
+                            const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x0f, 0x02214000 }, /* HP/speaker */
+               { 0x12, 0x90a60160 }, /* int mic */
+               { 0x13, 0x02a19000 }, /* ext mic */
+               { 0x18, 0x01446000 }, /* SPDIF out */
+               /* disable bogus I/O pins */
+               { 0x10, 0x411111f0 },
+               { 0x11, 0x411111f0 },
+               { 0x14, 0x411111f0 },
+               { 0x15, 0x411111f0 },
+               { 0x16, 0x411111f0 },
+               { 0x17, 0x411111f0 },
+               { 0x19, 0x411111f0 },
+               { }
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               spec->init_amp = ALC_INIT_NONE;
+               break;
+       }
+}
+
+static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->init_amp = ALC_INIT_NONE;
+}
+
+static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.add_jack_modes = 1;
+               spec->gen.hp_mic = 1;
+       }
+}
+
+static const struct hda_fixup alc260_fixups[] = {
+       [ALC260_FIXUP_HP_DC5750] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x11, 0x90130110 }, /* speaker */
+                       { }
+               }
+       },
+       [ALC260_FIXUP_HP_PIN_0F] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x0f, 0x01214000 }, /* HP */
+                       { }
+               }
+       },
+       [ALC260_FIXUP_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x1a, AC_VERB_SET_PROC_COEF,  0x3040 },
+                       { }
+               },
+       },
+       [ALC260_FIXUP_GPIO1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio1,
+       },
+       [ALC260_FIXUP_GPIO1_TOGGLE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc260_fixup_gpio1_toggle,
+               .chained = true,
+               .chain_id = ALC260_FIXUP_HP_PIN_0F,
+       },
+       [ALC260_FIXUP_REPLACER] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x1a, AC_VERB_SET_PROC_COEF,  0x3050 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
+       },
+       [ALC260_FIXUP_HP_B1900] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc260_fixup_gpio1_toggle,
+               .chained = true,
+               .chain_id = ALC260_FIXUP_COEF,
+       },
+       [ALC260_FIXUP_KN1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc260_fixup_kn1,
+       },
+       [ALC260_FIXUP_FSC_S7020] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc260_fixup_fsc_s7020,
+       },
+       [ALC260_FIXUP_FSC_S7020_JWSE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc260_fixup_fsc_s7020_jwse,
+               .chained = true,
+               .chain_id = ALC260_FIXUP_FSC_S7020,
+       },
+       [ALC260_FIXUP_VAIO_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* Pin configs are missing completely on some VAIOs */
+                       { 0x0f, 0x01211020 },
+                       { 0x10, 0x0001003f },
+                       { 0x11, 0x411111f0 },
+                       { 0x12, 0x01a15930 },
+                       { 0x13, 0x411111f0 },
+                       { 0x14, 0x411111f0 },
+                       { 0x15, 0x411111f0 },
+                       { 0x16, 0x411111f0 },
+                       { 0x17, 0x411111f0 },
+                       { 0x18, 0x411111f0 },
+                       { 0x19, 0x411111f0 },
+                       { }
+               }
+       },
+};
+
+static const struct hda_quirk alc260_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
+       SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
+       SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
+       SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
+       SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
+       SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
+       SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
+       SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
+       SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
+       SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
+       {}
+};
+
+static const struct hda_model_fixup alc260_fixup_models[] = {
+       {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
+       {.id = ALC260_FIXUP_COEF, .name = "coef"},
+       {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
+       {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
+       {}
+};
+
+/*
+ */
+static int patch_alc260(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err;
+
+       err = alc_alloc_spec(codec, 0x07);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       /* as quite a few machines require HP amp for speaker outputs,
+        * it's easier to enable it unconditionally; even if it's unneeded,
+        * it's almost harmless.
+        */
+       spec->gen.prefer_hp_amp = 1;
+       spec->gen.beep_nid = 0x01;
+
+       spec->shutup = alc_eapd_shutup;
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
+                          alc260_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       /* automatic parse from the BIOS config */
+       err = alc260_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!spec->gen.no_analog) {
+               err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
+               if (err < 0)
+                       goto error;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+
+/*
+ * ALC882/883/885/888/889 support
+ *
+ * ALC882 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration.  Each pin widget can choose any input DACs and a mixer.
+ * Each ADC is connected from a mixer of all inputs.  This makes possible
+ * 6-channel independent captures.
+ *
+ * In addition, an independent DAC for the multi-playback (not used in this
+ * driver yet).
+ */
+
+/*
+ * Pin config fixes
+ */
+enum {
+       ALC882_FIXUP_ABIT_AW9D_MAX,
+       ALC882_FIXUP_LENOVO_Y530,
+       ALC882_FIXUP_PB_M5210,
+       ALC882_FIXUP_ACER_ASPIRE_7736,
+       ALC882_FIXUP_ASUS_W90V,
+       ALC889_FIXUP_CD,
+       ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
+       ALC889_FIXUP_VAIO_TT,
+       ALC888_FIXUP_EEE1601,
+       ALC886_FIXUP_EAPD,
+       ALC882_FIXUP_EAPD,
+       ALC883_FIXUP_EAPD,
+       ALC883_FIXUP_ACER_EAPD,
+       ALC882_FIXUP_GPIO1,
+       ALC882_FIXUP_GPIO2,
+       ALC882_FIXUP_GPIO3,
+       ALC889_FIXUP_COEF,
+       ALC882_FIXUP_ASUS_W2JC,
+       ALC882_FIXUP_ACER_ASPIRE_4930G,
+       ALC882_FIXUP_ACER_ASPIRE_8930G,
+       ALC882_FIXUP_ASPIRE_8930G_VERBS,
+       ALC885_FIXUP_MACPRO_GPIO,
+       ALC889_FIXUP_DAC_ROUTE,
+       ALC889_FIXUP_MBP_VREF,
+       ALC889_FIXUP_IMAC91_VREF,
+       ALC889_FIXUP_MBA11_VREF,
+       ALC889_FIXUP_MBA21_VREF,
+       ALC889_FIXUP_MP11_VREF,
+       ALC889_FIXUP_MP41_VREF,
+       ALC882_FIXUP_INV_DMIC,
+       ALC882_FIXUP_NO_PRIMARY_HP,
+       ALC887_FIXUP_ASUS_BASS,
+       ALC887_FIXUP_BASS_CHMAP,
+       ALC1220_FIXUP_GB_DUAL_CODECS,
+       ALC1220_FIXUP_GB_X570,
+       ALC1220_FIXUP_CLEVO_P950,
+       ALC1220_FIXUP_CLEVO_PB51ED,
+       ALC1220_FIXUP_CLEVO_PB51ED_PINS,
+       ALC887_FIXUP_ASUS_AUDIO,
+       ALC887_FIXUP_ASUS_HMIC,
+       ALCS1200A_FIXUP_MIC_VREF,
+       ALC888VD_FIXUP_MIC_100VREF,
+};
+
+static void alc889_fixup_coef(struct hda_codec *codec,
+                             const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_INIT)
+               return;
+       alc_update_coef_idx(codec, 7, 0, 0x2030);
+}
+
+/* set up GPIO at initialization */
+static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       spec->gpio_write_delay = true;
+       alc_fixup_gpio3(codec, fix, action);
+}
+
+/* Fix the connection of some pins for ALC889:
+ * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
+ * work correctly (bko#42740)
+ */
+static void alc889_fixup_dac_route(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* fake the connections during parsing the tree */
+               static const hda_nid_t conn1[] = { 0x0c, 0x0d };
+               static const hda_nid_t conn2[] = { 0x0e, 0x0f };
+               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+               snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
+               snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2);
+               snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2);
+       } else if (action == HDA_FIXUP_ACT_PROBE) {
+               /* restore the connections */
+               static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
+               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
+               snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
+               snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn);
+               snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn);
+       }
+}
+
+/* Set VREF on HP pin */
+static void alc889_fixup_mbp_vref(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 };
+       struct alc_spec *spec = codec->spec;
+       int i;
+
+       if (action != HDA_FIXUP_ACT_INIT)
+               return;
+       for (i = 0; i < ARRAY_SIZE(nids); i++) {
+               unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
+               if (get_defcfg_device(val) != AC_JACK_HP_OUT)
+                       continue;
+               val = snd_hda_codec_get_pin_target(codec, nids[i]);
+               val |= AC_PINCTL_VREF_80;
+               snd_hda_set_pin_ctl(codec, nids[i], val);
+               spec->gen.keep_vref_in_automute = 1;
+               break;
+       }
+}
+
+static void alc889_fixup_mac_pins(struct hda_codec *codec,
+                                 const hda_nid_t *nids, int num_nids)
+{
+       struct alc_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < num_nids; i++) {
+               unsigned int val;
+               val = snd_hda_codec_get_pin_target(codec, nids[i]);
+               val |= AC_PINCTL_VREF_50;
+               snd_hda_set_pin_ctl(codec, nids[i], val);
+       }
+       spec->gen.keep_vref_in_automute = 1;
+}
+
+/* Set VREF on speaker pins on imac91 */
+static void alc889_fixup_imac91_vref(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t nids[] = { 0x18, 0x1a };
+
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Set VREF on speaker pins on mba11 */
+static void alc889_fixup_mba11_vref(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t nids[] = { 0x18 };
+
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Set VREF on speaker pins on mba21 */
+static void alc889_fixup_mba21_vref(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t nids[] = { 0x18, 0x19 };
+
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
+/* Don't take HP output as primary
+ * Strangely, the speaker output doesn't work on Vaio Z and some Vaio
+ * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
+ */
+static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.no_primary_hp = 1;
+               spec->gen.no_multi_io = 1;
+       }
+}
+
+static void alc_fixup_bass_chmap(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action);
+
+/* For dual-codec configuration, we need to disable some features to avoid
+ * conflicts of kctls and PCM streams
+ */
+static void alc_fixup_dual_codecs(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       /* disable vmaster */
+       spec->gen.suppress_vmaster = 1;
+       /* auto-mute and auto-mic switch don't work with multiple codecs */
+       spec->gen.suppress_auto_mute = 1;
+       spec->gen.suppress_auto_mic = 1;
+       /* disable aamix as well */
+       spec->gen.mixer_nid = 0;
+       /* add location prefix to avoid conflicts */
+       codec->force_pin_prefix = 1;
+}
+
+static void rename_ctl(struct hda_codec *codec, const char *oldname,
+                      const char *newname)
+{
+       struct snd_kcontrol *kctl;
+
+       kctl = snd_hda_find_mixer_ctl(codec, oldname);
+       if (kctl)
+               snd_ctl_rename(codec->card, kctl, newname);
+}
+
+static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
+                                        const struct hda_fixup *fix,
+                                        int action)
+{
+       alc_fixup_dual_codecs(codec, fix, action);
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               /* override card longname to provide a unique UCM profile */
+               strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               /* rename Capture controls depending on the codec */
+               rename_ctl(codec, "Capture Volume",
+                          codec->addr == 0 ?
+                          "Rear-Panel Capture Volume" :
+                          "Front-Panel Capture Volume");
+               rename_ctl(codec, "Capture Switch",
+                          codec->addr == 0 ?
+                          "Rear-Panel Capture Switch" :
+                          "Front-Panel Capture Switch");
+               break;
+       }
+}
+
+static void alc1220_fixup_gb_x570(struct hda_codec *codec,
+                                    const struct hda_fixup *fix,
+                                    int action)
+{
+       static const hda_nid_t conn1[] = { 0x0c };
+       static const struct coef_fw gb_x570_coefs[] = {
+               WRITE_COEF(0x07, 0x03c0),
+               WRITE_COEF(0x1a, 0x01c1),
+               WRITE_COEF(0x1b, 0x0202),
+               WRITE_COEF(0x43, 0x3005),
+               {}
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+               snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               alc_process_coef_fw(codec, gb_x570_coefs);
+               break;
+       }
+}
+
+static void alc1220_fixup_clevo_p950(struct hda_codec *codec,
+                                    const struct hda_fixup *fix,
+                                    int action)
+{
+       static const hda_nid_t conn1[] = { 0x0c };
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       alc_update_coef_idx(codec, 0x7, 0, 0x3c3);
+       /* We therefore want to make sure 0x14 (front headphone) and
+        * 0x1b (speakers) use the stereo DAC 0x02
+        */
+       snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+       snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
+}
+
+static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action);
+
+static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec,
+                                    const struct hda_fixup *fix,
+                                    int action)
+{
+       alc1220_fixup_clevo_p950(codec, fix, action);
+       alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
+}
+
+static void alc887_asus_hp_automute_hook(struct hda_codec *codec,
+                                        struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int vref;
+
+       snd_hda_gen_hp_automute(codec, jack);
+
+       if (spec->gen.hp_jack_present)
+               vref = AC_PINCTL_VREF_80;
+       else
+               vref = AC_PINCTL_VREF_HIZ;
+       snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref);
+}
+
+static void alc887_fixup_asus_jack(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action != HDA_FIXUP_ACT_PROBE)
+               return;
+       snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP);
+       spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook;
+}
+
+static const struct hda_fixup alc882_fixups[] = {
+       [ALC882_FIXUP_ABIT_AW9D_MAX] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x01080104 }, /* side */
+                       { 0x16, 0x01011012 }, /* rear */
+                       { 0x17, 0x01016011 }, /* clfe */
+                       { }
+               }
+       },
+       [ALC882_FIXUP_LENOVO_Y530] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x99130112 }, /* rear int speakers */
+                       { 0x16, 0x99130111 }, /* subwoofer */
+                       { }
+               }
+       },
+       [ALC882_FIXUP_PB_M5210] = {
+               .type = HDA_FIXUP_PINCTLS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, PIN_VREF50 },
+                       {}
+               }
+       },
+       [ALC882_FIXUP_ACER_ASPIRE_7736] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_sku_ignore,
+       },
+       [ALC882_FIXUP_ASUS_W90V] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x99130110 }, /* fix sequence for CLFE */
+                       { }
+               }
+       },
+       [ALC889_FIXUP_CD] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1c, 0x993301f0 }, /* CD */
+                       { }
+               }
+       },
+       [ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC889_FIXUP_CD,
+       },
+       [ALC889_FIXUP_VAIO_TT] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x17, 0x90170111 }, /* hidden surround speaker */
+                       { }
+               }
+       },
+       [ALC888_FIXUP_EEE1601] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
+                       { 0x20, AC_VERB_SET_PROC_COEF,  0x0838 },
+                       { }
+               }
+       },
+       [ALC886_FIXUP_EAPD] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
+                       { }
+               }
+       },
+       [ALC882_FIXUP_EAPD] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
+                       { }
+               }
+       },
+       [ALC883_FIXUP_EAPD] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* change to EAPD mode */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+                       { }
+               }
+       },
+       [ALC883_FIXUP_ACER_EAPD] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* eanable EAPD on Acer laptops */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+                       { }
+               }
+       },
+       [ALC882_FIXUP_GPIO1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio1,
+       },
+       [ALC882_FIXUP_GPIO2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio2,
+       },
+       [ALC882_FIXUP_GPIO3] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio3,
+       },
+       [ALC882_FIXUP_ASUS_W2JC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio1,
+               .chained = true,
+               .chain_id = ALC882_FIXUP_EAPD,
+       },
+       [ALC889_FIXUP_COEF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_coef,
+       },
+       [ALC882_FIXUP_ACER_ASPIRE_4930G] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x99130111 }, /* CLFE speaker */
+                       { 0x17, 0x99130112 }, /* surround speaker */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC882_FIXUP_GPIO1,
+       },
+       [ALC882_FIXUP_ACER_ASPIRE_8930G] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x99130111 }, /* CLFE speaker */
+                       { 0x1b, 0x99130112 }, /* surround speaker */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
+       },
+       [ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
+               /* additional init verbs for Acer Aspire 8930G */
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Enable all DACs */
+                       /* DAC DISABLE/MUTE 1? */
+                       /*  setting bits 1-5 disables DAC nids 0x02-0x06
+                        *  apparently. Init=0x38 */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+                       /* DAC DISABLE/MUTE 2? */
+                       /*  some bit here disables the other DACs.
+                        *  Init=0x4900 */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
+                       /* DMIC fix
+                        * This laptop has a stereo digital microphone.
+                        * The mics are only 1cm apart which makes the stereo
+                        * useless. However, either the mic or the ALC889
+                        * makes the signal become a difference/sum signal
+                        * instead of standard stereo, which is annoying.
+                        * So instead we flip this bit which makes the
+                        * codec replicate the sum signal to both channels,
+                        * turning it into a normal mono mic.
+                        */
+                       /* DMIC_CONTROL? Init value = 0x0001 */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC882_FIXUP_GPIO1,
+       },
+       [ALC885_FIXUP_MACPRO_GPIO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc885_fixup_macpro_gpio,
+       },
+       [ALC889_FIXUP_DAC_ROUTE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_dac_route,
+       },
+       [ALC889_FIXUP_MBP_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_mbp_vref,
+               .chained = true,
+               .chain_id = ALC882_FIXUP_GPIO1,
+       },
+       [ALC889_FIXUP_IMAC91_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_imac91_vref,
+               .chained = true,
+               .chain_id = ALC882_FIXUP_GPIO1,
+       },
+       [ALC889_FIXUP_MBA11_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_mba11_vref,
+               .chained = true,
+               .chain_id = ALC889_FIXUP_MBP_VREF,
+       },
+       [ALC889_FIXUP_MBA21_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_mba21_vref,
+               .chained = true,
+               .chain_id = ALC889_FIXUP_MBP_VREF,
+       },
+       [ALC889_FIXUP_MP11_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_mba11_vref,
+               .chained = true,
+               .chain_id = ALC885_FIXUP_MACPRO_GPIO,
+       },
+       [ALC889_FIXUP_MP41_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_mbp_vref,
+               .chained = true,
+               .chain_id = ALC885_FIXUP_MACPRO_GPIO,
+       },
+       [ALC882_FIXUP_INV_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_inv_dmic,
+       },
+       [ALC882_FIXUP_NO_PRIMARY_HP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc882_fixup_no_primary_hp,
+       },
+       [ALC887_FIXUP_ASUS_BASS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       {0x16, 0x99130130}, /* bass speaker */
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC887_FIXUP_BASS_CHMAP,
+       },
+       [ALC887_FIXUP_BASS_CHMAP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_bass_chmap,
+       },
+       [ALC1220_FIXUP_GB_DUAL_CODECS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc1220_fixup_gb_dual_codecs,
+       },
+       [ALC1220_FIXUP_GB_X570] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc1220_fixup_gb_x570,
+       },
+       [ALC1220_FIXUP_CLEVO_P950] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc1220_fixup_clevo_p950,
+       },
+       [ALC1220_FIXUP_CLEVO_PB51ED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc1220_fixup_clevo_pb51ed,
+       },
+       [ALC1220_FIXUP_CLEVO_PB51ED_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC1220_FIXUP_CLEVO_PB51ED,
+       },
+       [ALC887_FIXUP_ASUS_AUDIO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */
+                       { 0x19, 0x22219420 },
+                       {}
+               },
+       },
+       [ALC887_FIXUP_ASUS_HMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc887_fixup_asus_jack,
+               .chained = true,
+               .chain_id = ALC887_FIXUP_ASUS_AUDIO,
+       },
+       [ALCS1200A_FIXUP_MIC_VREF] = {
+               .type = HDA_FIXUP_PINCTLS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, PIN_VREF50 }, /* rear mic */
+                       { 0x19, PIN_VREF50 }, /* front mic */
+                       {}
+               }
+       },
+       [ALC888VD_FIXUP_MIC_100VREF] = {
+               .type = HDA_FIXUP_PINCTLS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, PIN_VREF100 }, /* headset mic */
+                       {}
+               }
+       },
+};
+
+static const struct hda_quirk alc882_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
+       SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
+                     ALC882_FIXUP_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
+                     ALC882_FIXUP_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
+       SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
+                     ALC882_FIXUP_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
+       SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
+       SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
+       SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
+       SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
+       SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC),
+       SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
+       SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
+       SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
+       SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF),
+       SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
+       SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
+       SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
+       SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
+       SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
+
+       /* All Apple entries are in codec SSIDs */
+       SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
+       SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
+       SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
+       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
+
+       SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF),
+       SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
+       SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
+       SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
+       SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
+       SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
+       SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
+       SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
+       SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
+       SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
+       SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
+       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
+       SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
+       {}
+};
+
+static const struct hda_model_fixup alc882_fixup_models[] = {
+       {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
+       {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
+       {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
+       {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
+       {.id = ALC889_FIXUP_CD, .name = "cd"},
+       {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
+       {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
+       {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
+       {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
+       {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
+       {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
+       {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
+       {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
+       {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
+       {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
+       {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
+       {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
+       {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
+       {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
+       {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
+       {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
+       {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
+       {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
+       {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
+       {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
+       {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
+       {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
+       {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
+       {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
+       {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
+       {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
+       {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
+       {}
+};
+
+static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = {
+       SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950,
+               {0x14, 0x01014010},
+               {0x15, 0x01011012},
+               {0x16, 0x01016011},
+               {0x18, 0x01a19040},
+               {0x19, 0x02a19050},
+               {0x1a, 0x0181304f},
+               {0x1b, 0x0221401f},
+               {0x1e, 0x01456130}),
+       SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950,
+               {0x14, 0x01015010},
+               {0x15, 0x01011012},
+               {0x16, 0x01011011},
+               {0x18, 0x01a11040},
+               {0x19, 0x02a19050},
+               {0x1a, 0x0181104f},
+               {0x1b, 0x0221401f},
+               {0x1e, 0x01451130}),
+       {}
+};
+
+/*
+ * BIOS auto configuration
+ */
+/* almost identical with ALC880 parser... */
+static int alc882_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
+}
+
+/*
+ */
+static int patch_alc882(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err;
+
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0882:
+       case 0x10ec0885:
+       case 0x10ec0900:
+       case 0x10ec0b00:
+       case 0x10ec1220:
+               break;
+       default:
+               /* ALC883 and variants */
+               alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+               break;
+       }
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
+                      alc882_fixups);
+       snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       alc_auto_parse_customize_define(codec);
+
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
+       /* automatic parse from the BIOS config */
+       err = alc882_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!spec->gen.no_analog && spec->gen.beep_nid) {
+               err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+               if (err < 0)
+                       goto error;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+
+/*
+ * ALC262 support
+ */
+static int alc262_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
+}
+
+/*
+ * Pin config fixes
+ */
+enum {
+       ALC262_FIXUP_FSC_H270,
+       ALC262_FIXUP_FSC_S7110,
+       ALC262_FIXUP_HP_Z200,
+       ALC262_FIXUP_TYAN,
+       ALC262_FIXUP_LENOVO_3000,
+       ALC262_FIXUP_BENQ,
+       ALC262_FIXUP_BENQ_T31,
+       ALC262_FIXUP_INV_DMIC,
+       ALC262_FIXUP_INTEL_BAYLEYBAY,
+};
+
+static const struct hda_fixup alc262_fixups[] = {
+       [ALC262_FIXUP_FSC_H270] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0221142f }, /* front HP */
+                       { 0x1b, 0x0121141f }, /* rear HP */
+                       { }
+               }
+       },
+       [ALC262_FIXUP_FSC_S7110] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x90170110 }, /* speaker */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC262_FIXUP_BENQ,
+       },
+       [ALC262_FIXUP_HP_Z200] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x99130120 }, /* internal speaker */
+                       { }
+               }
+       },
+       [ALC262_FIXUP_TYAN] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x1993e1f0 }, /* int AUX */
+                       { }
+               }
+       },
+       [ALC262_FIXUP_LENOVO_3000] = {
+               .type = HDA_FIXUP_PINCTLS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, PIN_VREF50 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC262_FIXUP_BENQ,
+       },
+       [ALC262_FIXUP_BENQ] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
+                       {}
+               }
+       },
+       [ALC262_FIXUP_BENQ_T31] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
+                       {}
+               }
+       },
+       [ALC262_FIXUP_INV_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_inv_dmic,
+       },
+       [ALC262_FIXUP_INTEL_BAYLEYBAY] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_depop_delay,
+       },
+};
+
+static const struct hda_quirk alc262_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
+       SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
+       SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
+       SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
+       SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
+       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
+       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
+       SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
+       SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
+       SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
+       {}
+};
+
+static const struct hda_model_fixup alc262_fixup_models[] = {
+       {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
+       {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
+       {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
+       {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
+       {.id = ALC262_FIXUP_TYAN, .name = "tyan"},
+       {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
+       {.id = ALC262_FIXUP_BENQ, .name = "benq"},
+       {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
+       {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
+       {}
+};
+
+/*
+ */
+static int patch_alc262(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err;
+
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->gen.shared_mic_vref_pin = 0x18;
+
+       spec->shutup = alc_eapd_shutup;
+
+#if 0
+       /* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
+        * under-run
+        */
+       alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
+#endif
+       alc_fix_pll_init(codec, 0x20, 0x0a, 10);
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
+                      alc262_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       alc_auto_parse_customize_define(codec);
+
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
+       /* automatic parse from the BIOS config */
+       err = alc262_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!spec->gen.no_analog && spec->gen.beep_nid) {
+               err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+               if (err < 0)
+                       goto error;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+/*
+ *  ALC268
+ */
+/* bind Beep switches of both NID 0x0f and 0x10 */
+static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned long pval;
+       int err;
+
+       mutex_lock(&codec->control_mutex);
+       pval = kcontrol->private_value;
+       kcontrol->private_value = (pval & ~0xff) | 0x0f;
+       err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       if (err >= 0) {
+               kcontrol->private_value = (pval & ~0xff) | 0x10;
+               err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
+       }
+       kcontrol->private_value = pval;
+       mutex_unlock(&codec->control_mutex);
+       return err;
+}
+
+static const struct snd_kcontrol_new alc268_beep_mixer[] = {
+       HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Beep Playback Switch",
+               .subdevice = HDA_SUBDEV_AMP_FLAG,
+               .info = snd_hda_mixer_amp_switch_info,
+               .get = snd_hda_mixer_amp_switch_get,
+               .put = alc268_beep_switch_put,
+               .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
+       },
+};
+
+/* set PCBEEP vol = 0, mute connections */
+static const struct hda_verb alc268_beep_init_verbs[] = {
+       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
+       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
+       { }
+};
+
+enum {
+       ALC268_FIXUP_INV_DMIC,
+       ALC268_FIXUP_HP_EAPD,
+       ALC268_FIXUP_SPDIF,
+};
+
+static const struct hda_fixup alc268_fixups[] = {
+       [ALC268_FIXUP_INV_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_inv_dmic,
+       },
+       [ALC268_FIXUP_HP_EAPD] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
+                       {}
+               }
+       },
+       [ALC268_FIXUP_SPDIF] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1e, 0x014b1180 }, /* enable SPDIF out */
+                       {}
+               }
+       },
+};
+
+static const struct hda_model_fixup alc268_fixup_models[] = {
+       {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
+       {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
+       {.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
+       {}
+};
+
+static const struct hda_quirk alc268_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
+       SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
+       /* below is codec SSID since multiple Toshiba laptops have the
+        * same PCI SSID 1179:ff00
+        */
+       SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
+       {}
+};
+
+/*
+ * BIOS auto configuration
+ */
+static int alc268_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, NULL, alc268_ssids);
+}
+
+/*
+ */
+static int patch_alc268(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int i, err;
+
+       /* ALC268 has no aa-loopback mixer */
+       err = alc_alloc_spec(codec, 0);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
+       spec->shutup = alc_eapd_shutup;
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       /* automatic parse from the BIOS config */
+       err = alc268_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (err > 0 && !spec->gen.no_analog &&
+           spec->gen.autocfg.speaker_pins[0] != 0x1d) {
+               for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
+                       if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
+                                                 &alc268_beep_mixer[i])) {
+                               err = -ENOMEM;
+                               goto error;
+                       }
+               }
+               snd_hda_add_verbs(codec, alc268_beep_init_verbs);
+               if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
+                       /* override the amp caps for beep generator */
+                       snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
+                                         (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
+                                         (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                         (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                         (0 << AC_AMPCAP_MUTE_SHIFT));
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+/*
+ * ALC269
+ */
+
+static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+};
+
+static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
+       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
+};
+
+/* different alc269-variants */
+enum {
+       ALC269_TYPE_ALC269VA,
+       ALC269_TYPE_ALC269VB,
+       ALC269_TYPE_ALC269VC,
+       ALC269_TYPE_ALC269VD,
+       ALC269_TYPE_ALC280,
+       ALC269_TYPE_ALC282,
+       ALC269_TYPE_ALC283,
+       ALC269_TYPE_ALC284,
+       ALC269_TYPE_ALC293,
+       ALC269_TYPE_ALC286,
+       ALC269_TYPE_ALC298,
+       ALC269_TYPE_ALC255,
+       ALC269_TYPE_ALC256,
+       ALC269_TYPE_ALC257,
+       ALC269_TYPE_ALC215,
+       ALC269_TYPE_ALC225,
+       ALC269_TYPE_ALC245,
+       ALC269_TYPE_ALC287,
+       ALC269_TYPE_ALC294,
+       ALC269_TYPE_ALC300,
+       ALC269_TYPE_ALC623,
+       ALC269_TYPE_ALC700,
+};
+
+/*
+ * BIOS auto configuration
+ */
+static int alc269_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
+       static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       struct alc_spec *spec = codec->spec;
+       const hda_nid_t *ssids;
+
+       switch (spec->codec_variant) {
+       case ALC269_TYPE_ALC269VA:
+       case ALC269_TYPE_ALC269VC:
+       case ALC269_TYPE_ALC280:
+       case ALC269_TYPE_ALC284:
+       case ALC269_TYPE_ALC293:
+               ssids = alc269va_ssids;
+               break;
+       case ALC269_TYPE_ALC269VB:
+       case ALC269_TYPE_ALC269VD:
+       case ALC269_TYPE_ALC282:
+       case ALC269_TYPE_ALC283:
+       case ALC269_TYPE_ALC286:
+       case ALC269_TYPE_ALC298:
+       case ALC269_TYPE_ALC255:
+       case ALC269_TYPE_ALC256:
+       case ALC269_TYPE_ALC257:
+       case ALC269_TYPE_ALC215:
+       case ALC269_TYPE_ALC225:
+       case ALC269_TYPE_ALC245:
+       case ALC269_TYPE_ALC287:
+       case ALC269_TYPE_ALC294:
+       case ALC269_TYPE_ALC300:
+       case ALC269_TYPE_ALC623:
+       case ALC269_TYPE_ALC700:
+               ssids = alc269_ssids;
+               break;
+       default:
+               ssids = alc269_ssids;
+               break;
+       }
+
+       return alc_parse_auto_config(codec, alc269_ignore, ssids);
+}
+
+static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
+       { SND_JACK_BTN_0, KEY_PLAYPAUSE },
+       { SND_JACK_BTN_1, KEY_VOICECOMMAND },
+       { SND_JACK_BTN_2, KEY_VOLUMEUP },
+       { SND_JACK_BTN_3, KEY_VOLUMEDOWN },
+       {}
+};
+
+static void alc_headset_btn_callback(struct hda_codec *codec,
+                                    struct hda_jack_callback *jack)
+{
+       int report = 0;
+
+       if (jack->unsol_res & (7 << 13))
+               report |= SND_JACK_BTN_0;
+
+       if (jack->unsol_res  & (1 << 16 | 3 << 8))
+               report |= SND_JACK_BTN_1;
+
+       /* Volume up key */
+       if (jack->unsol_res & (7 << 23))
+               report |= SND_JACK_BTN_2;
+
+       /* Volume down key */
+       if (jack->unsol_res & (7 << 10))
+               report |= SND_JACK_BTN_3;
+
+       snd_hda_jack_set_button_state(codec, jack->nid, report);
+}
+
+static void alc_disable_headset_jack_key(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (!spec->has_hs_key)
+               return;
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0215:
+       case 0x10ec0225:
+       case 0x10ec0285:
+       case 0x10ec0287:
+       case 0x10ec0295:
+       case 0x10ec0289:
+       case 0x10ec0299:
+               alc_write_coef_idx(codec, 0x48, 0x0);
+               alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
+               alc_update_coef_idx(codec, 0x44, 0x0045 << 8, 0x0);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x10ec0257:
+       case 0x19e58326:
+               alc_write_coef_idx(codec, 0x48, 0x0);
+               alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
+               break;
+       }
+}
+
+static void alc_enable_headset_jack_key(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (!spec->has_hs_key)
+               return;
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0215:
+       case 0x10ec0225:
+       case 0x10ec0285:
+       case 0x10ec0287:
+       case 0x10ec0295:
+       case 0x10ec0289:
+       case 0x10ec0299:
+               alc_write_coef_idx(codec, 0x48, 0xd011);
+               alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
+               alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x10ec0257:
+       case 0x19e58326:
+               alc_write_coef_idx(codec, 0x48, 0xd011);
+               alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
+               break;
+       }
+}
+
+static void alc_fixup_headset_jack(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->has_hs_key = 1;
+               snd_hda_jack_detect_enable_callback(codec, 0x55,
+                                                   alc_headset_btn_callback);
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               hp_pin = alc_get_hp_pin(spec);
+               if (!hp_pin || snd_hda_jack_bind_keymap(codec, 0x55,
+                                                       alc_headset_btn_keymap,
+                                                       hp_pin))
+                       snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack",
+                                             false, SND_JACK_HEADSET,
+                                             alc_headset_btn_keymap);
+
+               alc_enable_headset_jack_key(codec);
+               break;
+       }
+}
+
+static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
+{
+       alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0);
+}
+
+static void alc269_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
+               alc269vb_toggle_power_output(codec, 0);
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
+                       (alc_get_coef0(codec) & 0x00ff) == 0x018) {
+               msleep(150);
+       }
+       alc_shutup_pins(codec);
+}
+
+static const struct coef_fw alc282_coefs[] = {
+       WRITE_COEF(0x03, 0x0002), /* Power Down Control */
+       UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
+       WRITE_COEF(0x07, 0x0200), /* DMIC control */
+       UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
+       UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
+       WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */
+       WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */
+       WRITE_COEF(0x0e, 0x6e00), /* LDO1/2/3, DAC/ADC */
+       UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */
+       UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */
+       WRITE_COEF(0x6f, 0x0), /* Class D test 4 */
+       UPDATE_COEF(0x0c, 0xfe00, 0), /* IO power down directly */
+       WRITE_COEF(0x34, 0xa0c0), /* ANC */
+       UPDATE_COEF(0x16, 0x0008, 0), /* AGC MUX */
+       UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */
+       UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */
+       WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */
+       WRITE_COEF(0x63, 0x2902), /* PLL */
+       WRITE_COEF(0x68, 0xa080), /* capless control 2 */
+       WRITE_COEF(0x69, 0x3400), /* capless control 3 */
+       WRITE_COEF(0x6a, 0x2f3e), /* capless control 4 */
+       WRITE_COEF(0x6b, 0x0), /* capless control 5 */
+       UPDATE_COEF(0x6d, 0x0fff, 0x0900), /* class D test 2 */
+       WRITE_COEF(0x6e, 0x110a), /* class D test 3 */
+       UPDATE_COEF(0x70, 0x00f8, 0x00d8), /* class D test 5 */
+       WRITE_COEF(0x71, 0x0014), /* class D test 6 */
+       WRITE_COEF(0x72, 0xc2ba), /* classD OCP */
+       UPDATE_COEF(0x77, 0x0f80, 0), /* classD pure DC test */
+       WRITE_COEF(0x6c, 0xfc06), /* Class D amp control */
+       {}
+};
+
+static void alc282_restore_default_value(struct hda_codec *codec)
+{
+       alc_process_coef_fw(codec, alc282_coefs);
+}
+
+static void alc282_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp_pin_sense;
+       int coef78;
+
+       alc282_restore_default_value(codec);
+
+       if (!hp_pin)
+               return;
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+       coef78 = alc_read_coef_idx(codec, 0x78);
+
+       /* Index 0x78 Direct Drive HP AMP LPM Control 1 */
+       /* Headphone capless set to high power mode */
+       alc_write_coef_idx(codec, 0x78, 0x9004);
+
+       if (hp_pin_sense)
+               msleep(2);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+       if (hp_pin_sense)
+               msleep(100);
+
+       /* Headphone capless set to normal mode */
+       alc_write_coef_idx(codec, 0x78, coef78);
+}
+
+static void alc282_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp_pin_sense;
+       int coef78;
+
+       if (!hp_pin) {
+               alc269_shutup(codec);
+               return;
+       }
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+       coef78 = alc_read_coef_idx(codec, 0x78);
+       alc_write_coef_idx(codec, 0x78, 0x9004);
+
+       if (hp_pin_sense)
+               msleep(2);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       if (!spec->no_shutup_pins)
+               snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+       if (hp_pin_sense)
+               msleep(100);
+
+       alc_auto_setup_eapd(codec, false);
+       alc_shutup_pins(codec);
+       alc_write_coef_idx(codec, 0x78, coef78);
+}
+
+static const struct coef_fw alc283_coefs[] = {
+       WRITE_COEF(0x03, 0x0002), /* Power Down Control */
+       UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
+       WRITE_COEF(0x07, 0x0200), /* DMIC control */
+       UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
+       UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
+       WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */
+       WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */
+       WRITE_COEF(0x0e, 0x6fc0), /* LDO1/2/3, DAC/ADC */
+       UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */
+       UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */
+       WRITE_COEF(0x3a, 0x0), /* Class D test 4 */
+       UPDATE_COEF(0x0c, 0xfe00, 0x0), /* IO power down directly */
+       WRITE_COEF(0x22, 0xa0c0), /* ANC */
+       UPDATE_COEFEX(0x53, 0x01, 0x000f, 0x0008), /* AGC MUX */
+       UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */
+       UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */
+       WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */
+       WRITE_COEF(0x2e, 0x2902), /* PLL */
+       WRITE_COEF(0x33, 0xa080), /* capless control 2 */
+       WRITE_COEF(0x34, 0x3400), /* capless control 3 */
+       WRITE_COEF(0x35, 0x2f3e), /* capless control 4 */
+       WRITE_COEF(0x36, 0x0), /* capless control 5 */
+       UPDATE_COEF(0x38, 0x0fff, 0x0900), /* class D test 2 */
+       WRITE_COEF(0x39, 0x110a), /* class D test 3 */
+       UPDATE_COEF(0x3b, 0x00f8, 0x00d8), /* class D test 5 */
+       WRITE_COEF(0x3c, 0x0014), /* class D test 6 */
+       WRITE_COEF(0x3d, 0xc2ba), /* classD OCP */
+       UPDATE_COEF(0x42, 0x0f80, 0x0), /* classD pure DC test */
+       WRITE_COEF(0x49, 0x0), /* test mode */
+       UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */
+       UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */
+       WRITE_COEF(0x37, 0xfc06), /* Class D amp control */
+       UPDATE_COEF(0x1b, 0x8000, 0), /* HP JD control */
+       {}
+};
+
+static void alc283_restore_default_value(struct hda_codec *codec)
+{
+       alc_process_coef_fw(codec, alc283_coefs);
+}
+
+static void alc283_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp_pin_sense;
+
+       alc283_restore_default_value(codec);
+
+       if (!hp_pin)
+               return;
+
+       msleep(30);
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       /* Index 0x43 Direct Drive HP AMP LPM Control 1 */
+       /* Headphone capless set to high power mode */
+       alc_write_coef_idx(codec, 0x43, 0x9004);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(85);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+       if (hp_pin_sense)
+               msleep(85);
+       /* Index 0x46 Combo jack auto switch control 2 */
+       /* 3k pull low control for Headset jack. */
+       alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
+       /* Headphone capless set to normal mode */
+       alc_write_coef_idx(codec, 0x43, 0x9614);
+}
+
+static void alc283_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp_pin_sense;
+
+       if (!hp_pin) {
+               alc269_shutup(codec);
+               return;
+       }
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       alc_write_coef_idx(codec, 0x43, 0x9004);
+
+       /*depop hp during suspend*/
+       alc_write_coef_idx(codec, 0x06, 0x2100);
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       if (hp_pin_sense)
+               msleep(100);
+
+       if (!spec->no_shutup_pins)
+               snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+       alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
+
+       if (hp_pin_sense)
+               msleep(100);
+       alc_auto_setup_eapd(codec, false);
+       alc_shutup_pins(codec);
+       alc_write_coef_idx(codec, 0x43, 0x9614);
+}
+
+static void alc256_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp_pin_sense;
+
+       if (spec->ultra_low_power) {
+               alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
+               alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
+               alc_update_coef_idx(codec, 0x08, 7<<4, 0);
+               alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
+               alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
+               msleep(30);
+       }
+
+       if (!hp_pin)
+               hp_pin = 0x21;
+
+       msleep(30);
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       if (hp_pin_sense) {
+               msleep(2);
+               alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
+
+               snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+               msleep(75);
+
+               snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+               msleep(75);
+               alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
+       }
+       alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
+       alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */
+       alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15);
+       /*
+        * Expose headphone mic (or possibly Line In on some machines) instead
+        * of PC Beep on 1Ah, and disable 1Ah loopback for all outputs. See
+        * Documentation/sound/hd-audio/realtek-pc-beep.rst for details of
+        * this register.
+        */
+       alc_write_coef_idx(codec, 0x36, 0x5757);
+}
+
+static void alc256_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp_pin_sense;
+
+       if (!hp_pin)
+               hp_pin = 0x21;
+
+       alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       if (hp_pin_sense) {
+               msleep(2);
+
+               snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+               msleep(75);
+
+       /* 3k pull low control for Headset jack. */
+       /* NOTE: call this before clearing the pin, otherwise codec stalls */
+       /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly
+        * when booting with headset plugged. So skip setting it for the codec alc257
+        */
+               if (spec->en_3kpull_low)
+                       alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
+
+               if (!spec->no_shutup_pins)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+               msleep(75);
+       }
+
+       alc_auto_setup_eapd(codec, false);
+       alc_shutup_pins(codec);
+       if (spec->ultra_low_power) {
+               msleep(50);
+               alc_update_coef_idx(codec, 0x03, 1<<1, 0);
+               alc_update_coef_idx(codec, 0x08, 7<<4, 7<<4);
+               alc_update_coef_idx(codec, 0x08, 3<<2, 0);
+               alc_update_coef_idx(codec, 0x3b, 1<<15, 1<<15);
+               alc_update_coef_idx(codec, 0x0e, 7<<6, 0);
+               msleep(30);
+       }
+}
+
+static void alc285_hp_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       int i, val;
+       int coef38, coef0d, coef36;
+
+       alc_write_coefex_idx(codec, 0x58, 0x00, 0x1888); /* write default value */
+       alc_update_coef_idx(codec, 0x4a, 1<<15, 1<<15); /* Reset HP JD */
+       coef38 = alc_read_coef_idx(codec, 0x38); /* Amp control */
+       coef0d = alc_read_coef_idx(codec, 0x0d); /* Digital Misc control */
+       coef36 = alc_read_coef_idx(codec, 0x36); /* Passthrough Control */
+       alc_update_coef_idx(codec, 0x38, 1<<4, 0x0);
+       alc_update_coef_idx(codec, 0x0d, 0x110, 0x0);
+
+       alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
+
+       if (hp_pin)
+               snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       msleep(130);
+       alc_update_coef_idx(codec, 0x36, 1<<14, 1<<14);
+       alc_update_coef_idx(codec, 0x36, 1<<13, 0x0);
+
+       if (hp_pin)
+               snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+       msleep(10);
+       alc_write_coef_idx(codec, 0x67, 0x0); /* Set HP depop to manual mode */
+       alc_write_coefex_idx(codec, 0x58, 0x00, 0x7880);
+       alc_write_coefex_idx(codec, 0x58, 0x0f, 0xf049);
+       alc_update_coefex_idx(codec, 0x58, 0x03, 0x00f0, 0x00c0);
+
+       alc_write_coefex_idx(codec, 0x58, 0x00, 0xf888); /* HP depop procedure start */
+       val = alc_read_coefex_idx(codec, 0x58, 0x00);
+       for (i = 0; i < 20 && val & 0x8000; i++) {
+               msleep(50);
+               val = alc_read_coefex_idx(codec, 0x58, 0x00);
+       } /* Wait for depop procedure finish  */
+
+       alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */
+       alc_update_coef_idx(codec, 0x38, 1<<4, coef38);
+       alc_update_coef_idx(codec, 0x0d, 0x110, coef0d);
+       alc_update_coef_idx(codec, 0x36, 3<<13, coef36);
+
+       msleep(50);
+       alc_update_coef_idx(codec, 0x4a, 1<<15, 0);
+}
+
+static void alc225_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp1_pin_sense, hp2_pin_sense;
+
+       if (spec->ultra_low_power) {
+               alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
+               alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
+               alc_update_coef_idx(codec, 0x33, 1<<11, 0);
+               msleep(30);
+       }
+
+       if (spec->codec_variant != ALC269_TYPE_ALC287 &&
+               spec->codec_variant != ALC269_TYPE_ALC245)
+               /* required only at boot or S3 and S4 resume time */
+               if (!spec->done_hp_init ||
+                       is_s3_resume(codec) ||
+                       is_s4_resume(codec)) {
+                       alc285_hp_init(codec);
+                       spec->done_hp_init = true;
+               }
+
+       if (!hp_pin)
+               hp_pin = 0x21;
+       msleep(30);
+
+       hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+       hp2_pin_sense = snd_hda_jack_detect(codec, 0x16);
+
+       if (hp1_pin_sense || hp2_pin_sense) {
+               msleep(2);
+               alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
+
+               if (hp1_pin_sense)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               if (hp2_pin_sense)
+                       snd_hda_codec_write(codec, 0x16, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               msleep(75);
+
+               if (hp1_pin_sense)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+               if (hp2_pin_sense)
+                       snd_hda_codec_write(codec, 0x16, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+               msleep(75);
+               alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
+               alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
+       }
+}
+
+static void alc225_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp1_pin_sense, hp2_pin_sense;
+
+       if (!hp_pin)
+               hp_pin = 0x21;
+
+       hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+       hp2_pin_sense = snd_hda_jack_detect(codec, 0x16);
+
+       if (hp1_pin_sense || hp2_pin_sense) {
+               alc_disable_headset_jack_key(codec);
+               /* 3k pull low control for Headset jack. */
+               alc_update_coef_idx(codec, 0x4a, 0, 3 << 10);
+               msleep(2);
+
+               if (hp1_pin_sense)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+               if (hp2_pin_sense)
+                       snd_hda_codec_write(codec, 0x16, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+               msleep(75);
+
+               if (hp1_pin_sense)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+               if (hp2_pin_sense)
+                       snd_hda_codec_write(codec, 0x16, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+               msleep(75);
+               alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
+               alc_enable_headset_jack_key(codec);
+       }
+       alc_auto_setup_eapd(codec, false);
+       alc_shutup_pins(codec);
+       if (spec->ultra_low_power) {
+               msleep(50);
+               alc_update_coef_idx(codec, 0x08, 0x0f << 2, 0x0c << 2);
+               alc_update_coef_idx(codec, 0x0e, 7<<6, 0);
+               alc_update_coef_idx(codec, 0x33, 1<<11, 1<<11);
+               alc_update_coef_idx(codec, 0x4a, 3<<4, 2<<4);
+               msleep(30);
+       }
+}
+
+static void alc222_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp1_pin_sense, hp2_pin_sense;
+
+       if (!hp_pin)
+               return;
+
+       msleep(30);
+
+       hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+       hp2_pin_sense = snd_hda_jack_detect(codec, 0x14);
+
+       if (hp1_pin_sense || hp2_pin_sense) {
+               msleep(2);
+
+               if (hp1_pin_sense)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               if (hp2_pin_sense)
+                       snd_hda_codec_write(codec, 0x14, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+               msleep(75);
+
+               if (hp1_pin_sense)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+               if (hp2_pin_sense)
+                       snd_hda_codec_write(codec, 0x14, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+
+               msleep(75);
+       }
+}
+
+static void alc222_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp1_pin_sense, hp2_pin_sense;
+
+       if (!hp_pin)
+               hp_pin = 0x21;
+
+       hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+       hp2_pin_sense = snd_hda_jack_detect(codec, 0x14);
+
+       if (hp1_pin_sense || hp2_pin_sense) {
+               msleep(2);
+
+               if (hp1_pin_sense)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+               if (hp2_pin_sense)
+                       snd_hda_codec_write(codec, 0x14, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+               msleep(75);
+
+               if (hp1_pin_sense)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+               if (hp2_pin_sense)
+                       snd_hda_codec_write(codec, 0x14, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+               msleep(75);
+       }
+       alc_auto_setup_eapd(codec, false);
+       alc_shutup_pins(codec);
+}
+
+static void alc_default_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp_pin_sense;
+
+       if (!hp_pin)
+               return;
+
+       msleep(30);
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       if (hp_pin_sense) {
+               msleep(2);
+
+               snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+
+               msleep(75);
+
+               snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+               msleep(75);
+       }
+}
+
+static void alc_default_shutup(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       bool hp_pin_sense;
+
+       if (!hp_pin) {
+               alc269_shutup(codec);
+               return;
+       }
+
+       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
+
+       if (hp_pin_sense) {
+               msleep(2);
+
+               snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+               msleep(75);
+
+               if (!spec->no_shutup_pins)
+                       snd_hda_codec_write(codec, hp_pin, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+               msleep(75);
+       }
+       alc_auto_setup_eapd(codec, false);
+       alc_shutup_pins(codec);
+}
+
+static void alc294_hp_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+       int i, val;
+
+       if (!hp_pin)
+               return;
+
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+
+       msleep(100);
+
+       if (!spec->no_shutup_pins)
+               snd_hda_codec_write(codec, hp_pin, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+
+       alc_update_coef_idx(codec, 0x6f, 0x000f, 0);/* Set HP depop to manual mode */
+       alc_update_coefex_idx(codec, 0x58, 0x00, 0x8000, 0x8000); /* HP depop procedure start */
+
+       /* Wait for depop procedure finish  */
+       val = alc_read_coefex_idx(codec, 0x58, 0x01);
+       for (i = 0; i < 20 && val & 0x0080; i++) {
+               msleep(50);
+               val = alc_read_coefex_idx(codec, 0x58, 0x01);
+       }
+       /* Set HP depop to auto mode */
+       alc_update_coef_idx(codec, 0x6f, 0x000f, 0x000b);
+       msleep(50);
+}
+
+static void alc294_init(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       /* required only at boot or S4 resume time */
+       if (!spec->done_hp_init ||
+           codec->core.dev.power.power_state.event == PM_EVENT_RESTORE) {
+               alc294_hp_init(codec);
+               spec->done_hp_init = true;
+       }
+       alc_default_init(codec);
+}
+
+static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
+                            unsigned int val)
+{
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val & 0xffff); /* LSB */
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val >> 16); /* MSB */
+}
+
+static int alc5505_coef_get(struct hda_codec *codec, unsigned int index_reg)
+{
+       unsigned int val;
+
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
+       val = snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
+               & 0xffff;
+       val |= snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
+               << 16;
+       return val;
+}
+
+static void alc5505_dsp_halt(struct hda_codec *codec)
+{
+       unsigned int val;
+
+       alc5505_coef_set(codec, 0x3000, 0x000c); /* DSP CPU stop */
+       alc5505_coef_set(codec, 0x880c, 0x0008); /* DDR enter self refresh */
+       alc5505_coef_set(codec, 0x61c0, 0x11110080); /* Clock control for PLL and CPU */
+       alc5505_coef_set(codec, 0x6230, 0xfc0d4011); /* Disable Input OP */
+       alc5505_coef_set(codec, 0x61b4, 0x040a2b03); /* Stop PLL2 */
+       alc5505_coef_set(codec, 0x61b0, 0x00005b17); /* Stop PLL1 */
+       alc5505_coef_set(codec, 0x61b8, 0x04133303); /* Stop PLL3 */
+       val = alc5505_coef_get(codec, 0x6220);
+       alc5505_coef_set(codec, 0x6220, (val | 0x3000)); /* switch Ringbuffer clock to DBUS clock */
+}
+
+static void alc5505_dsp_back_from_halt(struct hda_codec *codec)
+{
+       alc5505_coef_set(codec, 0x61b8, 0x04133302);
+       alc5505_coef_set(codec, 0x61b0, 0x00005b16);
+       alc5505_coef_set(codec, 0x61b4, 0x040a2b02);
+       alc5505_coef_set(codec, 0x6230, 0xf80d4011);
+       alc5505_coef_set(codec, 0x6220, 0x2002010f);
+       alc5505_coef_set(codec, 0x880c, 0x00000004);
+}
+
+static void alc5505_dsp_init(struct hda_codec *codec)
+{
+       unsigned int val;
+
+       alc5505_dsp_halt(codec);
+       alc5505_dsp_back_from_halt(codec);
+       alc5505_coef_set(codec, 0x61b0, 0x5b14); /* PLL1 control */
+       alc5505_coef_set(codec, 0x61b0, 0x5b16);
+       alc5505_coef_set(codec, 0x61b4, 0x04132b00); /* PLL2 control */
+       alc5505_coef_set(codec, 0x61b4, 0x04132b02);
+       alc5505_coef_set(codec, 0x61b8, 0x041f3300); /* PLL3 control*/
+       alc5505_coef_set(codec, 0x61b8, 0x041f3302);
+       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_CODEC_RESET, 0); /* Function reset */
+       alc5505_coef_set(codec, 0x61b8, 0x041b3302);
+       alc5505_coef_set(codec, 0x61b8, 0x04173302);
+       alc5505_coef_set(codec, 0x61b8, 0x04163302);
+       alc5505_coef_set(codec, 0x8800, 0x348b328b); /* DRAM control */
+       alc5505_coef_set(codec, 0x8808, 0x00020022); /* DRAM control */
+       alc5505_coef_set(codec, 0x8818, 0x00000400); /* DRAM control */
+
+       val = alc5505_coef_get(codec, 0x6200) >> 16; /* Read revision ID */
+       if (val <= 3)
+               alc5505_coef_set(codec, 0x6220, 0x2002010f); /* I/O PAD Configuration */
+       else
+               alc5505_coef_set(codec, 0x6220, 0x6002018f);
+
+       alc5505_coef_set(codec, 0x61ac, 0x055525f0); /**/
+       alc5505_coef_set(codec, 0x61c0, 0x12230080); /* Clock control */
+       alc5505_coef_set(codec, 0x61b4, 0x040e2b02); /* PLL2 control */
+       alc5505_coef_set(codec, 0x61bc, 0x010234f8); /* OSC Control */
+       alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */
+       alc5505_coef_set(codec, 0x880c, 0x00000003);
+       alc5505_coef_set(codec, 0x880c, 0x00000010);
+
+#ifdef HALT_REALTEK_ALC5505
+       alc5505_dsp_halt(codec);
+#endif
+}
+
+#ifdef HALT_REALTEK_ALC5505
+#define alc5505_dsp_suspend(codec)     do { } while (0) /* NOP */
+#define alc5505_dsp_resume(codec)      do { } while (0) /* NOP */
+#else
+#define alc5505_dsp_suspend(codec)     alc5505_dsp_halt(codec)
+#define alc5505_dsp_resume(codec)      alc5505_dsp_back_from_halt(codec)
+#endif
+
+static int alc269_suspend(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->has_alc5505_dsp)
+               alc5505_dsp_suspend(codec);
+
+       return alc_suspend(codec);
+}
+
+static int alc269_resume(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
+               alc269vb_toggle_power_output(codec, 0);
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
+                       (alc_get_coef0(codec) & 0x00ff) == 0x018) {
+               msleep(150);
+       }
+
+       codec->patch_ops.init(codec);
+
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
+               alc269vb_toggle_power_output(codec, 1);
+       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
+                       (alc_get_coef0(codec) & 0x00ff) == 0x017) {
+               msleep(200);
+       }
+
+       snd_hda_regmap_sync(codec);
+       hda_call_check_power_status(codec, 0x01);
+
+       /* on some machine, the BIOS will clear the codec gpio data when enter
+        * suspend, and won't restore the data after resume, so we restore it
+        * in the driver.
+        */
+       if (spec->gpio_data)
+               alc_write_gpio_data(codec);
+
+       if (spec->has_alc5505_dsp)
+               alc5505_dsp_resume(codec);
+
+       return 0;
+}
+
+static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
+                                                const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+}
+
+static void alc269_fixup_pincfg_U7x7_headset_mic(struct hda_codec *codec,
+                                                const struct hda_fixup *fix,
+                                                int action)
+{
+       unsigned int cfg_headphone = snd_hda_codec_get_pincfg(codec, 0x21);
+       unsigned int cfg_headset_mic = snd_hda_codec_get_pincfg(codec, 0x19);
+
+       if (cfg_headphone && cfg_headset_mic == 0x411111f0)
+               snd_hda_codec_set_pincfg(codec, 0x19,
+                       (cfg_headphone & ~AC_DEFCFG_DEVICE) |
+                       (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT));
+}
+
+static void alc269_fixup_hweq(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc_update_coef_idx(codec, 0x1e, 0, 0x80);
+}
+
+static void alc269_fixup_headset_mic(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+}
+
+static void alc271_fixup_dmic(struct hda_codec *codec,
+                             const struct hda_fixup *fix, int action)
+{
+       static const struct hda_verb verbs[] = {
+               {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
+               {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
+               {}
+       };
+       unsigned int cfg;
+
+       if (strcmp(codec->core.chip_name, "ALC271X") &&
+           strcmp(codec->core.chip_name, "ALC269VB"))
+               return;
+       cfg = snd_hda_codec_get_pincfg(codec, 0x12);
+       if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
+               snd_hda_sequence_write(codec, verbs);
+}
+
+/* Fix the speaker amp after resume, etc */
+static void alc269vb_fixup_aspire_e1_coef(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc_update_coef_idx(codec, 0x0d, 0x6000, 0x6000);
+}
+
+static void alc269_fixup_pcm_44k(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PROBE)
+               return;
+
+       /* Due to a hardware problem on Lenovo Ideadpad, we need to
+        * fix the sample rate of analog I/O to 44.1kHz
+        */
+       spec->gen.stream_analog_playback = &alc269_44k_pcm_analog_playback;
+       spec->gen.stream_analog_capture = &alc269_44k_pcm_analog_capture;
+}
+
+static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       /* The digital-mic unit sends PDM (differential signal) instead of
+        * the standard PCM, thus you can't record a valid mono stream as is.
+        * Below is a workaround specific to ALC269 to control the dmic
+        * signal source as mono.
+        */
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc_update_coef_idx(codec, 0x07, 0, 0x80);
+}
+
+static void alc269_quanta_automute(struct hda_codec *codec)
+{
+       snd_hda_gen_update_outputs(codec);
+
+       alc_write_coef_idx(codec, 0x0c, 0x680);
+       alc_write_coef_idx(codec, 0x0c, 0x480);
+}
+
+static void alc269_fixup_quanta_mute(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action != HDA_FIXUP_ACT_PROBE)
+               return;
+       spec->gen.automute_hook = alc269_quanta_automute;
+}
+
+static void alc269_x101_hp_automute_hook(struct hda_codec *codec,
+                                        struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       int vref;
+       msleep(200);
+       snd_hda_gen_hp_automute(codec, jack);
+
+       vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+       msleep(100);
+       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           vref);
+       msleep(500);
+       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           vref);
+}
+
+/*
+ * Magic sequence to make Huawei Matebook X right speaker working (bko#197801)
+ */
+struct hda_alc298_mbxinit {
+       unsigned char value_0x23;
+       unsigned char value_0x25;
+};
+
+static void alc298_huawei_mbx_stereo_seq(struct hda_codec *codec,
+                                        const struct hda_alc298_mbxinit *initval,
+                                        bool first)
+{
+       snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x0);
+       alc_write_coef_idx(codec, 0x26, 0xb000);
+
+       if (first)
+               snd_hda_codec_write(codec, 0x21, 0, AC_VERB_GET_PIN_SENSE, 0x0);
+
+       snd_hda_codec_write(codec, 0x6, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80);
+       alc_write_coef_idx(codec, 0x26, 0xf000);
+       alc_write_coef_idx(codec, 0x23, initval->value_0x23);
+
+       if (initval->value_0x23 != 0x1e)
+               alc_write_coef_idx(codec, 0x25, initval->value_0x25);
+
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010);
+}
+
+static void alc298_fixup_huawei_mbx_stereo(struct hda_codec *codec,
+                                          const struct hda_fixup *fix,
+                                          int action)
+{
+       /* Initialization magic */
+       static const struct hda_alc298_mbxinit dac_init[] = {
+               {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
+               {0x10, 0x00}, {0x1a, 0x40}, {0x1b, 0x82}, {0x1c, 0x00},
+               {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
+               {0x20, 0xc2}, {0x21, 0xc8}, {0x22, 0x26}, {0x23, 0x24},
+               {0x27, 0xff}, {0x28, 0xff}, {0x29, 0xff}, {0x2a, 0x8f},
+               {0x2b, 0x02}, {0x2c, 0x48}, {0x2d, 0x34}, {0x2e, 0x00},
+               {0x2f, 0x00},
+               {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
+               {0x34, 0x00}, {0x35, 0x01}, {0x36, 0x93}, {0x37, 0x0c},
+               {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0xf8}, {0x38, 0x80},
+               {}
+       };
+       const struct hda_alc298_mbxinit *seq;
+
+       if (action != HDA_FIXUP_ACT_INIT)
+               return;
+
+       /* Start */
+       snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x00);
+       snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80);
+       alc_write_coef_idx(codec, 0x26, 0xf000);
+       alc_write_coef_idx(codec, 0x22, 0x31);
+       alc_write_coef_idx(codec, 0x23, 0x0b);
+       alc_write_coef_idx(codec, 0x25, 0x00);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26);
+       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010);
+
+       for (seq = dac_init; seq->value_0x23; seq++)
+               alc298_huawei_mbx_stereo_seq(codec, seq, seq == dac_init);
+}
+
+static void alc269_fixup_x101_headset_mic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               spec->gen.hp_automute_hook = alc269_x101_hp_automute_hook;
+       }
+}
+
+static void alc_update_vref_led(struct hda_codec *codec, hda_nid_t pin,
+                               bool polarity, bool on)
+{
+       unsigned int pinval;
+
+       if (!pin)
+               return;
+       if (polarity)
+               on = !on;
+       pinval = snd_hda_codec_get_pin_target(codec, pin);
+       pinval &= ~AC_PINCTL_VREFEN;
+       pinval |= on ? AC_PINCTL_VREF_80 : AC_PINCTL_VREF_HIZ;
+       /* temporarily power up/down for setting VREF */
+       snd_hda_power_up_pm(codec);
+       snd_hda_set_pin_ctl_cache(codec, pin, pinval);
+       snd_hda_power_down_pm(codec);
+}
+
+/* update mute-LED according to the speaker mute state via mic VREF pin */
+static int vref_mute_led_set(struct led_classdev *led_cdev,
+                            enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct alc_spec *spec = codec->spec;
+
+       alc_update_vref_led(codec, spec->mute_led_nid,
+                           spec->mute_led_polarity, brightness);
+       return 0;
+}
+
+/* Make sure the led works even in runtime suspend */
+static unsigned int led_power_filter(struct hda_codec *codec,
+                                                 hda_nid_t nid,
+                                                 unsigned int power_state)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (power_state != AC_PWRST_D3 || nid == 0 ||
+           (nid != spec->mute_led_nid && nid != spec->cap_mute_led_nid))
+               return power_state;
+
+       /* Set pin ctl again, it might have just been set to 0 */
+       snd_hda_set_pin_ctl(codec, nid,
+                           snd_hda_codec_get_pin_target(codec, nid));
+
+       return snd_hda_gen_path_power_filter(codec, nid, power_state);
+}
+
+static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       const struct dmi_device *dev = NULL;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+               int pol, pin;
+               if (sscanf(dev->name, "HP_Mute_LED_%d_%x", &pol, &pin) != 2)
+                       continue;
+               if (pin < 0x0a || pin >= 0x10)
+                       break;
+               spec->mute_led_polarity = pol;
+               spec->mute_led_nid = pin - 0x0a + 0x18;
+               snd_hda_gen_add_mute_led_cdev(codec, vref_mute_led_set);
+               codec->power_filter = led_power_filter;
+               codec_dbg(codec,
+                         "Detected mute LED for %x:%d\n", spec->mute_led_nid,
+                          spec->mute_led_polarity);
+               break;
+       }
+}
+
+static void alc269_fixup_hp_mute_led_micx(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action, hda_nid_t pin)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_nid = pin;
+               snd_hda_gen_add_mute_led_cdev(codec, vref_mute_led_set);
+               codec->power_filter = led_power_filter;
+       }
+}
+
+static void alc269_fixup_hp_mute_led_mic1(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x18);
+}
+
+static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x19);
+}
+
+static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b);
+}
+
+/* update LED status via GPIO */
+static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+                               int polarity, bool enabled)
+{
+       if (polarity)
+               enabled = !enabled;
+       alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
+}
+
+/* turn on/off mute LED via GPIO per vmaster hook */
+static int gpio_mute_led_set(struct led_classdev *led_cdev,
+                            enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct alc_spec *spec = codec->spec;
+
+       alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
+                           spec->mute_led_polarity, !brightness);
+       return 0;
+}
+
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static int micmute_led_set(struct led_classdev *led_cdev,
+                          enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct alc_spec *spec = codec->spec;
+
+       alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
+                           spec->micmute_led_polarity, !brightness);
+       return 0;
+}
+
+/* setup mute and mic-mute GPIO bits, add hooks appropriately */
+static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
+                                 int action,
+                                 unsigned int mute_mask,
+                                 unsigned int micmute_mask)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       if (mute_mask) {
+               spec->gpio_mute_led_mask = mute_mask;
+               snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
+       }
+       if (micmute_mask) {
+               spec->gpio_mic_led_mask = micmute_mask;
+               snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
+       }
+}
+
+static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc_fixup_hp_gpio_led(codec, action, 0x02, 0x01);
+}
+
+static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
+}
+
+static void alc285_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc_fixup_hp_gpio_led(codec, action, 0x04, 0x01);
+}
+
+static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc_fixup_hp_gpio_led(codec, action, 0x02, 0x20);
+}
+
+static void alc287_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc_fixup_hp_gpio_led(codec, action, 0x10, 0);
+}
+
+static void alc245_fixup_hp_gpio_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->micmute_led_polarity = 1;
+       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
+}
+
+/* turn on/off mic-mute LED per capture hook via VREF change */
+static int vref_micmute_led_set(struct led_classdev *led_cdev,
+                               enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct alc_spec *spec = codec->spec;
+
+       alc_update_vref_led(codec, spec->cap_mute_led_nid,
+                           spec->micmute_led_polarity, brightness);
+       return 0;
+}
+
+static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* Like hp_gpio_mic1_led, but also needs GPIO4 low to
+                * enable headphone amp
+                */
+               spec->gpio_mask |= 0x10;
+               spec->gpio_dir |= 0x10;
+               spec->cap_mute_led_nid = 0x18;
+               snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
+               codec->power_filter = led_power_filter;
+       }
+}
+
+static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->cap_mute_led_nid = 0x18;
+               snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
+               codec->power_filter = led_power_filter;
+       }
+}
+
+/* HP Spectre x360 14 model needs a unique workaround for enabling the amp;
+ * it needs to toggle the GPIO0 once on and off at each time (bko#210633)
+ */
+static void alc245_fixup_hp_x360_amp(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->gpio_mask |= 0x01;
+               spec->gpio_dir |= 0x01;
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* need to toggle GPIO to enable the amp */
+               alc_update_gpio_data(codec, 0x01, true);
+               msleep(100);
+               alc_update_gpio_data(codec, 0x01, false);
+               break;
+       }
+}
+
+/* toggle GPIO2 at each time stream is started; we use PREPARE state instead */
+static void alc274_hp_envy_pcm_hook(struct hda_pcm_stream *hinfo,
+                                   struct hda_codec *codec,
+                                   struct snd_pcm_substream *substream,
+                                   int action)
+{
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               alc_update_gpio_data(codec, 0x04, true);
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               alc_update_gpio_data(codec, 0x04, false);
+               break;
+       }
+}
+
+static void alc274_fixup_hp_envy_gpio(struct hda_codec *codec,
+                                     const struct hda_fixup *fix,
+                                     int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PROBE) {
+               spec->gpio_mask |= 0x04;
+               spec->gpio_dir |= 0x04;
+               spec->gen.pcm_playback_hook = alc274_hp_envy_pcm_hook;
+       }
+}
+
+static void alc_update_coef_led(struct hda_codec *codec,
+                               struct alc_coef_led *led,
+                               bool polarity, bool on)
+{
+       if (polarity)
+               on = !on;
+       /* temporarily power up/down for setting COEF bit */
+       alc_update_coef_idx(codec, led->idx, led->mask,
+                           on ? led->on : led->off);
+}
+
+/* update mute-LED according to the speaker mute state via COEF bit */
+static int coef_mute_led_set(struct led_classdev *led_cdev,
+                            enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct alc_spec *spec = codec->spec;
+
+       alc_update_coef_led(codec, &spec->mute_led_coef,
+                           spec->mute_led_polarity, brightness);
+       return 0;
+}
+
+static void alc285_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef.idx = 0x0b;
+               spec->mute_led_coef.mask = 1 << 3;
+               spec->mute_led_coef.on = 1 << 3;
+               spec->mute_led_coef.off = 0;
+               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+       }
+}
+
+static void alc236_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef.idx = 0x34;
+               spec->mute_led_coef.mask = 1 << 5;
+               spec->mute_led_coef.on = 0;
+               spec->mute_led_coef.off = 1 << 5;
+               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+       }
+}
+
+static void alc236_fixup_hp_mute_led_coefbit2(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef.idx = 0x07;
+               spec->mute_led_coef.mask = 1;
+               spec->mute_led_coef.on = 1;
+               spec->mute_led_coef.off = 0;
+               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+       }
+}
+
+static void alc245_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef.idx = 0x0b;
+               spec->mute_led_coef.mask = 3 << 2;
+               spec->mute_led_coef.on = 2 << 2;
+               spec->mute_led_coef.off = 1 << 2;
+               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+       }
+}
+
+static void alc245_fixup_hp_mute_led_v1_coefbit(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef.idx = 0x0b;
+               spec->mute_led_coef.mask = 1 << 3;
+               spec->mute_led_coef.on = 1 << 3;
+               spec->mute_led_coef.off = 0;
+               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+       }
+}
+
+/* turn on/off mic-mute LED per capture hook by coef bit */
+static int coef_micmute_led_set(struct led_classdev *led_cdev,
+                               enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct alc_spec *spec = codec->spec;
+
+       alc_update_coef_led(codec, &spec->mic_led_coef,
+                           spec->micmute_led_polarity, brightness);
+       return 0;
+}
+
+static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mic_led_coef.idx = 0x19;
+               spec->mic_led_coef.mask = 1 << 13;
+               spec->mic_led_coef.on = 1 << 13;
+               spec->mic_led_coef.off = 0;
+               snd_hda_gen_add_micmute_led_cdev(codec, coef_micmute_led_set);
+       }
+}
+
+static void alc285_fixup_hp_gpio_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->micmute_led_polarity = 1;
+       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
+}
+
+static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mic_led_coef.idx = 0x35;
+               spec->mic_led_coef.mask = 3 << 2;
+               spec->mic_led_coef.on = 2 << 2;
+               spec->mic_led_coef.off = 1 << 2;
+               snd_hda_gen_add_micmute_led_cdev(codec, coef_micmute_led_set);
+       }
+}
+
+static void alc295_fixup_hp_mute_led_coefbit11(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 0;
+               spec->mute_led_coef.idx = 0xb;
+               spec->mute_led_coef.mask = 3 << 3;
+               spec->mute_led_coef.on = 1 << 3;
+               spec->mute_led_coef.off = 1 << 4;
+               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
+       }
+}
+
+static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
+static void alc285_fixup_hp_spectre_x360_mute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc285_fixup_hp_gpio_micmute_led(codec, fix, action);
+}
+
+static void alc236_fixup_hp_mute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc236_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc236_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
+static void alc236_fixup_hp_micmute_led_vref(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->cap_mute_led_nid = 0x1a;
+               snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
+               codec->power_filter = led_power_filter;
+       }
+}
+
+static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc236_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc236_fixup_hp_micmute_led_vref(codec, fix, action);
+}
+
+static inline void alc298_samsung_write_coef_pack(struct hda_codec *codec,
+                                                 const unsigned short coefs[2])
+{
+       alc_write_coef_idx(codec, 0x23, coefs[0]);
+       alc_write_coef_idx(codec, 0x25, coefs[1]);
+       alc_write_coef_idx(codec, 0x26, 0xb011);
+}
+
+struct alc298_samsung_amp_desc {
+       unsigned char nid;
+       unsigned short init_seq[2][2];
+};
+
+static void alc298_fixup_samsung_amp(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       int i, j;
+       static const unsigned short init_seq[][2] = {
+               { 0x19, 0x00 }, { 0x20, 0xc0 }, { 0x22, 0x44 }, { 0x23, 0x08 },
+               { 0x24, 0x85 }, { 0x25, 0x41 }, { 0x35, 0x40 }, { 0x36, 0x01 },
+               { 0x38, 0x81 }, { 0x3a, 0x03 }, { 0x3b, 0x81 }, { 0x40, 0x3e },
+               { 0x41, 0x07 }, { 0x400, 0x1 }
+       };
+       static const struct alc298_samsung_amp_desc amps[] = {
+               { 0x3a, { { 0x18, 0x1 }, { 0x26, 0x0 } } },
+               { 0x39, { { 0x18, 0x2 }, { 0x26, 0x1 } } }
+       };
+
+       if (action != HDA_FIXUP_ACT_INIT)
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(amps); i++) {
+               alc_write_coef_idx(codec, 0x22, amps[i].nid);
+
+               for (j = 0; j < ARRAY_SIZE(amps[i].init_seq); j++)
+                       alc298_samsung_write_coef_pack(codec, amps[i].init_seq[j]);
+
+               for (j = 0; j < ARRAY_SIZE(init_seq); j++)
+                       alc298_samsung_write_coef_pack(codec, init_seq[j]);
+       }
+}
+
+struct alc298_samsung_v2_amp_desc {
+       unsigned short nid;
+       int init_seq_size;
+       unsigned short init_seq[18][2];
+};
+
+static const struct alc298_samsung_v2_amp_desc
+alc298_samsung_v2_amp_desc_tbl[] = {
+       { 0x38, 18, {
+               { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
+               { 0x201b, 0x0001 }, { 0x201d, 0x0001 }, { 0x201f, 0x00fe },
+               { 0x2021, 0x0000 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
+               { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
+               { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x2399, 0x0003 },
+               { 0x23a4, 0x00b5 }, { 0x23a5, 0x0001 }, { 0x23ba, 0x0094 }
+       }},
+       { 0x39, 18, {
+               { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
+               { 0x201b, 0x0002 }, { 0x201d, 0x0002 }, { 0x201f, 0x00fd },
+               { 0x2021, 0x0001 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
+               { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
+               { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x2399, 0x0003 },
+               { 0x23a4, 0x00b5 }, { 0x23a5, 0x0001 }, { 0x23ba, 0x0094 }
+       }},
+       { 0x3c, 15, {
+               { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
+               { 0x201b, 0x0001 }, { 0x201d, 0x0001 }, { 0x201f, 0x00fe },
+               { 0x2021, 0x0000 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
+               { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
+               { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x23ba, 0x008d }
+       }},
+       { 0x3d, 15, {
+               { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
+               { 0x201b, 0x0002 }, { 0x201d, 0x0002 }, { 0x201f, 0x00fd },
+               { 0x2021, 0x0001 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
+               { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
+               { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x23ba, 0x008d }
+       }}
+};
+
+static void alc298_samsung_v2_enable_amps(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       static const unsigned short enable_seq[][2] = {
+               { 0x203a, 0x0081 }, { 0x23ff, 0x0001 },
+       };
+       int i, j;
+
+       for (i = 0; i < spec->num_speaker_amps; i++) {
+               alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
+               for (j = 0; j < ARRAY_SIZE(enable_seq); j++)
+                       alc298_samsung_write_coef_pack(codec, enable_seq[j]);
+               codec_dbg(codec, "alc298_samsung_v2: Enabled speaker amp 0x%02x\n",
+                               alc298_samsung_v2_amp_desc_tbl[i].nid);
+       }
+}
+
+static void alc298_samsung_v2_disable_amps(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       static const unsigned short disable_seq[][2] = {
+               { 0x23ff, 0x0000 }, { 0x203a, 0x0080 },
+       };
+       int i, j;
+
+       for (i = 0; i < spec->num_speaker_amps; i++) {
+               alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
+               for (j = 0; j < ARRAY_SIZE(disable_seq); j++)
+                       alc298_samsung_write_coef_pack(codec, disable_seq[j]);
+               codec_dbg(codec, "alc298_samsung_v2: Disabled speaker amp 0x%02x\n",
+                               alc298_samsung_v2_amp_desc_tbl[i].nid);
+       }
+}
+
+static void alc298_samsung_v2_playback_hook(struct hda_pcm_stream *hinfo,
+                               struct hda_codec *codec,
+                               struct snd_pcm_substream *substream,
+                               int action)
+{
+       /* Dynamically enable/disable speaker amps before and after playback */
+       if (action == HDA_GEN_PCM_ACT_OPEN)
+               alc298_samsung_v2_enable_amps(codec);
+       if (action == HDA_GEN_PCM_ACT_CLOSE)
+               alc298_samsung_v2_disable_amps(codec);
+}
+
+static void alc298_samsung_v2_init_amps(struct hda_codec *codec,
+                               int num_speaker_amps)
+{
+       struct alc_spec *spec = codec->spec;
+       int i, j;
+
+       /* Set spec's num_speaker_amps before doing anything else */
+       spec->num_speaker_amps = num_speaker_amps;
+
+       /* Disable speaker amps before init to prevent any physical damage */
+       alc298_samsung_v2_disable_amps(codec);
+
+       /* Initialize the speaker amps */
+       for (i = 0; i < spec->num_speaker_amps; i++) {
+               alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
+               for (j = 0; j < alc298_samsung_v2_amp_desc_tbl[i].init_seq_size; j++) {
+                       alc298_samsung_write_coef_pack(codec,
+                                       alc298_samsung_v2_amp_desc_tbl[i].init_seq[j]);
+               }
+               alc_write_coef_idx(codec, 0x89, 0x0);
+               codec_dbg(codec, "alc298_samsung_v2: Initialized speaker amp 0x%02x\n",
+                               alc298_samsung_v2_amp_desc_tbl[i].nid);
+       }
+
+       /* register hook to enable speaker amps only when they are needed */
+       spec->gen.pcm_playback_hook = alc298_samsung_v2_playback_hook;
+}
+
+static void alc298_fixup_samsung_amp_v2_2_amps(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PROBE)
+               alc298_samsung_v2_init_amps(codec, 2);
+}
+
+static void alc298_fixup_samsung_amp_v2_4_amps(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PROBE)
+               alc298_samsung_v2_init_amps(codec, 4);
+}
+
+static void gpio2_mic_hotkey_event(struct hda_codec *codec,
+                                  struct hda_jack_callback *event)
+{
+       struct alc_spec *spec = codec->spec;
+
+       /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
+          send both key on and key off event for every interrupt. */
+       input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 1);
+       input_sync(spec->kb_dev);
+       input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 0);
+       input_sync(spec->kb_dev);
+}
+
+static int alc_register_micmute_input_device(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int i;
+
+       spec->kb_dev = input_allocate_device();
+       if (!spec->kb_dev) {
+               codec_err(codec, "Out of memory (input_allocate_device)\n");
+               return -ENOMEM;
+       }
+
+       spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX] = KEY_MICMUTE;
+
+       spec->kb_dev->name = "Microphone Mute Button";
+       spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
+       spec->kb_dev->keycodesize = sizeof(spec->alc_mute_keycode_map[0]);
+       spec->kb_dev->keycodemax = ARRAY_SIZE(spec->alc_mute_keycode_map);
+       spec->kb_dev->keycode = spec->alc_mute_keycode_map;
+       for (i = 0; i < ARRAY_SIZE(spec->alc_mute_keycode_map); i++)
+               set_bit(spec->alc_mute_keycode_map[i], spec->kb_dev->keybit);
+
+       if (input_register_device(spec->kb_dev)) {
+               codec_err(codec, "input_register_device failed\n");
+               input_free_device(spec->kb_dev);
+               spec->kb_dev = NULL;
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/* GPIO1 = set according to SKU external amp
+ * GPIO2 = mic mute hotkey
+ * GPIO3 = mute LED
+ * GPIO4 = mic mute LED
+ */
+static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
+                                            const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->init_amp = ALC_INIT_DEFAULT;
+               if (alc_register_micmute_input_device(codec) != 0)
+                       return;
+
+               spec->gpio_mask |= 0x06;
+               spec->gpio_dir |= 0x02;
+               spec->gpio_data |= 0x02;
+               snd_hda_codec_write_cache(codec, codec->core.afg, 0,
+                                         AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
+               snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
+                                                   gpio2_mic_hotkey_event);
+               return;
+       }
+
+       if (!spec->kb_dev)
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_FREE:
+               input_unregister_device(spec->kb_dev);
+               spec->kb_dev = NULL;
+       }
+}
+
+/* Line2 = mic mute hotkey
+ * GPIO2 = mic mute LED
+ */
+static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
+                                            const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->init_amp = ALC_INIT_DEFAULT;
+               if (alc_register_micmute_input_device(codec) != 0)
+                       return;
+
+               snd_hda_jack_detect_enable_callback(codec, 0x1b,
+                                                   gpio2_mic_hotkey_event);
+               return;
+       }
+
+       if (!spec->kb_dev)
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_FREE:
+               input_unregister_device(spec->kb_dev);
+               spec->kb_dev = NULL;
+       }
+}
+
+static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1a);
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->cap_mute_led_nid = 0x18;
+               snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
+       }
+}
+
+static void alc233_fixup_lenovo_low_en_micmute_led(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->micmute_led_polarity = 1;
+       alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action);
+}
+
+static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
+{
+       if (delay <= 0)
+               delay = 75;
+       snd_hda_codec_write(codec, 0x21, 0,
+                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+       msleep(delay);
+       snd_hda_codec_write(codec, 0x21, 0,
+                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+       msleep(delay);
+}
+
+static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay)
+{
+       if (delay <= 0)
+               delay = 75;
+       snd_hda_codec_write(codec, 0x21, 0,
+                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+       msleep(delay);
+       snd_hda_codec_write(codec, 0x21, 0,
+                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+       msleep(delay);
+}
+
+static const struct coef_fw alc225_pre_hsmode[] = {
+       UPDATE_COEF(0x4a, 1<<8, 0),
+       UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
+       UPDATE_COEF(0x63, 3<<14, 3<<14),
+       UPDATE_COEF(0x4a, 3<<4, 2<<4),
+       UPDATE_COEF(0x4a, 3<<10, 3<<10),
+       UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
+       UPDATE_COEF(0x4a, 3<<10, 0),
+       {}
+};
+
+static void alc_headset_mode_unplugged(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct coef_fw coef0255[] = {
+               WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
+               WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+               WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+               WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
+               {}
+       };
+       static const struct coef_fw coef0256[] = {
+               WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
+               WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
+               WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
+               WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
+               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+               {}
+       };
+       static const struct coef_fw coef0233[] = {
+               WRITE_COEF(0x1b, 0x0c0b),
+               WRITE_COEF(0x45, 0xc429),
+               UPDATE_COEF(0x35, 0x4000, 0),
+               WRITE_COEF(0x06, 0x2104),
+               WRITE_COEF(0x1a, 0x0001),
+               WRITE_COEF(0x26, 0x0004),
+               WRITE_COEF(0x32, 0x42a3),
+               {}
+       };
+       static const struct coef_fw coef0288[] = {
+               UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+               UPDATE_COEF(0x50, 0x2000, 0x2000),
+               UPDATE_COEF(0x56, 0x0006, 0x0006),
+               UPDATE_COEF(0x66, 0x0008, 0),
+               UPDATE_COEF(0x67, 0x2000, 0),
+               {}
+       };
+       static const struct coef_fw coef0298[] = {
+               UPDATE_COEF(0x19, 0x1300, 0x0300),
+               {}
+       };
+       static const struct coef_fw coef0292[] = {
+               WRITE_COEF(0x76, 0x000e),
+               WRITE_COEF(0x6c, 0x2400),
+               WRITE_COEF(0x18, 0x7308),
+               WRITE_COEF(0x6b, 0xc429),
+               {}
+       };
+       static const struct coef_fw coef0293[] = {
+               UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
+               UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
+               UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
+               UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
+               WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
+               UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+               {}
+       };
+       static const struct coef_fw coef0668[] = {
+               WRITE_COEF(0x15, 0x0d40),
+               WRITE_COEF(0xb7, 0x802b),
+               {}
+       };
+       static const struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x63, 3<<14, 0),
+               {}
+       };
+       static const struct coef_fw coef0274[] = {
+               UPDATE_COEF(0x4a, 0x0100, 0),
+               UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
+               UPDATE_COEF(0x6b, 0xf000, 0x5000),
+               UPDATE_COEF(0x4a, 0x0010, 0),
+               UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
+               WRITE_COEF(0x45, 0x5289),
+               UPDATE_COEF(0x4a, 0x0c00, 0),
+               {}
+       };
+
+       if (spec->no_internal_mic_pin) {
+               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+               return;
+       }
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0255:
+               alc_process_coef_fw(codec, coef0255);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x19e58326:
+               alc_hp_mute_disable(codec, 75);
+               alc_process_coef_fw(codec, coef0256);
+               break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_process_coef_fw(codec, coef0274);
+               break;
+       case 0x10ec0233:
+       case 0x10ec0283:
+               alc_process_coef_fw(codec, coef0233);
+               break;
+       case 0x10ec0286:
+       case 0x10ec0288:
+               alc_process_coef_fw(codec, coef0288);
+               break;
+       case 0x10ec0298:
+               alc_process_coef_fw(codec, coef0298);
+               alc_process_coef_fw(codec, coef0288);
+               break;
+       case 0x10ec0292:
+               alc_process_coef_fw(codec, coef0292);
+               break;
+       case 0x10ec0293:
+               alc_process_coef_fw(codec, coef0293);
+               break;
+       case 0x10ec0668:
+               alc_process_coef_fw(codec, coef0668);
+               break;
+       case 0x10ec0215:
+       case 0x10ec0225:
+       case 0x10ec0285:
+       case 0x10ec0295:
+       case 0x10ec0289:
+       case 0x10ec0299:
+               alc_hp_mute_disable(codec, 75);
+               alc_process_coef_fw(codec, alc225_pre_hsmode);
+               alc_process_coef_fw(codec, coef0225);
+               break;
+       case 0x10ec0867:
+               alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+               break;
+       }
+       codec_dbg(codec, "Headset jack set to unplugged mode.\n");
+}
+
+
+static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
+                                   hda_nid_t mic_pin)
+{
+       static const struct coef_fw coef0255[] = {
+               WRITE_COEFEX(0x57, 0x03, 0x8aa6),
+               WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+               {}
+       };
+       static const struct coef_fw coef0256[] = {
+               UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
+               WRITE_COEFEX(0x57, 0x03, 0x09a3),
+               WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
+               {}
+       };
+       static const struct coef_fw coef0233[] = {
+               UPDATE_COEF(0x35, 0, 1<<14),
+               WRITE_COEF(0x06, 0x2100),
+               WRITE_COEF(0x1a, 0x0021),
+               WRITE_COEF(0x26, 0x008c),
+               {}
+       };
+       static const struct coef_fw coef0288[] = {
+               UPDATE_COEF(0x4f, 0x00c0, 0),
+               UPDATE_COEF(0x50, 0x2000, 0),
+               UPDATE_COEF(0x56, 0x0006, 0),
+               UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
+               UPDATE_COEF(0x66, 0x0008, 0x0008),
+               UPDATE_COEF(0x67, 0x2000, 0x2000),
+               {}
+       };
+       static const struct coef_fw coef0292[] = {
+               WRITE_COEF(0x19, 0xa208),
+               WRITE_COEF(0x2e, 0xacf0),
+               {}
+       };
+       static const struct coef_fw coef0293[] = {
+               UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
+               UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
+               UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+               {}
+       };
+       static const struct coef_fw coef0688[] = {
+               WRITE_COEF(0xb7, 0x802b),
+               WRITE_COEF(0xb5, 0x1040),
+               UPDATE_COEF(0xc3, 0, 1<<12),
+               {}
+       };
+       static const struct coef_fw coef0225[] = {
+               UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
+               UPDATE_COEF(0x4a, 3<<4, 2<<4),
+               UPDATE_COEF(0x63, 3<<14, 0),
+               {}
+       };
+       static const struct coef_fw coef0274[] = {
+               UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
+               UPDATE_COEF(0x4a, 0x0010, 0),
+               UPDATE_COEF(0x6b, 0xf000, 0),
+               {}
+       };
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0255:
+               alc_write_coef_idx(codec, 0x45, 0xc489);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0255);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x19e58326:
+               alc_write_coef_idx(codec, 0x45, 0xc489);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0256);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_write_coef_idx(codec, 0x45, 0x4689);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0274);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0233:
+       case 0x10ec0283:
+               alc_write_coef_idx(codec, 0x45, 0xc429);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0233);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0286:
+       case 0x10ec0288:
+       case 0x10ec0298:
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0288);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0292:
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0292);
+               break;
+       case 0x10ec0293:
+               /* Set to TRS mode */
+               alc_write_coef_idx(codec, 0x45, 0xc429);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0293);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0867:
+               alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
+               fallthrough;
+       case 0x10ec0221:
+       case 0x10ec0662:
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0668:
+               alc_write_coef_idx(codec, 0x11, 0x0001);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0688);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       case 0x10ec0215:
+       case 0x10ec0225:
+       case 0x10ec0285:
+       case 0x10ec0295:
+       case 0x10ec0289:
+       case 0x10ec0299:
+               alc_process_coef_fw(codec, alc225_pre_hsmode);
+               alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
+               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
+               alc_process_coef_fw(codec, coef0225);
+               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
+               break;
+       }
+       codec_dbg(codec, "Headset jack set to mic-in mode.\n");
+}
+
+static void alc_headset_mode_default(struct hda_codec *codec)
+{
+       static const struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
+               UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
+               UPDATE_COEF(0x49, 3<<8, 0<<8),
+               UPDATE_COEF(0x4a, 3<<4, 3<<4),
+               UPDATE_COEF(0x63, 3<<14, 0),
+               UPDATE_COEF(0x67, 0xf000, 0x3000),
+               {}
+       };
+       static const struct coef_fw coef0255[] = {
+               WRITE_COEF(0x45, 0xc089),
+               WRITE_COEF(0x45, 0xc489),
+               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+               WRITE_COEF(0x49, 0x0049),
+               {}
+       };
+       static const struct coef_fw coef0256[] = {
+               WRITE_COEF(0x45, 0xc489),
+               WRITE_COEFEX(0x57, 0x03, 0x0da3),
+               WRITE_COEF(0x49, 0x0049),
+               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
+               WRITE_COEF(0x06, 0x6100),
+               {}
+       };
+       static const struct coef_fw coef0233[] = {
+               WRITE_COEF(0x06, 0x2100),
+               WRITE_COEF(0x32, 0x4ea3),
+               {}
+       };
+       static const struct coef_fw coef0288[] = {
+               UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
+               UPDATE_COEF(0x50, 0x2000, 0x2000),
+               UPDATE_COEF(0x56, 0x0006, 0x0006),
+               UPDATE_COEF(0x66, 0x0008, 0),
+               UPDATE_COEF(0x67, 0x2000, 0),
+               {}
+       };
+       static const struct coef_fw coef0292[] = {
+               WRITE_COEF(0x76, 0x000e),
+               WRITE_COEF(0x6c, 0x2400),
+               WRITE_COEF(0x6b, 0xc429),
+               WRITE_COEF(0x18, 0x7308),
+               {}
+       };
+       static const struct coef_fw coef0293[] = {
+               UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
+               WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
+               UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
+               {}
+       };
+       static const struct coef_fw coef0688[] = {
+               WRITE_COEF(0x11, 0x0041),
+               WRITE_COEF(0x15, 0x0d40),
+               WRITE_COEF(0xb7, 0x802b),
+               {}
+       };
+       static const struct coef_fw coef0274[] = {
+               WRITE_COEF(0x45, 0x4289),
+               UPDATE_COEF(0x4a, 0x0010, 0x0010),
+               UPDATE_COEF(0x6b, 0x0f00, 0),
+               UPDATE_COEF(0x49, 0x0300, 0x0300),
+               {}
+       };
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0215:
+       case 0x10ec0225:
+       case 0x10ec0285:
+       case 0x10ec0295:
+       case 0x10ec0289:
+       case 0x10ec0299:
+               alc_process_coef_fw(codec, alc225_pre_hsmode);
+               alc_process_coef_fw(codec, coef0225);
+               alc_hp_enable_unmute(codec, 75);
+               break;
+       case 0x10ec0255:
+               alc_process_coef_fw(codec, coef0255);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x19e58326:
+               alc_write_coef_idx(codec, 0x1b, 0x0e4b);
+               alc_write_coef_idx(codec, 0x45, 0xc089);
+               msleep(50);
+               alc_process_coef_fw(codec, coef0256);
+               alc_hp_enable_unmute(codec, 75);
+               break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_process_coef_fw(codec, coef0274);
+               break;
+       case 0x10ec0233:
+       case 0x10ec0283:
+               alc_process_coef_fw(codec, coef0233);
+               break;
+       case 0x10ec0286:
+       case 0x10ec0288:
+       case 0x10ec0298:
+               alc_process_coef_fw(codec, coef0288);
+               break;
+       case 0x10ec0292:
+               alc_process_coef_fw(codec, coef0292);
+               break;
+       case 0x10ec0293:
+               alc_process_coef_fw(codec, coef0293);
+               break;
+       case 0x10ec0668:
+               alc_process_coef_fw(codec, coef0688);
+               break;
+       case 0x10ec0867:
+               alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+               break;
+       }
+       codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
+}
+
+/* Iphone type */
+static void alc_headset_mode_ctia(struct hda_codec *codec)
+{
+       int val;
+
+       static const struct coef_fw coef0255[] = {
+               WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+               WRITE_COEF(0x1b, 0x0c2b),
+               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+               {}
+       };
+       static const struct coef_fw coef0256[] = {
+               WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
+               WRITE_COEF(0x1b, 0x0e6b),
+               {}
+       };
+       static const struct coef_fw coef0233[] = {
+               WRITE_COEF(0x45, 0xd429),
+               WRITE_COEF(0x1b, 0x0c2b),
+               WRITE_COEF(0x32, 0x4ea3),
+               {}
+       };
+       static const struct coef_fw coef0288[] = {
+               UPDATE_COEF(0x50, 0x2000, 0x2000),
+               UPDATE_COEF(0x56, 0x0006, 0x0006),
+               UPDATE_COEF(0x66, 0x0008, 0),
+               UPDATE_COEF(0x67, 0x2000, 0),
+               {}
+       };
+       static const struct coef_fw coef0292[] = {
+               WRITE_COEF(0x6b, 0xd429),
+               WRITE_COEF(0x76, 0x0008),
+               WRITE_COEF(0x18, 0x7388),
+               {}
+       };
+       static const struct coef_fw coef0293[] = {
+               WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
+               UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+               {}
+       };
+       static const struct coef_fw coef0688[] = {
+               WRITE_COEF(0x11, 0x0001),
+               WRITE_COEF(0x15, 0x0d60),
+               WRITE_COEF(0xc3, 0x0000),
+               {}
+       };
+       static const struct coef_fw coef0225_1[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+               UPDATE_COEF(0x63, 3<<14, 2<<14),
+               {}
+       };
+       static const struct coef_fw coef0225_2[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
+               UPDATE_COEF(0x63, 3<<14, 1<<14),
+               {}
+       };
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0255:
+               alc_process_coef_fw(codec, coef0255);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x19e58326:
+               alc_process_coef_fw(codec, coef0256);
+               alc_hp_enable_unmute(codec, 75);
+               break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_write_coef_idx(codec, 0x45, 0xd689);
+               break;
+       case 0x10ec0233:
+       case 0x10ec0283:
+               alc_process_coef_fw(codec, coef0233);
+               break;
+       case 0x10ec0298:
+               val = alc_read_coef_idx(codec, 0x50);
+               if (val & (1 << 12)) {
+                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+                       alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+                       msleep(300);
+               } else {
+                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+                       alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+                       msleep(300);
+               }
+               break;
+       case 0x10ec0286:
+       case 0x10ec0288:
+               alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
+               msleep(300);
+               alc_process_coef_fw(codec, coef0288);
+               break;
+       case 0x10ec0292:
+               alc_process_coef_fw(codec, coef0292);
+               break;
+       case 0x10ec0293:
+               alc_process_coef_fw(codec, coef0293);
+               break;
+       case 0x10ec0668:
+               alc_process_coef_fw(codec, coef0688);
+               break;
+       case 0x10ec0215:
+       case 0x10ec0225:
+       case 0x10ec0285:
+       case 0x10ec0295:
+       case 0x10ec0289:
+       case 0x10ec0299:
+               val = alc_read_coef_idx(codec, 0x45);
+               if (val & (1 << 9))
+                       alc_process_coef_fw(codec, coef0225_2);
+               else
+                       alc_process_coef_fw(codec, coef0225_1);
+               alc_hp_enable_unmute(codec, 75);
+               break;
+       case 0x10ec0867:
+               alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+               break;
+       }
+       codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
+}
+
+/* Nokia type */
+static void alc_headset_mode_omtp(struct hda_codec *codec)
+{
+       static const struct coef_fw coef0255[] = {
+               WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+               WRITE_COEF(0x1b, 0x0c2b),
+               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
+               {}
+       };
+       static const struct coef_fw coef0256[] = {
+               WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
+               WRITE_COEF(0x1b, 0x0e6b),
+               {}
+       };
+       static const struct coef_fw coef0233[] = {
+               WRITE_COEF(0x45, 0xe429),
+               WRITE_COEF(0x1b, 0x0c2b),
+               WRITE_COEF(0x32, 0x4ea3),
+               {}
+       };
+       static const struct coef_fw coef0288[] = {
+               UPDATE_COEF(0x50, 0x2000, 0x2000),
+               UPDATE_COEF(0x56, 0x0006, 0x0006),
+               UPDATE_COEF(0x66, 0x0008, 0),
+               UPDATE_COEF(0x67, 0x2000, 0),
+               {}
+       };
+       static const struct coef_fw coef0292[] = {
+               WRITE_COEF(0x6b, 0xe429),
+               WRITE_COEF(0x76, 0x0008),
+               WRITE_COEF(0x18, 0x7388),
+               {}
+       };
+       static const struct coef_fw coef0293[] = {
+               WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
+               UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
+               {}
+       };
+       static const struct coef_fw coef0688[] = {
+               WRITE_COEF(0x11, 0x0001),
+               WRITE_COEF(0x15, 0x0d50),
+               WRITE_COEF(0xc3, 0x0000),
+               {}
+       };
+       static const struct coef_fw coef0225[] = {
+               UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
+               UPDATE_COEF(0x63, 3<<14, 2<<14),
+               {}
+       };
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0255:
+               alc_process_coef_fw(codec, coef0255);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x19e58326:
+               alc_process_coef_fw(codec, coef0256);
+               alc_hp_enable_unmute(codec, 75);
+               break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_write_coef_idx(codec, 0x45, 0xe689);
+               break;
+       case 0x10ec0233:
+       case 0x10ec0283:
+               alc_process_coef_fw(codec, coef0233);
+               break;
+       case 0x10ec0298:
+               alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
+               alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+               msleep(300);
+               break;
+       case 0x10ec0286:
+       case 0x10ec0288:
+               alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
+               msleep(300);
+               alc_process_coef_fw(codec, coef0288);
+               break;
+       case 0x10ec0292:
+               alc_process_coef_fw(codec, coef0292);
+               break;
+       case 0x10ec0293:
+               alc_process_coef_fw(codec, coef0293);
+               break;
+       case 0x10ec0668:
+               alc_process_coef_fw(codec, coef0688);
+               break;
+       case 0x10ec0215:
+       case 0x10ec0225:
+       case 0x10ec0285:
+       case 0x10ec0295:
+       case 0x10ec0289:
+       case 0x10ec0299:
+               alc_process_coef_fw(codec, coef0225);
+               alc_hp_enable_unmute(codec, 75);
+               break;
+       }
+       codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
+}
+
+static void alc_determine_headset_type(struct hda_codec *codec)
+{
+       int val;
+       bool is_ctia = false;
+       struct alc_spec *spec = codec->spec;
+       static const struct coef_fw coef0255[] = {
+               WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
+               WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
+ conteol) */
+               {}
+       };
+       static const struct coef_fw coef0288[] = {
+               UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
+               {}
+       };
+       static const struct coef_fw coef0298[] = {
+               UPDATE_COEF(0x50, 0x2000, 0x2000),
+               UPDATE_COEF(0x56, 0x0006, 0x0006),
+               UPDATE_COEF(0x66, 0x0008, 0),
+               UPDATE_COEF(0x67, 0x2000, 0),
+               UPDATE_COEF(0x19, 0x1300, 0x1300),
+               {}
+       };
+       static const struct coef_fw coef0293[] = {
+               UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
+               WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
+               {}
+       };
+       static const struct coef_fw coef0688[] = {
+               WRITE_COEF(0x11, 0x0001),
+               WRITE_COEF(0xb7, 0x802b),
+               WRITE_COEF(0x15, 0x0d60),
+               WRITE_COEF(0xc3, 0x0c00),
+               {}
+       };
+       static const struct coef_fw coef0274[] = {
+               UPDATE_COEF(0x4a, 0x0010, 0),
+               UPDATE_COEF(0x4a, 0x8000, 0),
+               WRITE_COEF(0x45, 0xd289),
+               UPDATE_COEF(0x49, 0x0300, 0x0300),
+               {}
+       };
+
+       if (spec->no_internal_mic_pin) {
+               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+               return;
+       }
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0255:
+               alc_process_coef_fw(codec, coef0255);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x0070) == 0x0070;
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x19e58326:
+               alc_write_coef_idx(codec, 0x1b, 0x0e4b);
+               alc_write_coef_idx(codec, 0x06, 0x6104);
+               alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
+
+               alc_process_coef_fw(codec, coef0255);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x0070) == 0x0070;
+               if (!is_ctia) {
+                       alc_write_coef_idx(codec, 0x45, 0xe089);
+                       msleep(100);
+                       val = alc_read_coef_idx(codec, 0x46);
+                       if ((val & 0x0070) == 0x0070)
+                               is_ctia = false;
+                       else
+                               is_ctia = true;
+               }
+               alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
+               alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
+               break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               alc_process_coef_fw(codec, coef0274);
+               msleep(850);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x00f0) == 0x00f0;
+               break;
+       case 0x10ec0233:
+       case 0x10ec0283:
+               alc_write_coef_idx(codec, 0x45, 0xd029);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x0070) == 0x0070;
+               break;
+       case 0x10ec0298:
+               snd_hda_codec_write(codec, 0x21, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+               msleep(100);
+               snd_hda_codec_write(codec, 0x21, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
+               msleep(200);
+
+               val = alc_read_coef_idx(codec, 0x50);
+               if (val & (1 << 12)) {
+                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
+                       alc_process_coef_fw(codec, coef0288);
+                       msleep(350);
+                       val = alc_read_coef_idx(codec, 0x50);
+                       is_ctia = (val & 0x0070) == 0x0070;
+               } else {
+                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
+                       alc_process_coef_fw(codec, coef0288);
+                       msleep(350);
+                       val = alc_read_coef_idx(codec, 0x50);
+                       is_ctia = (val & 0x0070) == 0x0070;
+               }
+               alc_process_coef_fw(codec, coef0298);
+               snd_hda_codec_write(codec, 0x21, 0,
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
+               msleep(75);
+               snd_hda_codec_write(codec, 0x21, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
+               break;
+       case 0x10ec0286:
+       case 0x10ec0288:
+               alc_process_coef_fw(codec, coef0288);
+               msleep(350);
+               val = alc_read_coef_idx(codec, 0x50);
+               is_ctia = (val & 0x0070) == 0x0070;
+               break;
+       case 0x10ec0292:
+               alc_write_coef_idx(codec, 0x6b, 0xd429);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0x6c);
+               is_ctia = (val & 0x001c) == 0x001c;
+               break;
+       case 0x10ec0293:
+               alc_process_coef_fw(codec, coef0293);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0x46);
+               is_ctia = (val & 0x0070) == 0x0070;
+               break;
+       case 0x10ec0668:
+               alc_process_coef_fw(codec, coef0688);
+               msleep(300);
+               val = alc_read_coef_idx(codec, 0xbe);
+               is_ctia = (val & 0x1c02) == 0x1c02;
+               break;
+       case 0x10ec0215:
+       case 0x10ec0225:
+       case 0x10ec0285:
+       case 0x10ec0295:
+       case 0x10ec0289:
+       case 0x10ec0299:
+               alc_process_coef_fw(codec, alc225_pre_hsmode);
+               alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
+               val = alc_read_coef_idx(codec, 0x45);
+               if (val & (1 << 9)) {
+                       alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+                       alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
+                       msleep(800);
+                       val = alc_read_coef_idx(codec, 0x46);
+                       is_ctia = (val & 0x00f0) == 0x00f0;
+               } else {
+                       alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
+                       alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+                       msleep(800);
+                       val = alc_read_coef_idx(codec, 0x46);
+                       is_ctia = (val & 0x00f0) == 0x00f0;
+               }
+               if (!is_ctia) {
+                       alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10);
+                       alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
+                       msleep(100);
+                       val = alc_read_coef_idx(codec, 0x46);
+                       if ((val & 0x00f0) == 0x00f0)
+                               is_ctia = false;
+                       else
+                               is_ctia = true;
+               }
+               alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
+               alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
+               alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
+               break;
+       case 0x10ec0867:
+               is_ctia = true;
+               break;
+       }
+
+       codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
+                 str_yes_no(is_ctia));
+       spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
+}
+
+static void alc_update_headset_mode(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+
+       hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
+       hda_nid_t hp_pin = alc_get_hp_pin(spec);
+
+       int new_headset_mode;
+
+       if (!snd_hda_jack_detect(codec, hp_pin))
+               new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
+       else if (mux_pin == spec->headset_mic_pin)
+               new_headset_mode = ALC_HEADSET_MODE_HEADSET;
+       else if (mux_pin == spec->headphone_mic_pin)
+               new_headset_mode = ALC_HEADSET_MODE_MIC;
+       else
+               new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
+
+       if (new_headset_mode == spec->current_headset_mode) {
+               snd_hda_gen_update_outputs(codec);
+               return;
+       }
+
+       switch (new_headset_mode) {
+       case ALC_HEADSET_MODE_UNPLUGGED:
+               alc_headset_mode_unplugged(codec);
+               spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
+               spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
+               spec->gen.hp_jack_present = false;
+               break;
+       case ALC_HEADSET_MODE_HEADSET:
+               if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
+                       alc_determine_headset_type(codec);
+               if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
+                       alc_headset_mode_ctia(codec);
+               else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
+                       alc_headset_mode_omtp(codec);
+               spec->gen.hp_jack_present = true;
+               break;
+       case ALC_HEADSET_MODE_MIC:
+               alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
+               spec->gen.hp_jack_present = false;
+               break;
+       case ALC_HEADSET_MODE_HEADPHONE:
+               alc_headset_mode_default(codec);
+               spec->gen.hp_jack_present = true;
+               break;
+       }
+       if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
+               snd_hda_set_pin_ctl_cache(codec, hp_pin,
+                                         AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
+               if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
+                       snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
+                                                 PIN_VREFHIZ);
+       }
+       spec->current_headset_mode = new_headset_mode;
+
+       snd_hda_gen_update_outputs(codec);
+}
+
+static void alc_update_headset_mode_hook(struct hda_codec *codec,
+                                        struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       alc_update_headset_mode(codec);
+}
+
+static void alc_update_headset_jack_cb(struct hda_codec *codec,
+                                      struct hda_jack_callback *jack)
+{
+       snd_hda_gen_hp_automute(codec, jack);
+       alc_update_headset_mode(codec);
+}
+
+static void alc_probe_headset_mode(struct hda_codec *codec)
+{
+       int i;
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+
+       /* Find mic pins */
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
+                       spec->headset_mic_pin = cfg->inputs[i].pin;
+               if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
+                       spec->headphone_mic_pin = cfg->inputs[i].pin;
+       }
+
+       WARN_ON(spec->gen.cap_sync_hook);
+       spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
+       spec->gen.automute_hook = alc_update_headset_mode;
+       spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
+}
+
+static void alc_fixup_headset_mode(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               alc_probe_headset_mode(codec);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               if (is_s3_resume(codec) || is_s4_resume(codec)) {
+                       spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
+                       spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
+               }
+               alc_update_headset_mode(codec);
+               break;
+       }
+}
+
+static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+       }
+       else
+               alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc255_set_default_jack_type(struct hda_codec *codec)
+{
+       /* Set to iphone type */
+       static const struct coef_fw alc255fw[] = {
+               WRITE_COEF(0x1b, 0x880b),
+               WRITE_COEF(0x45, 0xd089),
+               WRITE_COEF(0x1b, 0x080b),
+               WRITE_COEF(0x46, 0x0004),
+               WRITE_COEF(0x1b, 0x0c0b),
+               {}
+       };
+       static const struct coef_fw alc256fw[] = {
+               WRITE_COEF(0x1b, 0x884b),
+               WRITE_COEF(0x45, 0xd089),
+               WRITE_COEF(0x1b, 0x084b),
+               WRITE_COEF(0x46, 0x0004),
+               WRITE_COEF(0x1b, 0x0c4b),
+               {}
+       };
+       switch (codec->core.vendor_id) {
+       case 0x10ec0255:
+               alc_process_coef_fw(codec, alc255fw);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x19e58326:
+               alc_process_coef_fw(codec, alc256fw);
+               break;
+       }
+       msleep(30);
+}
+
+static void alc_fixup_headset_mode_alc255(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               alc255_set_default_jack_type(codec);
+       }
+       alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               alc255_set_default_jack_type(codec);
+       }
+       else
+               alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc288_update_headset_jack_cb(struct hda_codec *codec,
+                                      struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_update_headset_jack_cb(codec, jack);
+       /* Headset Mic enable or disable, only for Dell Dino */
+       alc_update_gpio_data(codec, 0x40, spec->gen.hp_jack_present);
+}
+
+static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       alc_fixup_headset_mode(codec, fix, action);
+       if (action == HDA_FIXUP_ACT_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               /* toggled via hp_automute_hook */
+               spec->gpio_mask |= 0x40;
+               spec->gpio_dir |= 0x40;
+               spec->gen.hp_automute_hook = alc288_update_headset_jack_cb;
+       }
+}
+
+static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->gen.auto_mute_via_amp = 1;
+       }
+}
+
+static void alc_fixup_no_shutup(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               spec->no_shutup_pins = 1;
+       }
+}
+
+static void alc_fixup_disable_aamix(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               struct alc_spec *spec = codec->spec;
+               /* Disable AA-loopback as it causes white noise */
+               spec->gen.mixer_nid = 0;
+       }
+}
+
+/* fixup for Thinkpad docks: add dock pins, avoid HP parser fixup */
+static void alc_fixup_tpt440_dock(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x16, 0x21211010 }, /* dock headphone */
+               { 0x19, 0x21a11010 }, /* dock mic */
+               { }
+       };
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+               codec->power_save_node = 0; /* avoid click noises */
+               snd_hda_apply_pincfgs(codec, pincfgs);
+       }
+}
+
+static void alc_fixup_tpt470_dock(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x17, 0x21211010 }, /* dock headphone */
+               { 0x19, 0x21a11010 }, /* dock mic */
+               { }
+       };
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+               snd_hda_apply_pincfgs(codec, pincfgs);
+       } else if (action == HDA_FIXUP_ACT_INIT) {
+               /* Enable DOCK device */
+               snd_hda_codec_write(codec, 0x17, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);
+               /* Enable DOCK device */
+               snd_hda_codec_write(codec, 0x19, 0,
+                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);
+       }
+}
+
+static void alc_fixup_tpt470_dacs(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       /* Assure the speaker pin to be coupled with DAC NID 0x03; otherwise
+        * the speaker output becomes too low by some reason on Thinkpads with
+        * ALC298 codec
+        */
+       static const hda_nid_t preferred_pairs[] = {
+               0x14, 0x03, 0x17, 0x02, 0x21, 0x02,
+               0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->gen.preferred_dacs = preferred_pairs;
+}
+
+static void alc295_fixup_asus_dacs(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t preferred_pairs[] = {
+               0x17, 0x02, 0x21, 0x03, 0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->gen.preferred_dacs = preferred_pairs;
+}
+
+static void alc_shutup_dell_xps13(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int hp_pin = alc_get_hp_pin(spec);
+
+       /* Prevent pop noises when headphones are plugged in */
+       snd_hda_codec_write(codec, hp_pin, 0,
+                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
+       msleep(20);
+}
+
+static void alc_fixup_dell_xps13(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->gen.input_mux;
+       int i;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               /* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
+                * it causes a click noise at start up
+                */
+               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+               spec->shutup = alc_shutup_dell_xps13;
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               /* Make the internal mic the default input source. */
+               for (i = 0; i < imux->num_items; i++) {
+                       if (spec->gen.imux_pins[i] == 0x12) {
+                               spec->gen.cur_mux[0] = i;
+                               break;
+                       }
+               }
+               break;
+       }
+}
+
+static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
+
+               /* Disable boost for mic-in permanently. (This code is only called
+                  from quirks that guarantee that the headphone is at NID 0x1b.) */
+               snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
+               snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
+       } else
+               alc_fixup_headset_mode(codec, fix, action);
+}
+
+static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               alc_write_coef_idx(codec, 0xc4, 0x8000);
+               alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
+               snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
+       }
+       alc_fixup_headset_mode(codec, fix, action);
+}
+
+/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
+static int find_ext_mic_pin(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+       hda_nid_t nid;
+       unsigned int defcfg;
+       int i;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               if (cfg->inputs[i].type != AUTO_PIN_MIC)
+                       continue;
+               nid = cfg->inputs[i].pin;
+               defcfg = snd_hda_codec_get_pincfg(codec, nid);
+               if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
+                       continue;
+               return nid;
+       }
+
+       return 0;
+}
+
+static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
+                                   const struct hda_fixup *fix,
+                                   int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PROBE) {
+               int mic_pin = find_ext_mic_pin(codec);
+               int hp_pin = alc_get_hp_pin(spec);
+
+               if (snd_BUG_ON(!mic_pin || !hp_pin))
+                       return;
+               snd_hda_jack_set_gating_jack(codec, mic_pin, hp_pin);
+       }
+}
+
+static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec,
+                                            const struct hda_fixup *fix,
+                                            int action)
+{
+       struct alc_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+       int i;
+
+       /* The mic boosts on level 2 and 3 are too noisy
+          on the internal mic input.
+          Therefore limit the boost to 0 or 1. */
+
+       if (action != HDA_FIXUP_ACT_PROBE)
+               return;
+
+       for (i = 0; i < cfg->num_inputs; i++) {
+               hda_nid_t nid = cfg->inputs[i].pin;
+               unsigned int defcfg;
+               if (cfg->inputs[i].type != AUTO_PIN_MIC)
+                       continue;
+               defcfg = snd_hda_codec_get_pincfg(codec, nid);
+               if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
+                       continue;
+
+               snd_hda_override_amp_caps(codec, nid, HDA_INPUT,
+                                         (0x00 << AC_AMPCAP_OFFSET_SHIFT) |
+                                         (0x01 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                         (0x2f << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                         (0 << AC_AMPCAP_MUTE_SHIFT));
+       }
+}
+
+static void alc283_hp_automute_hook(struct hda_codec *codec,
+                                   struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       int vref;
+
+       msleep(200);
+       snd_hda_gen_hp_automute(codec, jack);
+
+       vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+
+       msleep(600);
+       snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           vref);
+}
+
+static void alc283_fixup_chromebook(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_override_wcaps(codec, 0x03, 0);
+               /* Disable AA-loopback as it causes white noise */
+               spec->gen.mixer_nid = 0;
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* MIC2-VREF control */
+               /* Set to manual mode */
+               alc_update_coef_idx(codec, 0x06, 0x000c, 0);
+               /* Enable Line1 input control by verb */
+               alc_update_coef_idx(codec, 0x1a, 0, 1 << 4);
+               break;
+       }
+}
+
+static void alc283_fixup_sense_combo_jack(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->gen.hp_automute_hook = alc283_hp_automute_hook;
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* MIC2-VREF control */
+               /* Set to manual mode */
+               alc_update_coef_idx(codec, 0x06, 0x000c, 0);
+               break;
+       }
+}
+
+/* mute tablet speaker pin (0x14) via dock plugging in addition */
+static void asus_tx300_automute(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       snd_hda_gen_update_outputs(codec);
+       if (snd_hda_jack_detect(codec, 0x1b))
+               spec->gen.mute_bits |= (1ULL << 0x14);
+}
+
+static void alc282_fixup_asus_tx300(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_pintbl dock_pins[] = {
+               { 0x1b, 0x21114000 }, /* dock speaker pin */
+               {}
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->init_amp = ALC_INIT_DEFAULT;
+               /* TX300 needs to set up GPIO2 for the speaker amp */
+               alc_setup_gpio(codec, 0x04);
+               snd_hda_apply_pincfgs(codec, dock_pins);
+               spec->gen.auto_mute_via_amp = 1;
+               spec->gen.automute_hook = asus_tx300_automute;
+               snd_hda_jack_detect_enable_callback(codec, 0x1b,
+                                                   snd_hda_gen_hp_automute);
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               spec->init_amp = ALC_INIT_DEFAULT;
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               /* this is a bit tricky; give more sane names for the main
+                * (tablet) speaker and the dock speaker, respectively
+                */
+               rename_ctl(codec, "Speaker Playback Switch",
+                          "Dock Speaker Playback Switch");
+               rename_ctl(codec, "Bass Speaker Playback Switch",
+                          "Speaker Playback Switch");
+               break;
+       }
+}
+
+static void alc290_fixup_mono_speakers(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* DAC node 0x03 is giving mono output. We therefore want to
+                  make sure 0x14 (front speaker) and 0x15 (headphones) use the
+                  stereo DAC, while leaving 0x17 (bass speaker) for node 0x03. */
+               static const hda_nid_t conn1[] = { 0x0c };
+               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
+               snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
+       }
+}
+
+static void alc298_fixup_speaker_volume(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* The speaker is routed to the Node 0x06 by a mistake, as a result
+                  we can't adjust the speaker's volume since this node does not has
+                  Amp-out capability. we change the speaker's route to:
+                  Node 0x02 (Audio Output) -> Node 0x0c (Audio Mixer) -> Node 0x17 (
+                  Pin Complex), since Node 0x02 has Amp-out caps, we can adjust
+                  speaker's volume now. */
+
+               static const hda_nid_t conn1[] = { 0x0c };
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn1), conn1);
+       }
+}
+
+/* disable DAC3 (0x06) selection on NID 0x17 as it has no volume amp control */
+static void alc295_fixup_disable_dac3(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               static const hda_nid_t conn[] = { 0x02, 0x03 };
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+       }
+}
+
+/* force NID 0x17 (Bass Speaker) to DAC1 to share it with the main speaker */
+static void alc285_fixup_speaker2_to_dac1(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               static const hda_nid_t conn[] = { 0x02 };
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+       }
+}
+
+/* disable DAC3 (0x06) selection on NID 0x15 - share Speaker/Bass Speaker DAC 0x03 */
+static void alc294_fixup_bass_speaker_15(struct hda_codec *codec,
+                                        const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               static const hda_nid_t conn[] = { 0x02, 0x03 };
+               snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
+               snd_hda_gen_add_micmute_led_cdev(codec, NULL);
+       }
+}
+
+/* Hook to update amp GPIO4 for automute */
+static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
+                                         struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+
+       snd_hda_gen_hp_automute(codec, jack);
+       /* mute_led_polarity is set to 0, so we pass inverted value here */
+       alc_update_gpio_led(codec, 0x10, spec->mute_led_polarity,
+                           !spec->gen.hp_jack_present);
+}
+
+/* Manage GPIOs for HP EliteBook Folio 9480m.
+ *
+ * GPIO4 is the headphone amplifier power control
+ * GPIO3 is the audio output mute indicator LED
+ */
+
+static void alc280_fixup_hp_9480m(struct hda_codec *codec,
+                                 const struct hda_fixup *fix,
+                                 int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               /* amp at GPIO4; toggled via alc280_hp_gpio4_automute_hook() */
+               spec->gpio_mask |= 0x10;
+               spec->gpio_dir |= 0x10;
+               spec->gen.hp_automute_hook = alc280_hp_gpio4_automute_hook;
+       }
+}
+
+static void alc275_fixup_gpio4_off(struct hda_codec *codec,
+                                  const struct hda_fixup *fix,
+                                  int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gpio_mask |= 0x04;
+               spec->gpio_dir |= 0x04;
+               /* set data bit low */
+       }
+}
+
+/* Quirk for Thinkpad X1 7th and 8th Gen
+ * The following fixed routing needed
+ * DAC1 (NID 0x02) -> Speaker (NID 0x14); some eq applied secretly
+ * DAC2 (NID 0x03) -> Bass (NID 0x17) & Headphone (NID 0x21); sharing a DAC
+ * DAC3 (NID 0x06) -> Unused, due to the lack of volume amp
+ */
+static void alc285_fixup_thinkpad_x1_gen7(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
+       static const hda_nid_t preferred_pairs[] = {
+               0x14, 0x02, 0x17, 0x03, 0x21, 0x03, 0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               spec->gen.preferred_dacs = preferred_pairs;
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               /* The generic parser creates somewhat unintuitive volume ctls
+                * with the fixed routing above, and the shared DAC2 may be
+                * confusing for PA.
+                * Rename those to unique names so that PA doesn't touch them
+                * and use only Master volume.
+                */
+               rename_ctl(codec, "Front Playback Volume", "DAC1 Playback Volume");
+               rename_ctl(codec, "Bass Speaker Playback Volume", "DAC2 Playback Volume");
+               break;
+       }
+}
+
+static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
+                                        const struct hda_fixup *fix,
+                                        int action)
+{
+       alc_fixup_dual_codecs(codec, fix, action);
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               /* override card longname to provide a unique UCM profile */
+               strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               /* rename Capture controls depending on the codec */
+               rename_ctl(codec, "Capture Volume",
+                          codec->addr == 0 ?
+                          "Rear-Panel Capture Volume" :
+                          "Front-Panel Capture Volume");
+               rename_ctl(codec, "Capture Switch",
+                          codec->addr == 0 ?
+                          "Rear-Panel Capture Switch" :
+                          "Front-Panel Capture Switch");
+               break;
+       }
+}
+
+static void alc225_fixup_s3_pop_noise(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       codec->power_save_node = 1;
+}
+
+/* Forcibly assign NID 0x03 to HP/LO while NID 0x02 to SPK for EQ */
+static void alc274_fixup_bind_dacs(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const hda_nid_t preferred_pairs[] = {
+               0x21, 0x03, 0x1b, 0x03, 0x16, 0x02,
+               0
+       };
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       spec->gen.preferred_dacs = preferred_pairs;
+       spec->gen.auto_mute_via_amp = 1;
+       codec->power_save_node = 0;
+}
+
+/* avoid DAC 0x06 for speaker switch 0x17; it has no volume control */
+static void alc274_fixup_hp_aio_bind_dacs(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
+       /* The speaker is routed to the Node 0x06 by a mistake, thus the
+        * speaker's volume can't be adjusted since the node doesn't have
+        * Amp-out capability. Assure the speaker and lineout pin to be
+        * coupled with DAC NID 0x02.
+        */
+       static const hda_nid_t preferred_pairs[] = {
+               0x16, 0x02, 0x17, 0x02, 0x21, 0x03, 0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+       spec->gen.preferred_dacs = preferred_pairs;
+}
+
+/* avoid DAC 0x06 for bass speaker 0x17; it has no volume control */
+static void alc289_fixup_asus_ga401(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t preferred_pairs[] = {
+               0x14, 0x02, 0x17, 0x02, 0x21, 0x03, 0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->gen.preferred_dacs = preferred_pairs;
+}
+
+/* The DAC of NID 0x3 will introduce click/pop noise on headphones, so invalidate it */
+static void alc285_fixup_invalidate_dacs(struct hda_codec *codec,
+                             const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       snd_hda_override_wcaps(codec, 0x03, 0);
+}
+
+static void alc_combo_jack_hp_jd_restart(struct hda_codec *codec)
+{
+       switch (codec->core.vendor_id) {
+       case 0x10ec0274:
+       case 0x10ec0294:
+       case 0x10ec0225:
+       case 0x10ec0295:
+       case 0x10ec0299:
+               alc_update_coef_idx(codec, 0x4a, 0x8000, 1 << 15); /* Reset HP JD */
+               alc_update_coef_idx(codec, 0x4a, 0x8000, 0 << 15);
+               break;
+       case 0x10ec0230:
+       case 0x10ec0235:
+       case 0x10ec0236:
+       case 0x10ec0255:
+       case 0x10ec0256:
+       case 0x10ec0257:
+       case 0x19e58326:
+               alc_update_coef_idx(codec, 0x1b, 0x8000, 1 << 15); /* Reset HP JD */
+               alc_update_coef_idx(codec, 0x1b, 0x8000, 0 << 15);
+               break;
+       }
+}
+
+static void alc295_fixup_chromebook(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->ultra_low_power = true;
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               alc_combo_jack_hp_jd_restart(codec);
+               break;
+       }
+}
+
+static void alc256_fixup_chromebook(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               if (codec->core.subsystem_id == 0x10280d76)
+                       spec->gen.suppress_auto_mute = 0;
+               else
+                       spec->gen.suppress_auto_mute = 1;
+               spec->gen.suppress_auto_mic = 1;
+               spec->en_3kpull_low = false;
+               break;
+       }
+}
+
+static void alc_fixup_disable_mic_vref(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+}
+
+
+static void alc294_gx502_toggle_output(struct hda_codec *codec,
+                                       struct hda_jack_callback *cb)
+{
+       /* The Windows driver sets the codec up in a very different way where
+        * it appears to leave 0x10 = 0x8a20 set. For Linux we need to toggle it
+        */
+       if (snd_hda_jack_detect_state(codec, 0x21) == HDA_JACK_PRESENT)
+               alc_write_coef_idx(codec, 0x10, 0x8a20);
+       else
+               alc_write_coef_idx(codec, 0x10, 0x0a20);
+}
+
+static void alc294_fixup_gx502_hp(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       /* Pin 0x21: headphones/headset mic */
+       if (!is_jack_detectable(codec, 0x21))
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_jack_detect_enable_callback(codec, 0x21,
+                               alc294_gx502_toggle_output);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* Make sure to start in a correct state, i.e. if
+                * headphones have been plugged in before powering up the system
+                */
+               alc294_gx502_toggle_output(codec, NULL);
+               break;
+       }
+}
+
+static void alc294_gu502_toggle_output(struct hda_codec *codec,
+                                      struct hda_jack_callback *cb)
+{
+       /* Windows sets 0x10 to 0x8420 for Node 0x20 which is
+        * responsible from changes between speakers and headphones
+        */
+       if (snd_hda_jack_detect_state(codec, 0x21) == HDA_JACK_PRESENT)
+               alc_write_coef_idx(codec, 0x10, 0x8420);
+       else
+               alc_write_coef_idx(codec, 0x10, 0x0a20);
+}
+
+static void alc294_fixup_gu502_hp(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       if (!is_jack_detectable(codec, 0x21))
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_jack_detect_enable_callback(codec, 0x21,
+                               alc294_gu502_toggle_output);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               alc294_gu502_toggle_output(codec, NULL);
+               break;
+       }
+}
+
+static void  alc285_fixup_hp_gpio_amp_init(struct hda_codec *codec,
+                             const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_INIT)
+               return;
+
+       msleep(100);
+       alc_write_coef_idx(codec, 0x65, 0x0);
+}
+
+static void alc274_fixup_hp_headset_mic(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       switch (action) {
+       case HDA_FIXUP_ACT_INIT:
+               alc_combo_jack_hp_jd_restart(codec);
+               break;
+       }
+}
+
+static void alc_fixup_no_int_mic(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               /* Mic RING SLEEVE swap for combo jack */
+               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+               spec->no_internal_mic_pin = true;
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               alc_combo_jack_hp_jd_restart(codec);
+               break;
+       }
+}
+
+/* GPIO1 = amplifier on/off
+ * GPIO3 = mic mute LED
+ */
+static void alc285_fixup_hp_spectre_x360_eb1(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t conn[] = { 0x02 };
+
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x14, 0x90170110 },  /* front/high speakers */
+               { 0x17, 0x90170130 },  /* back/bass speakers */
+               { }
+       };
+
+       //enable micmute led
+       alc_fixup_hp_gpio_led(codec, action, 0x00, 0x04);
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->micmute_led_polarity = 1;
+               /* needed for amp of back speakers */
+               spec->gpio_mask |= 0x01;
+               spec->gpio_dir |= 0x01;
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               /* share DAC to have unified volume control */
+               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* need to toggle GPIO to enable the amp of back speakers */
+               alc_update_gpio_data(codec, 0x01, true);
+               msleep(100);
+               alc_update_gpio_data(codec, 0x01, false);
+               break;
+       }
+}
+
+/* GPIO1 = amplifier on/off */
+static void alc285_fixup_hp_spectre_x360_df1(struct hda_codec *codec,
+                                            const struct hda_fixup *fix,
+                                            int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const hda_nid_t conn[] = { 0x02 };
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x14, 0x90170110 },  /* front/high speakers */
+               { 0x17, 0x90170130 },  /* back/bass speakers */
+               { }
+       };
+
+       // enable mute led
+       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               /* needed for amp of back speakers */
+               spec->gpio_mask |= 0x01;
+               spec->gpio_dir |= 0x01;
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               /* share DAC to have unified volume control */
+               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* need to toggle GPIO to enable the amp of back speakers */
+               alc_update_gpio_data(codec, 0x01, true);
+               msleep(100);
+               alc_update_gpio_data(codec, 0x01, false);
+               break;
+       }
+}
+
+static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       static const hda_nid_t conn[] = { 0x02 };
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x14, 0x90170110 },  /* rear speaker */
+               { }
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               /* force front speaker to DAC1 */
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               break;
+       }
+}
+
+static void alc285_fixup_hp_envy_x360(struct hda_codec *codec,
+                                     const struct hda_fixup *fix,
+                                     int action)
+{
+       static const struct coef_fw coefs[] = {
+               WRITE_COEF(0x08, 0x6a0c), WRITE_COEF(0x0d, 0xa023),
+               WRITE_COEF(0x10, 0x0320), WRITE_COEF(0x1a, 0x8c03),
+               WRITE_COEF(0x25, 0x1800), WRITE_COEF(0x26, 0x003a),
+               WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb014),
+               WRITE_COEF(0x2b, 0x1dfe), WRITE_COEF(0x37, 0xfe15),
+               WRITE_COEF(0x38, 0x7909), WRITE_COEF(0x45, 0xd489),
+               WRITE_COEF(0x46, 0x00f4), WRITE_COEF(0x4a, 0x21e0),
+               WRITE_COEF(0x66, 0x03f0), WRITE_COEF(0x67, 0x1000),
+               WRITE_COEF(0x6e, 0x1005), { }
+       };
+
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x12, 0xb7a60130 },  /* Internal microphone*/
+               { 0x14, 0x90170150 },  /* B&O soundbar speakers */
+               { 0x17, 0x90170153 },  /* Side speakers */
+               { 0x19, 0x03a11040 },  /* Headset microphone */
+               { }
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+
+               /* Fixes volume control problem for side speakers */
+               alc295_fixup_disable_dac3(codec, fix, action);
+
+               /* Fixes no sound from headset speaker */
+               snd_hda_codec_amp_stereo(codec, 0x21, HDA_OUTPUT, 0, -1, 0);
+
+               /* Auto-enable headset mic when plugged */
+               snd_hda_jack_set_gating_jack(codec, 0x19, 0x21);
+
+               /* Headset mic volume enhancement */
+               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREF50);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               alc_process_coef_fw(codec, coefs);
+               break;
+       case HDA_FIXUP_ACT_BUILD:
+               rename_ctl(codec, "Bass Speaker Playback Volume",
+                          "B&O-Tuned Playback Volume");
+               rename_ctl(codec, "Front Playback Switch",
+                          "B&O Soundbar Playback Switch");
+               rename_ctl(codec, "Bass Speaker Playback Switch",
+                          "Side Speaker Playback Switch");
+               break;
+       }
+}
+
+static void alc285_fixup_hp_beep(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               codec->beep_just_power_on = true;
+       } else  if (action == HDA_FIXUP_ACT_INIT) {
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+               /*
+                * Just enable loopback to internal speaker and headphone jack.
+                * Disable amplification to get about the same beep volume as
+                * was on pure BIOS setup before loading the driver.
+                */
+               alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13));
+
+               snd_hda_enable_beep_device(codec, 1);
+
+#if !IS_ENABLED(CONFIG_INPUT_PCSPKR)
+               dev_warn_once(hda_codec_dev(codec),
+                             "enable CONFIG_INPUT_PCSPKR to get PC beeps\n");
+#endif
+#endif
+       }
+}
+
+/* for hda_fixup_thinkpad_acpi() */
+#include "helpers/thinkpad.c"
+
+static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       alc_fixup_no_shutup(codec, fix, action); /* reduce click noise */
+       hda_fixup_thinkpad_acpi(codec, fix, action);
+}
+
+/* for hda_fixup_ideapad_acpi() */
+#include "helpers/ideapad_hotkey_led.c"
+
+static void alc_fixup_ideapad_acpi(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       hda_fixup_ideapad_acpi(codec, fix, action);
+}
+
+/* Fixup for Lenovo Legion 15IMHg05 speaker output on headset removal. */
+static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
+                                                 const struct hda_fixup *fix,
+                                                 int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->gen.suppress_auto_mute = 1;
+               break;
+       }
+}
+
+static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct hda_codec *cdc = data;
+       struct alc_spec *spec = cdc->spec;
+
+       codec_info(cdc, "ACPI Notification %d\n", event);
+
+       hda_component_acpi_device_notify(&spec->comps, handle, event, data);
+}
+
+static int comp_bind(struct device *dev)
+{
+       struct hda_codec *cdc = dev_to_hda_codec(dev);
+       struct alc_spec *spec = cdc->spec;
+       int ret;
+
+       ret = hda_component_manager_bind(cdc, &spec->comps);
+       if (ret)
+               return ret;
+
+       return hda_component_manager_bind_acpi_notifications(cdc,
+                                                            &spec->comps,
+                                                            comp_acpi_device_notify, cdc);
+}
+
+static void comp_unbind(struct device *dev)
+{
+       struct hda_codec *cdc = dev_to_hda_codec(dev);
+       struct alc_spec *spec = cdc->spec;
+
+       hda_component_manager_unbind_acpi_notifications(cdc, &spec->comps, comp_acpi_device_notify);
+       hda_component_manager_unbind(cdc, &spec->comps);
+}
+
+static const struct component_master_ops comp_master_ops = {
+       .bind = comp_bind,
+       .unbind = comp_unbind,
+};
+
+static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_codec *cdc,
+                                      struct snd_pcm_substream *sub, int action)
+{
+       struct alc_spec *spec = cdc->spec;
+
+       hda_component_manager_playback_hook(&spec->comps, action);
+}
+
+static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
+                              const char *hid, const char *match_str, int count)
+{
+       struct alc_spec *spec = cdc->spec;
+       int ret;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               ret = hda_component_manager_init(cdc, &spec->comps, count, bus, hid,
+                                                match_str, &comp_master_ops);
+               if (ret)
+                       return;
+
+               spec->gen.pcm_playback_hook = comp_generic_playback_hook;
+               break;
+       case HDA_FIXUP_ACT_FREE:
+               hda_component_manager_free(&spec->comps, &comp_master_ops);
+               break;
+       }
+}
+
+static void find_cirrus_companion_amps(struct hda_codec *cdc)
+{
+       struct device *dev = hda_codec_dev(cdc);
+       struct acpi_device *adev;
+       struct fwnode_handle *fwnode __free(fwnode_handle) = NULL;
+       const char *bus = NULL;
+       static const struct {
+               const char *hid;
+               const char *name;
+       } acpi_ids[] = {{ "CSC3554", "cs35l54-hda" },
+                       { "CSC3556", "cs35l56-hda" },
+                       { "CSC3557", "cs35l57-hda" }};
+       char *match;
+       int i, count = 0, count_devindex = 0;
+
+       for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) {
+               adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid, NULL, -1);
+               if (adev)
+                       break;
+       }
+       if (!adev) {
+               codec_dbg(cdc, "Did not find ACPI entry for a Cirrus Amp\n");
+               return;
+       }
+
+       count = i2c_acpi_client_count(adev);
+       if (count > 0) {
+               bus = "i2c";
+       } else {
+               count = acpi_spi_count_resources(adev);
+               if (count > 0)
+                       bus = "spi";
+       }
+
+       fwnode = fwnode_handle_get(acpi_fwnode_handle(adev));
+       acpi_dev_put(adev);
+
+       if (!bus) {
+               codec_err(cdc, "Did not find any buses for %s\n", acpi_ids[i].hid);
+               return;
+       }
+
+       if (!fwnode) {
+               codec_err(cdc, "Could not get fwnode for %s\n", acpi_ids[i].hid);
+               return;
+       }
+
+       /*
+        * When available the cirrus,dev-index property is an accurate
+        * count of the amps in a system and is used in preference to
+        * the count of bus devices that can contain additional address
+        * alias entries.
+        */
+       count_devindex = fwnode_property_count_u32(fwnode, "cirrus,dev-index");
+       if (count_devindex > 0)
+               count = count_devindex;
+
+       match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-%s.%%d", acpi_ids[i].name);
+       if (!match)
+               return;
+       codec_info(cdc, "Found %d %s on %s (%s)\n", count, acpi_ids[i].hid, bus, match);
+       comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count);
+}
+
+static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
+}
+
+static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void cs35l41_fixup_spi_one(struct hda_codec *codec, const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 1);
+}
+
+static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
+}
+
+static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
+                                                int action)
+{
+       comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
+                                                int action)
+{
+       comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2);
+}
+
+static void alc285_fixup_asus_ga403u(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+       /*
+        * The same SSID has been re-used in different hardware, they have
+        * different codecs and the newer GA403U has a ALC285.
+        */
+       if (cdc->core.vendor_id != 0x10ec0285)
+               alc_fixup_inv_dmic(cdc, fix, action);
+}
+
+static void tas2781_fixup_tias_i2c(struct hda_codec *cdc,
+       const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
+}
+
+static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2);
+}
+
+static void tas2781_fixup_txnw_i2c(struct hda_codec *cdc,
+       const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(cdc, action, "i2c", "TXNW2781", "-%s:00-tas2781-hda.%d", 1);
+}
+
+static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
+       const struct hda_fixup *fix, int action)
+{
+       comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1);
+}
+
+static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
+       const struct hda_fixup *fix, int action)
+{
+       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
+}
+
+
+/* for alc295_fixup_hp_top_speakers */
+#include "helpers/hp_x360.c"
+
+/* for alc285_fixup_ideapad_s740_coef() */
+#include "helpers/ideapad_s740.c"
+
+static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
+       WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
+       WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
+       WRITE_COEF(0x37, 0xfe05), WRITE_COEF(0x45, 0x5089),
+       {}
+};
+
+static void alc256_fixup_set_coef_defaults(struct hda_codec *codec,
+                                          const struct hda_fixup *fix,
+                                          int action)
+{
+       /*
+        * A certain other OS sets these coeffs to different values. On at least
+        * one TongFang barebone these settings might survive even a cold
+        * reboot. So to restore a clean slate the values are explicitly reset
+        * to default here. Without this, the external microphone is always in a
+        * plugged-in state, while the internal microphone is always in an
+        * unplugged state, breaking the ability to use the internal microphone.
+        */
+       alc_process_coef_fw(codec, alc256_fixup_set_coef_defaults_coefs);
+}
+
+static const struct coef_fw alc233_fixup_no_audio_jack_coefs[] = {
+       WRITE_COEF(0x1a, 0x9003), WRITE_COEF(0x1b, 0x0e2b), WRITE_COEF(0x37, 0xfe06),
+       WRITE_COEF(0x38, 0x4981), WRITE_COEF(0x45, 0xd489), WRITE_COEF(0x46, 0x0074),
+       WRITE_COEF(0x49, 0x0149),
+       {}
+};
+
+static void alc233_fixup_no_audio_jack(struct hda_codec *codec,
+                                      const struct hda_fixup *fix,
+                                      int action)
+{
+       /*
+        * The audio jack input and output is not detected on the ASRock NUC Box
+        * 1100 series when cold booting without this fix. Warm rebooting from a
+        * certain other OS makes the audio functional, as COEF settings are
+        * preserved in this case. This fix sets these altered COEF values as
+        * the default.
+        */
+       alc_process_coef_fw(codec, alc233_fixup_no_audio_jack_coefs);
+}
+
+static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
+                                                   const struct hda_fixup *fix,
+                                                   int action)
+{
+       /*
+        * The Clevo NJ51CU comes either with the ALC293 or the ALC256 codec,
+        * but uses the 0x8686 subproduct id in both cases. The ALC256 codec
+        * needs an additional quirk for sound working after suspend and resume.
+        */
+       if (codec->core.vendor_id == 0x10ec0256) {
+               alc_update_coef_idx(codec, 0x10, 1<<9, 0);
+               snd_hda_codec_set_pincfg(codec, 0x19, 0x04a11120);
+       } else {
+               snd_hda_codec_set_pincfg(codec, 0x1a, 0x04a1113c);
+       }
+}
+
+static void alc256_decrease_headphone_amp_val(struct hda_codec *codec,
+                                             const struct hda_fixup *fix, int action)
+{
+       u32 caps;
+       u8 nsteps, offs;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       caps = query_amp_caps(codec, 0x3, HDA_OUTPUT);
+       nsteps = ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) - 10;
+       offs = ((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT) - 10;
+       caps &= ~AC_AMPCAP_NUM_STEPS & ~AC_AMPCAP_OFFSET;
+       caps |= (nsteps << AC_AMPCAP_NUM_STEPS_SHIFT) | (offs << AC_AMPCAP_OFFSET_SHIFT);
+
+       if (snd_hda_override_amp_caps(codec, 0x3, HDA_OUTPUT, caps))
+               codec_warn(codec, "failed to override amp caps for NID 0x3\n");
+}
+
+static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec,
+                                                 const struct hda_fixup *fix,
+                                                 int action)
+{
+       struct alc_spec *spec = codec->spec;
+       struct hda_input_mux *imux = &spec->gen.input_mux;
+       int i;
+
+       alc269_fixup_limit_int_mic_boost(codec, fix, action);
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               /**
+                * Set the vref of pin 0x19 (Headset Mic) and pin 0x1b (Headphone Mic)
+                * to Hi-Z to avoid pop noises at startup and when plugging and
+                * unplugging headphones.
+                */
+               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
+               snd_hda_codec_set_pin_target(codec, 0x1b, PIN_VREFHIZ);
+               break;
+       case HDA_FIXUP_ACT_PROBE:
+               /**
+                * Make the internal mic (0x12) the default input source to
+                * prevent pop noises on cold boot.
+                */
+               for (i = 0; i < imux->num_items; i++) {
+                       if (spec->gen.imux_pins[i] == 0x12) {
+                               spec->gen.cur_mux[0] = i;
+                               break;
+                       }
+               }
+               break;
+       }
+}
+
+static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       /*
+        * The Pin Complex 0x17 for the bass speakers is wrongly reported as
+        * unconnected.
+        */
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x17, 0x90170121 },
+               { }
+       };
+       /*
+        * Avoid DAC 0x06 and 0x08, as they have no volume controls.
+        * DAC 0x02 and 0x03 would be fine.
+        */
+       static const hda_nid_t conn[] = { 0x02, 0x03 };
+       /*
+        * Prefer both speakerbar (0x14) and bass speakers (0x17) connected to DAC 0x02.
+        * Headphones (0x21) are connected to DAC 0x03.
+        */
+       static const hda_nid_t preferred_pairs[] = {
+               0x14, 0x02,
+               0x17, 0x02,
+               0x21, 0x03,
+               0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               spec->gen.preferred_dacs = preferred_pairs;
+               break;
+       }
+}
+
+static void alc295_fixup_dell_inspiron_top_speakers(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x14, 0x90170151 },
+               { 0x17, 0x90170150 },
+               { }
+       };
+       static const hda_nid_t conn[] = { 0x02, 0x03 };
+       static const hda_nid_t preferred_pairs[] = {
+               0x14, 0x02,
+               0x17, 0x03,
+               0x21, 0x02,
+               0
+       };
+       struct alc_spec *spec = codec->spec;
+
+       alc_fixup_no_shutup(codec, fix, action);
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               spec->gen.preferred_dacs = preferred_pairs;
+               break;
+       }
+}
+
+/* Forcibly assign NID 0x03 to HP while NID 0x02 to SPK */
+static void alc287_fixup_bind_dacs(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
+       static const hda_nid_t preferred_pairs[] = {
+               0x17, 0x02, 0x21, 0x03, 0
+       };
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+       spec->gen.preferred_dacs = preferred_pairs;
+       spec->gen.auto_mute_via_amp = 1;
+       if (spec->gen.autocfg.speaker_pins[0] != 0x14) {
+               snd_hda_codec_write_cache(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                       0x0); /* Make sure 0x14 was disable */
+       }
+}
+/* Fix none verb table of Headset Mic pin */
+static void alc_fixup_headset_mic(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x19, 0x03a1103c },
+               { }
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               break;
+       }
+}
+
+static void alc245_fixup_hp_spectre_x360_eu0xxx(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       /*
+        * The Pin Complex 0x14 for the treble speakers is wrongly reported as
+        * unconnected.
+        * The Pin Complex 0x17 for the bass speakers has the lowest association
+        * and sequence values so shift it up a bit to squeeze 0x14 in.
+        */
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x14, 0x90170110 }, // top/treble
+               { 0x17, 0x90170111 }, // bottom/bass
+               { }
+       };
+
+       /*
+        * Force DAC 0x02 for the bass speakers 0x17.
+        */
+       static const hda_nid_t conn[] = { 0x02 };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               break;
+       }
+
+       cs35l41_fixup_i2c_two(codec, fix, action);
+       alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc245_fixup_hp_gpio_led(codec, fix, action);
+}
+
+/* some changes for Spectre x360 16, 2024 model */
+static void alc245_fixup_hp_spectre_x360_16_aa0xxx(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       /*
+        * The Pin Complex 0x14 for the treble speakers is wrongly reported as
+        * unconnected.
+        * The Pin Complex 0x17 for the bass speakers has the lowest association
+        * and sequence values so shift it up a bit to squeeze 0x14 in.
+        */
+       struct alc_spec *spec = codec->spec;
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x14, 0x90170110 }, // top/treble
+               { 0x17, 0x90170111 }, // bottom/bass
+               { }
+       };
+
+       /*
+        * Force DAC 0x02 for the bass speakers 0x17.
+        */
+       static const hda_nid_t conn[] = { 0x02 };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               /* needed for amp of back speakers */
+               spec->gpio_mask |= 0x01;
+               spec->gpio_dir |= 0x01;
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* need to toggle GPIO to enable the amp of back speakers */
+               alc_update_gpio_data(codec, 0x01, true);
+               msleep(100);
+               alc_update_gpio_data(codec, 0x01, false);
+               break;
+       }
+
+       cs35l41_fixup_i2c_two(codec, fix, action);
+       alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc245_fixup_hp_gpio_led(codec, fix, action);
+}
+
+static void alc245_fixup_hp_zbook_firefly_g12a(struct hda_codec *codec,
+                                         const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const hda_nid_t conn[] = { 0x02 };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->gen.auto_mute_via_amp = 1;
+               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
+               break;
+       }
+
+       cs35l41_fixup_i2c_two(codec, fix, action);
+       alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
+       alc285_fixup_hp_coef_micmute_led(codec, fix, action);
+}
+
+/*
+ * ALC287 PCM hooks
+ */
+static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream,
+                                  int action)
+{
+       switch (action) {
+       case HDA_GEN_PCM_ACT_OPEN:
+               alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */
+               break;
+       case HDA_GEN_PCM_ACT_CLOSE:
+               alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
+               break;
+       }
+}
+
+static void alc287_s4_power_gpio3_default(struct hda_codec *codec)
+{
+       if (is_s4_suspend(codec)) {
+               alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
+       }
+}
+
+static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       static const struct coef_fw coefs[] = {
+               WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC300),
+               WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023),
+               WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301),
+               WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023),
+       };
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11);
+       alc_process_coef_fw(codec, coefs);
+       spec->power_hook = alc287_s4_power_gpio3_default;
+       spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
+}
+
+/*
+ * Clear COEF 0x0d (PCBEEP passthrough) bit 0x40 where BIOS sets it wrongly
+ * at PM resume
+ */
+static void alc283_fixup_dell_hp_resume(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc_write_coef_idx(codec, 0xd, 0x2800);
+}
+
+enum {
+       ALC269_FIXUP_GPIO2,
+       ALC269_FIXUP_SONY_VAIO,
+       ALC275_FIXUP_SONY_VAIO_GPIO2,
+       ALC269_FIXUP_DELL_M101Z,
+       ALC269_FIXUP_SKU_IGNORE,
+       ALC269_FIXUP_ASUS_G73JW,
+       ALC269_FIXUP_ASUS_N7601ZM_PINS,
+       ALC269_FIXUP_ASUS_N7601ZM,
+       ALC269_FIXUP_LENOVO_EAPD,
+       ALC275_FIXUP_SONY_HWEQ,
+       ALC275_FIXUP_SONY_DISABLE_AAMIX,
+       ALC271_FIXUP_DMIC,
+       ALC269_FIXUP_PCM_44K,
+       ALC269_FIXUP_STEREO_DMIC,
+       ALC269_FIXUP_HEADSET_MIC,
+       ALC269_FIXUP_QUANTA_MUTE,
+       ALC269_FIXUP_LIFEBOOK,
+       ALC269_FIXUP_LIFEBOOK_EXTMIC,
+       ALC269_FIXUP_LIFEBOOK_HP_PIN,
+       ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT,
+       ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC,
+       ALC269_FIXUP_AMIC,
+       ALC269_FIXUP_DMIC,
+       ALC269VB_FIXUP_AMIC,
+       ALC269VB_FIXUP_DMIC,
+       ALC269_FIXUP_HP_MUTE_LED,
+       ALC269_FIXUP_HP_MUTE_LED_MIC1,
+       ALC269_FIXUP_HP_MUTE_LED_MIC2,
+       ALC269_FIXUP_HP_MUTE_LED_MIC3,
+       ALC269_FIXUP_HP_GPIO_LED,
+       ALC269_FIXUP_HP_GPIO_MIC1_LED,
+       ALC269_FIXUP_HP_LINE1_MIC1_LED,
+       ALC269_FIXUP_INV_DMIC,
+       ALC269_FIXUP_LENOVO_DOCK,
+       ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST,
+       ALC269_FIXUP_NO_SHUTUP,
+       ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
+       ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
+       ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
+       ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+       ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+       ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+       ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET,
+       ALC269_FIXUP_HEADSET_MODE,
+       ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
+       ALC269_FIXUP_ASPIRE_HEADSET_MIC,
+       ALC269_FIXUP_ASUS_X101_FUNC,
+       ALC269_FIXUP_ASUS_X101_VERB,
+       ALC269_FIXUP_ASUS_X101,
+       ALC271_FIXUP_AMIC_MIC2,
+       ALC271_FIXUP_HP_GATE_MIC_JACK,
+       ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572,
+       ALC269_FIXUP_ACER_AC700,
+       ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
+       ALC269VB_FIXUP_ASUS_ZENBOOK,
+       ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A,
+       ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE,
+       ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED,
+       ALC269VB_FIXUP_ORDISSIMO_EVE2,
+       ALC283_FIXUP_CHROME_BOOK,
+       ALC283_FIXUP_SENSE_COMBO_JACK,
+       ALC282_FIXUP_ASUS_TX300,
+       ALC283_FIXUP_INT_MIC,
+       ALC290_FIXUP_MONO_SPEAKERS,
+       ALC290_FIXUP_MONO_SPEAKERS_HSJACK,
+       ALC290_FIXUP_SUBWOOFER,
+       ALC290_FIXUP_SUBWOOFER_HSJACK,
+       ALC295_FIXUP_HP_MUTE_LED_COEFBIT11,
+       ALC269_FIXUP_THINKPAD_ACPI,
+       ALC269_FIXUP_LENOVO_XPAD_ACPI,
+       ALC269_FIXUP_DMIC_THINKPAD_ACPI,
+       ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13,
+       ALC269VC_FIXUP_INFINIX_Y4_MAX,
+       ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO,
+       ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+       ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
+       ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
+       ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
+       ALC255_FIXUP_HEADSET_MODE,
+       ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
+       ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC292_FIXUP_TPT440_DOCK,
+       ALC292_FIXUP_TPT440,
+       ALC283_FIXUP_HEADSET_MIC,
+       ALC255_FIXUP_MIC_MUTE_LED,
+       ALC282_FIXUP_ASPIRE_V5_PINS,
+       ALC269VB_FIXUP_ASPIRE_E1_COEF,
+       ALC280_FIXUP_HP_GPIO4,
+       ALC286_FIXUP_HP_GPIO_LED,
+       ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
+       ALC280_FIXUP_HP_DOCK_PINS,
+       ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED,
+       ALC280_FIXUP_HP_9480M,
+       ALC245_FIXUP_HP_X360_AMP,
+       ALC285_FIXUP_HP_SPECTRE_X360_EB1,
+       ALC285_FIXUP_HP_SPECTRE_X360_DF1,
+       ALC285_FIXUP_HP_ENVY_X360,
+       ALC288_FIXUP_DELL_HEADSET_MODE,
+       ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC288_FIXUP_DELL_XPS_13,
+       ALC288_FIXUP_DISABLE_AAMIX,
+       ALC292_FIXUP_DELL_E7X_AAMIX,
+       ALC292_FIXUP_DELL_E7X,
+       ALC292_FIXUP_DISABLE_AAMIX,
+       ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK,
+       ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE,
+       ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
+       ALC275_FIXUP_DELL_XPS,
+       ALC293_FIXUP_LENOVO_SPK_NOISE,
+       ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
+       ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED,
+       ALC255_FIXUP_DELL_SPK_NOISE,
+       ALC225_FIXUP_DISABLE_MIC_VREF,
+       ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+       ALC295_FIXUP_DISABLE_DAC3,
+       ALC285_FIXUP_SPEAKER2_TO_DAC1,
+       ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1,
+       ALC285_FIXUP_ASUS_HEADSET_MIC,
+       ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS,
+       ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1,
+       ALC285_FIXUP_ASUS_I2C_HEADSET_MIC,
+       ALC280_FIXUP_HP_HEADSET_MIC,
+       ALC221_FIXUP_HP_FRONT_MIC,
+       ALC292_FIXUP_TPT460,
+       ALC298_FIXUP_SPK_VOLUME,
+       ALC298_FIXUP_LENOVO_SPK_VOLUME,
+       ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
+       ALC269_FIXUP_ATIV_BOOK_8,
+       ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE,
+       ALC221_FIXUP_HP_MIC_NO_PRESENCE,
+       ALC256_FIXUP_ASUS_HEADSET_MODE,
+       ALC256_FIXUP_ASUS_MIC,
+       ALC256_FIXUP_ASUS_AIO_GPIO2,
+       ALC233_FIXUP_ASUS_MIC_NO_PRESENCE,
+       ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE,
+       ALC233_FIXUP_LENOVO_MULTI_CODECS,
+       ALC233_FIXUP_ACER_HEADSET_MIC,
+       ALC294_FIXUP_LENOVO_MIC_LOCATION,
+       ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE,
+       ALC225_FIXUP_S3_POP_NOISE,
+       ALC700_FIXUP_INTEL_REFERENCE,
+       ALC274_FIXUP_DELL_BIND_DACS,
+       ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,
+       ALC298_FIXUP_TPT470_DOCK_FIX,
+       ALC298_FIXUP_TPT470_DOCK,
+       ALC255_FIXUP_DUMMY_LINEOUT_VERB,
+       ALC255_FIXUP_DELL_HEADSET_MIC,
+       ALC256_FIXUP_HUAWEI_MACH_WX9_PINS,
+       ALC298_FIXUP_HUAWEI_MBX_STEREO,
+       ALC295_FIXUP_HP_X360,
+       ALC221_FIXUP_HP_HEADSET_MIC,
+       ALC285_FIXUP_LENOVO_HEADPHONE_NOISE,
+       ALC295_FIXUP_HP_AUTO_MUTE,
+       ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE,
+       ALC294_FIXUP_ASUS_MIC,
+       ALC294_FIXUP_ASUS_HEADSET_MIC,
+       ALC294_FIXUP_ASUS_SPK,
+       ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
+       ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE,
+       ALC255_FIXUP_ACER_HEADSET_MIC,
+       ALC295_FIXUP_CHROME_BOOK,
+       ALC225_FIXUP_HEADSET_JACK,
+       ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE,
+       ALC225_FIXUP_WYSE_AUTO_MUTE,
+       ALC225_FIXUP_WYSE_DISABLE_MIC_VREF,
+       ALC286_FIXUP_ACER_AIO_HEADSET_MIC,
+       ALC256_FIXUP_ASUS_HEADSET_MIC,
+       ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
+       ALC255_FIXUP_PREDATOR_SUBWOOFER,
+       ALC299_FIXUP_PREDATOR_SPK,
+       ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE,
+       ALC289_FIXUP_DELL_SPK1,
+       ALC289_FIXUP_DELL_SPK2,
+       ALC289_FIXUP_DUAL_SPK,
+       ALC289_FIXUP_RTK_AMP_DUAL_SPK,
+       ALC294_FIXUP_SPK2_TO_DAC1,
+       ALC294_FIXUP_ASUS_DUAL_SPK,
+       ALC285_FIXUP_THINKPAD_X1_GEN7,
+       ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+       ALC294_FIXUP_ASUS_ALLY,
+       ALC294_FIXUP_ASUS_ALLY_PINS,
+       ALC294_FIXUP_ASUS_ALLY_VERBS,
+       ALC294_FIXUP_ASUS_ALLY_SPEAKER,
+       ALC294_FIXUP_ASUS_HPE,
+       ALC294_FIXUP_ASUS_COEF_1B,
+       ALC294_FIXUP_ASUS_GX502_HP,
+       ALC294_FIXUP_ASUS_GX502_PINS,
+       ALC294_FIXUP_ASUS_GX502_VERBS,
+       ALC294_FIXUP_ASUS_GU502_HP,
+       ALC294_FIXUP_ASUS_GU502_PINS,
+       ALC294_FIXUP_ASUS_GU502_VERBS,
+       ALC294_FIXUP_ASUS_G513_PINS,
+       ALC285_FIXUP_ASUS_G533Z_PINS,
+       ALC285_FIXUP_HP_GPIO_LED,
+       ALC285_FIXUP_HP_MUTE_LED,
+       ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
+       ALC285_FIXUP_HP_BEEP_MICMUTE_LED,
+       ALC236_FIXUP_HP_MUTE_LED_COEFBIT2,
+       ALC236_FIXUP_HP_GPIO_LED,
+       ALC236_FIXUP_HP_MUTE_LED,
+       ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
+       ALC236_FIXUP_LENOVO_INV_DMIC,
+       ALC298_FIXUP_SAMSUNG_AMP,
+       ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS,
+       ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS,
+       ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
+       ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
+       ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
+       ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS,
+       ALC269VC_FIXUP_ACER_HEADSET_MIC,
+       ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE,
+       ALC289_FIXUP_ASUS_GA401,
+       ALC289_FIXUP_ASUS_GA502,
+       ALC256_FIXUP_ACER_MIC_NO_PRESENCE,
+       ALC285_FIXUP_HP_GPIO_AMP_INIT,
+       ALC269_FIXUP_CZC_B20,
+       ALC269_FIXUP_CZC_TMI,
+       ALC269_FIXUP_CZC_L101,
+       ALC269_FIXUP_LEMOTE_A1802,
+       ALC269_FIXUP_LEMOTE_A190X,
+       ALC256_FIXUP_INTEL_NUC8_RUGGED,
+       ALC233_FIXUP_INTEL_NUC8_DMIC,
+       ALC233_FIXUP_INTEL_NUC8_BOOST,
+       ALC256_FIXUP_INTEL_NUC10,
+       ALC255_FIXUP_XIAOMI_HEADSET_MIC,
+       ALC274_FIXUP_HP_MIC,
+       ALC274_FIXUP_HP_HEADSET_MIC,
+       ALC274_FIXUP_HP_ENVY_GPIO,
+       ALC274_FIXUP_ASUS_ZEN_AIO_27,
+       ALC256_FIXUP_ASUS_HPE,
+       ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
+       ALC287_FIXUP_HP_GPIO_LED,
+       ALC256_FIXUP_HP_HEADSET_MIC,
+       ALC245_FIXUP_HP_GPIO_LED,
+       ALC236_FIXUP_DELL_AIO_HEADSET_MIC,
+       ALC282_FIXUP_ACER_DISABLE_LINEOUT,
+       ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST,
+       ALC256_FIXUP_ACER_HEADSET_MIC,
+       ALC285_FIXUP_IDEAPAD_S740_COEF,
+       ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST,
+       ALC295_FIXUP_ASUS_DACS,
+       ALC295_FIXUP_HP_OMEN,
+       ALC285_FIXUP_HP_SPECTRE_X360,
+       ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP,
+       ALC623_FIXUP_LENOVO_THINKSTATION_P340,
+       ALC255_FIXUP_ACER_HEADPHONE_AND_MIC,
+       ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST,
+       ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS,
+       ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
+       ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
+       ALC298_FIXUP_LENOVO_C940_DUET7,
+       ALC287_FIXUP_13S_GEN2_SPEAKERS,
+       ALC256_FIXUP_SET_COEF_DEFAULTS,
+       ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
+       ALC233_FIXUP_NO_AUDIO_JACK,
+       ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME,
+       ALC285_FIXUP_LEGION_Y9000X_SPEAKERS,
+       ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE,
+       ALC287_FIXUP_LEGION_16ACHG6,
+       ALC287_FIXUP_CS35L41_I2C_2,
+       ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED,
+       ALC287_FIXUP_CS35L41_I2C_4,
+       ALC245_FIXUP_CS35L41_SPI_1,
+       ALC245_FIXUP_CS35L41_SPI_2,
+       ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED,
+       ALC245_FIXUP_CS35L41_SPI_4,
+       ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED,
+       ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED,
+       ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE,
+       ALC287_FIXUP_LEGION_16ITHG6,
+       ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
+       ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
+       ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN,
+       ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS,
+       ALC236_FIXUP_DELL_DUAL_CODECS,
+       ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
+       ALC287_FIXUP_TAS2781_I2C,
+       ALC245_FIXUP_TAS2781_SPI_2,
+       ALC287_FIXUP_TXNW2781_I2C,
+       ALC287_FIXUP_YOGA7_14ARB7_I2C,
+       ALC245_FIXUP_HP_MUTE_LED_COEFBIT,
+       ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT,
+       ALC245_FIXUP_HP_X360_MUTE_LEDS,
+       ALC287_FIXUP_THINKPAD_I2S_SPK,
+       ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD,
+       ALC2XX_FIXUP_HEADSET_MIC,
+       ALC289_FIXUP_DELL_CS35L41_SPI_2,
+       ALC294_FIXUP_CS35L41_I2C_2,
+       ALC256_FIXUP_ACER_SFG16_MICMUTE_LED,
+       ALC256_FIXUP_HEADPHONE_AMP_VOL,
+       ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX,
+       ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX,
+       ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A,
+       ALC285_FIXUP_ASUS_GA403U,
+       ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC,
+       ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1,
+       ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC,
+       ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1,
+       ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318,
+       ALC256_FIXUP_CHROME_BOOK,
+       ALC245_FIXUP_CLEVO_NOISY_MIC,
+       ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
+       ALC233_FIXUP_MEDION_MTL_SPK,
+       ALC294_FIXUP_BASS_SPEAKER_15,
+       ALC283_FIXUP_DELL_HP_RESUME,
+       ALC294_FIXUP_ASUS_CS35L41_SPI_2,
+       ALC274_FIXUP_HP_AIO_BIND_DACS,
+       ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2,
+       ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC,
+       ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1,
+       ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
+};
+
+/* A special fixup for Lenovo C940 and Yoga Duet 7;
+ * both have the very same PCI SSID, and we need to apply different fixups
+ * depending on the codec ID
+ */
+static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec,
+                                          const struct hda_fixup *fix,
+                                          int action)
+{
+       int id;
+
+       if (codec->core.vendor_id == 0x10ec0298)
+               id = ALC298_FIXUP_LENOVO_SPK_VOLUME; /* C940 */
+       else
+               id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* Duet 7 */
+       __snd_hda_apply_fixup(codec, id, action, 0);
+}
+
+static const struct hda_fixup alc269_fixups[] = {
+       [ALC269_FIXUP_GPIO2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_gpio2,
+       },
+       [ALC269_FIXUP_SONY_VAIO] = {
+               .type = HDA_FIXUP_PINCTLS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       {0x19, PIN_VREFGRD},
+                       {}
+               }
+       },
+       [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc275_fixup_gpio4_off,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_SONY_VAIO
+       },
+       [ALC269_FIXUP_DELL_M101Z] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Enables internal speaker */
+                       {0x20, AC_VERB_SET_COEF_INDEX, 13},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
+                       {}
+               }
+       },
+       [ALC269_FIXUP_SKU_IGNORE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_sku_ignore,
+       },
+       [ALC269_FIXUP_ASUS_G73JW] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x17, 0x99130111 }, /* subwoofer */
+                       { }
+               }
+       },
+       [ALC269_FIXUP_ASUS_N7601ZM_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03A11050 },
+                       { 0x1a, 0x03A11C30 },
+                       { 0x21, 0x03211420 },
+                       { }
+               }
+       },
+       [ALC269_FIXUP_ASUS_N7601ZM] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x62},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0xa007},
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x10},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x8420},
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x0f},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x7774},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_ASUS_N7601ZM_PINS,
+       },
+       [ALC269_FIXUP_LENOVO_EAPD] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+                       {}
+               }
+       },
+       [ALC275_FIXUP_SONY_HWEQ] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hweq,
+               .chained = true,
+               .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
+       },
+       [ALC275_FIXUP_SONY_DISABLE_AAMIX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_SONY_VAIO
+       },
+       [ALC271_FIXUP_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc271_fixup_dmic,
+       },
+       [ALC269_FIXUP_PCM_44K] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_pcm_44k,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_QUANTA_MUTE
+       },
+       [ALC269_FIXUP_STEREO_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_stereo_dmic,
+       },
+       [ALC269_FIXUP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_headset_mic,
+       },
+       [ALC269_FIXUP_QUANTA_MUTE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_quanta_mute,
+       },
+       [ALC269_FIXUP_LIFEBOOK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x2101103f }, /* dock line-out */
+                       { 0x1b, 0x23a11040 }, /* dock mic-in */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_QUANTA_MUTE
+       },
+       [ALC269_FIXUP_LIFEBOOK_EXTMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1903c }, /* headset mic, with jack detect */
+                       { }
+               },
+       },
+       [ALC269_FIXUP_LIFEBOOK_HP_PIN] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x21, 0x0221102f }, /* HP out */
+                       { }
+               },
+       },
+       [ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
+       },
+       [ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_pincfg_U7x7_headset_mic,
+       },
+       [ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x90170151 }, /* use as internal speaker (LFE) */
+                       { 0x1b, 0x90170152 }, /* use as internal speaker (back) */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+       },
+       [ALC269VC_FIXUP_INFINIX_Y4_MAX] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170150 }, /* use as internal speaker */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+       },
+       [ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x03a19020 }, /* headset mic */
+                       { 0x1b, 0x90170150 }, /* speaker */
+                       { }
+               },
+       },
+       [ALC269_FIXUP_AMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0121401f }, /* HP out */
+                       { 0x18, 0x01a19c20 }, /* mic */
+                       { 0x19, 0x99a3092f }, /* int-mic */
+                       { }
+               },
+       },
+       [ALC269_FIXUP_DMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x99a3092f }, /* int-mic */
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0121401f }, /* HP out */
+                       { 0x18, 0x01a19c20 }, /* mic */
+                       { }
+               },
+       },
+       [ALC269VB_FIXUP_AMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x18, 0x01a19c20 }, /* mic */
+                       { 0x19, 0x99a3092f }, /* int-mic */
+                       { 0x21, 0x0121401f }, /* HP out */
+                       { }
+               },
+       },
+       [ALC269VB_FIXUP_DMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x99a3092f }, /* int-mic */
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x18, 0x01a19c20 }, /* mic */
+                       { 0x21, 0x0121401f }, /* HP out */
+                       { }
+               },
+       },
+       [ALC269_FIXUP_HP_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hp_mute_led,
+       },
+       [ALC269_FIXUP_HP_MUTE_LED_MIC1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hp_mute_led_mic1,
+       },
+       [ALC269_FIXUP_HP_MUTE_LED_MIC2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hp_mute_led_mic2,
+       },
+       [ALC269_FIXUP_HP_MUTE_LED_MIC3] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hp_mute_led_mic3,
+               .chained = true,
+               .chain_id = ALC295_FIXUP_HP_AUTO_MUTE
+       },
+       [ALC269_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hp_gpio_led,
+       },
+       [ALC269_FIXUP_HP_GPIO_MIC1_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hp_gpio_mic1_led,
+       },
+       [ALC269_FIXUP_HP_LINE1_MIC1_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_hp_line1_mic1_led,
+       },
+       [ALC269_FIXUP_INV_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_inv_dmic,
+       },
+       [ALC269_FIXUP_NO_SHUTUP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_shutup,
+       },
+       [ALC269_FIXUP_LENOVO_DOCK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x23a11040 }, /* dock mic */
+                       { 0x1b, 0x2121103f }, /* dock headphone */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT
+       },
+       [ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_LENOVO_DOCK,
+       },
+       [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+       },
+       [ALC269_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC269_FIXUP_DELL2_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x21014020 }, /* dock line out */
+                       { 0x19, 0x21a19030 }, /* dock mic */
+                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC269_FIXUP_DELL3_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC269_FIXUP_DELL4_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1b, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC269_FIXUP_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
+       },
+       [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_no_hp_mic,
+       },
+       [ALC269_FIXUP_ASPIRE_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* headset mic w/o jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE,
+       },
+       [ALC286_FIXUP_SONY_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC256_FIXUP_HUAWEI_MACH_WX9_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       {0x12, 0x90a60130},
+                       {0x13, 0x40000000},
+                       {0x14, 0x90170110},
+                       {0x18, 0x411111f0},
+                       {0x19, 0x04a11040},
+                       {0x1a, 0x411111f0},
+                       {0x1b, 0x90170112},
+                       {0x1d, 0x40759a05},
+                       {0x1e, 0x411111f0},
+                       {0x21, 0x04211020},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
+       },
+       [ALC298_FIXUP_HUAWEI_MBX_STEREO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_huawei_mbx_stereo,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
+       },
+       [ALC269_FIXUP_ASUS_X101_FUNC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_x101_headset_mic,
+       },
+       [ALC269_FIXUP_ASUS_X101_VERB] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
+                       {0x20, AC_VERB_SET_PROC_COEF,  0x0310},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_ASUS_X101_FUNC
+       },
+       [ALC269_FIXUP_ASUS_X101] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x04a1182c }, /* Headset mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_ASUS_X101_VERB
+       },
+       [ALC271_FIXUP_AMIC_MIC2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x19, 0x01a19c20 }, /* mic */
+                       { 0x1b, 0x99a7012f }, /* int-mic */
+                       { 0x21, 0x0121401f }, /* HP out */
+                       { }
+               },
+       },
+       [ALC271_FIXUP_HP_GATE_MIC_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc271_hp_gate_mic_jack,
+               .chained = true,
+               .chain_id = ALC271_FIXUP_AMIC_MIC2,
+       },
+       [ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC271_FIXUP_HP_GATE_MIC_JACK,
+       },
+       [ALC269_FIXUP_ACER_AC700] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x99a3092f }, /* int-mic */
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x18, 0x03a11c20 }, /* mic */
+                       { 0x1e, 0x0346101e }, /* SPDIF1 */
+                       { 0x21, 0x0321101f }, /* HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC271_FIXUP_DMIC,
+       },
+       [ALC269_FIXUP_LIMIT_INT_MIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+       },
+       [ALC269VB_FIXUP_ASUS_ZENBOOK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC269VB_FIXUP_DMIC,
+       },
+       [ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* class-D output amp +5dB */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x12 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2800 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC269VB_FIXUP_ASUS_ZENBOOK,
+       },
+       [ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a110f0 },  /* use as headset mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HP_MUTE_LED_MIC1,
+       },
+       [ALC269VB_FIXUP_ORDISSIMO_EVE2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x99a3092f }, /* int-mic */
+                       { 0x18, 0x03a11d20 }, /* mic */
+                       { 0x19, 0x411111f0 }, /* Unused bogus pin */
+                       { }
+               },
+       },
+       [ALC283_FIXUP_CHROME_BOOK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc283_fixup_chromebook,
+       },
+       [ALC283_FIXUP_SENSE_COMBO_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc283_fixup_sense_combo_jack,
+               .chained = true,
+               .chain_id = ALC283_FIXUP_CHROME_BOOK,
+       },
+       [ALC282_FIXUP_ASUS_TX300] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc282_fixup_asus_tx300,
+       },
+       [ALC283_FIXUP_INT_MIC] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x1a},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x0011},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+       },
+       [ALC290_FIXUP_SUBWOOFER_HSJACK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x17, 0x90170112 }, /* subwoofer */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK,
+       },
+       [ALC290_FIXUP_SUBWOOFER] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x17, 0x90170112 }, /* subwoofer */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC290_FIXUP_MONO_SPEAKERS,
+       },
+       [ALC290_FIXUP_MONO_SPEAKERS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc290_fixup_mono_speakers,
+       },
+       [ALC290_FIXUP_MONO_SPEAKERS_HSJACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc290_fixup_mono_speakers,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+       },
+       [ALC269_FIXUP_THINKPAD_ACPI] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_thinkpad_acpi,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_SKU_IGNORE,
+       },
+       [ALC269_FIXUP_LENOVO_XPAD_ACPI] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_ideapad_acpi,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+       },
+       [ALC269_FIXUP_DMIC_THINKPAD_ACPI] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_inv_dmic,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+       },
+       [ALC255_FIXUP_ACER_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_HEADSET_MODE
+       },
+       [ALC255_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_HEADSET_MODE
+       },
+       [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_HEADSET_MODE
+       },
+       [ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC255_FIXUP_DELL2_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC255_FIXUP_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_alc255,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
+       },
+       [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_alc255_no_hp_mic,
+       },
+       [ALC293_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC292_FIXUP_TPT440_DOCK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_tpt440_dock,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+       },
+       [ALC292_FIXUP_TPT440] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC292_FIXUP_TPT440_DOCK,
+       },
+       [ALC283_FIXUP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x04a110f0 },
+                       { },
+               },
+       },
+       [ALC255_FIXUP_MIC_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_micmute_led,
+       },
+       [ALC282_FIXUP_ASPIRE_V5_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x90a60130 },
+                       { 0x14, 0x90170110 },
+                       { 0x17, 0x40000008 },
+                       { 0x18, 0x411111f0 },
+                       { 0x19, 0x01a1913c },
+                       { 0x1a, 0x411111f0 },
+                       { 0x1b, 0x411111f0 },
+                       { 0x1d, 0x40f89b2d },
+                       { 0x1e, 0x411111f0 },
+                       { 0x21, 0x0321101f },
+                       { },
+               },
+       },
+       [ALC269VB_FIXUP_ASPIRE_E1_COEF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269vb_fixup_aspire_e1_coef,
+       },
+       [ALC280_FIXUP_HP_GPIO4] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc280_fixup_hp_gpio4,
+       },
+       [ALC286_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc286_fixup_hp_gpio_led,
+       },
+       [ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc280_fixup_hp_gpio2_mic_hotkey,
+       },
+       [ALC280_FIXUP_HP_DOCK_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x21011020 }, /* line-out */
+                       { 0x1a, 0x01a1903c }, /* headset mic */
+                       { 0x18, 0x2181103f }, /* line-in */
+                       { },
+               },
+               .chained = true,
+               .chain_id = ALC280_FIXUP_HP_GPIO4
+       },
+       [ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x21011020 }, /* line-out */
+                       { 0x18, 0x2181103f }, /* line-in */
+                       { },
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HP_GPIO_MIC1_LED
+       },
+       [ALC280_FIXUP_HP_9480M] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc280_fixup_hp_9480m,
+       },
+       [ALC245_FIXUP_HP_X360_AMP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_x360_amp,
+               .chained = true,
+               .chain_id = ALC245_FIXUP_HP_GPIO_LED
+       },
+       [ALC288_FIXUP_DELL_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_dell_alc288,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
+       },
+       [ALC288_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC288_FIXUP_DELL_HEADSET_MODE
+       },
+       [ALC288_FIXUP_DISABLE_AAMIX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC288_FIXUP_DELL_XPS_13] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_dell_xps13,
+               .chained = true,
+               .chain_id = ALC288_FIXUP_DISABLE_AAMIX
+       },
+       [ALC292_FIXUP_DISABLE_AAMIX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE
+       },
+       [ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC292_FIXUP_DELL_E7X_AAMIX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_dell_xps13,
+               .chained = true,
+               .chain_id = ALC292_FIXUP_DISABLE_AAMIX
+       },
+       [ALC292_FIXUP_DELL_E7X] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_micmute_led,
+               /* micmute fixup must be applied at last */
+               .chained_before = true,
+               .chain_id = ALC292_FIXUP_DELL_E7X_AAMIX,
+       },
+       [ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* headset mic w/o jack detect */
+                       { }
+               },
+               .chained_before = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE,
+       },
+       [ALC298_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC275_FIXUP_DELL_XPS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Enables internal speaker */
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x1f},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x00c0},
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x30},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x00b1},
+                       {}
+               }
+       },
+       [ALC293_FIXUP_LENOVO_SPK_NOISE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+       },
+       [ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc233_fixup_lenovo_line2_mic_hotkey,
+       },
+       [ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc233_fixup_lenovo_low_en_micmute_led,
+       },
+       [ALC233_FIXUP_INTEL_NUC8_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_inv_dmic,
+               .chained = true,
+               .chain_id = ALC233_FIXUP_INTEL_NUC8_BOOST,
+       },
+       [ALC233_FIXUP_INTEL_NUC8_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost
+       },
+       [ALC255_FIXUP_DELL_SPK_NOISE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC225_FIXUP_DISABLE_MIC_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_mic_vref,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC225_FIXUP_DELL1_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Disable pass-through path for FRONT 14h */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x36 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x57d7 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC225_FIXUP_DISABLE_MIC_VREF
+       },
+       [ALC280_FIXUP_HP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC,
+       },
+       [ALC221_FIXUP_HP_FRONT_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x02a19020 }, /* Front Mic */
+                       { }
+               },
+       },
+       [ALC292_FIXUP_TPT460] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_tpt440_dock,
+               .chained = true,
+               .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE,
+       },
+       [ALC298_FIXUP_SPK_VOLUME] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_speaker_volume,
+               .chained = true,
+               .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
+       },
+       [ALC298_FIXUP_LENOVO_SPK_VOLUME] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_speaker_volume,
+       },
+       [ALC295_FIXUP_DISABLE_DAC3] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc295_fixup_disable_dac3,
+       },
+       [ALC285_FIXUP_SPEAKER2_TO_DAC1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+       },
+       [ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC245_FIXUP_CS35L41_SPI_2
+       },
+       [ALC285_FIXUP_ASUS_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 },
+                       { 0x1b, 0x03a11c30 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1
+       },
+       [ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x90170120 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC285_FIXUP_ASUS_HEADSET_MIC
+       },
+       [ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC287_FIXUP_CS35L41_I2C_2
+       },
+       [ALC285_FIXUP_ASUS_I2C_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 },
+                       { 0x1b, 0x03a11c30 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1
+       },
+       [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170151 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC269_FIXUP_ATIV_BOOK_8] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_auto_mute_via_amp,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_NO_SHUTUP
+       },
+       [ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01813030 }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC256_FIXUP_ASUS_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode,
+       },
+       [ALC256_FIXUP_ASUS_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x13, 0x90a60160 }, /* use as internal mic */
+                       { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
+       },
+       [ALC256_FIXUP_ASUS_AIO_GPIO2] = {
+               .type = HDA_FIXUP_FUNC,
+               /* Set up GPIO2 for the speaker amp */
+               .v.func = alc_fixup_gpio4,
+       },
+       [ALC233_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Enables internal speaker */
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x40},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x8800},
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE
+       },
+       [ALC233_FIXUP_LENOVO_MULTI_CODECS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_GPIO2
+       },
+       [ALC233_FIXUP_ACER_HEADSET_MIC] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE
+       },
+       [ALC294_FIXUP_LENOVO_MIC_LOCATION] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* Change the mic location from front to right, otherwise there are
+                          two front mics with the same name, pulseaudio can't handle them.
+                          This is just a temporary workaround, after applying this fixup,
+                          there will be one "Front Mic" and one "Mic" in this machine.
+                        */
+                       { 0x1a, 0x04a19040 },
+                       { }
+               },
+       },
+       [ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x0101102f }, /* Rear Headset HP */
+                       { 0x19, 0x02a1913c }, /* use as Front headset mic, without its own jack detect */
+                       { 0x1a, 0x01a19030 }, /* Rear Headset MIC */
+                       { 0x1b, 0x02011020 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC225_FIXUP_S3_POP_NOISE
+       },
+       [ALC225_FIXUP_S3_POP_NOISE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc225_fixup_s3_pop_noise,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC700_FIXUP_INTEL_REFERENCE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Enables internal speaker */
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x45},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x5289},
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x4A},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x001b},
+                       {0x58, AC_VERB_SET_COEF_INDEX, 0x00},
+                       {0x58, AC_VERB_SET_PROC_COEF, 0x3888},
+                       {0x20, AC_VERB_SET_COEF_INDEX, 0x6f},
+                       {0x20, AC_VERB_SET_PROC_COEF, 0x2c0b},
+                       {}
+               }
+       },
+       [ALC274_FIXUP_DELL_BIND_DACS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc274_fixup_bind_dacs,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC274_FIXUP_DELL_AIO_LINEOUT_VERB] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x0401102f },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC274_FIXUP_DELL_BIND_DACS
+       },
+       [ALC298_FIXUP_TPT470_DOCK_FIX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_tpt470_dock,
+               .chained = true,
+               .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE
+       },
+       [ALC298_FIXUP_TPT470_DOCK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_tpt470_dacs,
+               .chained = true,
+               .chain_id = ALC298_FIXUP_TPT470_DOCK_FIX
+       },
+       [ALC255_FIXUP_DUMMY_LINEOUT_VERB] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x0201101f },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC255_FIXUP_DELL_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC295_FIXUP_HP_X360] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc295_fixup_hp_top_speakers,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HP_MUTE_LED_MIC3
+       },
+       [ALC221_FIXUP_HP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x0181313f},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC285_FIXUP_LENOVO_HEADPHONE_NOISE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_invalidate_dacs,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+       },
+       [ALC295_FIXUP_HP_AUTO_MUTE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_auto_mute_via_amp,
+       },
+       [ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC294_FIXUP_ASUS_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x13, 0x90a60160 }, /* use as internal mic */
+                       { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC294_FIXUP_ASUS_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1103c }, /* use as headset mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC294_FIXUP_ASUS_SPK] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Set EAPD high */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x40 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x8800 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0f },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x7774 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
+       },
+       [ALC295_FIXUP_CHROME_BOOK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc295_fixup_chromebook,
+               .chained = true,
+               .chain_id = ALC225_FIXUP_HEADSET_JACK
+       },
+       [ALC225_FIXUP_HEADSET_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_jack,
+       },
+       [ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Disable PCBEEP-IN passthrough */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x36 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x57d7 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC285_FIXUP_LENOVO_HEADPHONE_NOISE
+       },
+       [ALC255_FIXUP_ACER_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11130 },
+                       { 0x1a, 0x90a60140 }, /* use as internal mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x01011020 }, /* Rear Line out */
+                       { 0x19, 0x01a1913c }, /* use as Front headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC225_FIXUP_WYSE_AUTO_MUTE
+       },
+       [ALC225_FIXUP_WYSE_AUTO_MUTE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_auto_mute_via_amp,
+               .chained = true,
+               .chain_id = ALC225_FIXUP_WYSE_DISABLE_MIC_VREF
+       },
+       [ALC225_FIXUP_WYSE_DISABLE_MIC_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_mic_vref,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC286_FIXUP_ACER_AIO_HEADSET_MIC] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x4f },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5029 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE
+       },
+       [ALC256_FIXUP_ASUS_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11020 }, /* headset mic with jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
+       },
+       [ALC256_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
+       },
+       [ALC255_FIXUP_PREDATOR_SUBWOOFER] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x17, 0x90170151 }, /* use as internal speaker (LFE) */
+                       { 0x1b, 0x90170152 } /* use as internal speaker (back) */
+               }
+       },
+       [ALC299_FIXUP_PREDATOR_SPK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x21, 0x90170150 }, /* use as headset mic, without its own jack detect */
+                       { }
+               }
+       },
+       [ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_i2c_two,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_PREDATOR_SUBWOOFER
+       },
+       [ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x04a11040 },
+                       { 0x21, 0x04211020 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
+       },
+       [ALC289_FIXUP_DELL_SPK1] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x90170140 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE
+       },
+       [ALC289_FIXUP_DELL_SPK2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x17, 0x90170130 }, /* bass spk */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE
+       },
+       [ALC289_FIXUP_DUAL_SPK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC289_FIXUP_DELL_SPK2
+       },
+       [ALC289_FIXUP_RTK_AMP_DUAL_SPK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC289_FIXUP_DELL_SPK1
+       },
+       [ALC294_FIXUP_SPK2_TO_DAC1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
+       },
+       [ALC294_FIXUP_ASUS_DUAL_SPK] = {
+               .type = HDA_FIXUP_FUNC,
+               /* The GPIO must be pulled to initialize the AMP */
+               .v.func = alc_fixup_gpio4,
+               .chained = true,
+               .chain_id = ALC294_FIXUP_SPK2_TO_DAC1
+       },
+       [ALC294_FIXUP_ASUS_ALLY] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_i2c_two,
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
+       },
+       [ALC294_FIXUP_ASUS_ALLY_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 },
+                       { 0x1a, 0x03a11c30 },
+                       { 0x21, 0x03211420 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_ALLY_VERBS
+       },
+       [ALC294_FIXUP_ASUS_ALLY_VERBS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x46 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0004 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x47 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xa47a },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0049},
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x201b },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x4278},
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_ALLY_SPEAKER
+       },
+       [ALC294_FIXUP_ASUS_ALLY_SPEAKER] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+       },
+       [ALC285_FIXUP_THINKPAD_X1_GEN7] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_thinkpad_x1_gen7,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+       },
+       [ALC285_FIXUP_THINKPAD_HEADSET_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_jack,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_THINKPAD_X1_GEN7
+       },
+       [ALC294_FIXUP_ASUS_HPE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Set EAPD high */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0f },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x7774 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
+       },
+       [ALC294_FIXUP_ASUS_GX502_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 }, /* front HP mic */
+                       { 0x1a, 0x01a11830 }, /* rear external mic */
+                       { 0x21, 0x03211020 }, /* front HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_GX502_VERBS
+       },
+       [ALC294_FIXUP_ASUS_GX502_VERBS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* set 0x15 to HP-OUT ctrl */
+                       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+                       /* unmute the 0x15 amp */
+                       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_GX502_HP
+       },
+       [ALC294_FIXUP_ASUS_GX502_HP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc294_fixup_gx502_hp,
+       },
+       [ALC294_FIXUP_ASUS_GU502_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a11050 }, /* rear HP mic */
+                       { 0x1a, 0x01a11830 }, /* rear external mic */
+                       { 0x21, 0x012110f0 }, /* rear HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_GU502_VERBS
+       },
+       [ALC294_FIXUP_ASUS_GU502_VERBS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* set 0x15 to HP-OUT ctrl */
+                       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
+                       /* unmute the 0x15 amp */
+                       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
+                       /* set 0x1b to HP-OUT */
+                       { 0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_GU502_HP
+       },
+       [ALC294_FIXUP_ASUS_GU502_HP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc294_fixup_gu502_hp,
+       },
+        [ALC294_FIXUP_ASUS_G513_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                               { 0x19, 0x03a11050 }, /* front HP mic */
+                               { 0x1a, 0x03a11c30 }, /* rear external mic */
+                               { 0x21, 0x03211420 }, /* front HP out */
+                               { }
+               },
+       },
+       [ALC285_FIXUP_ASUS_G533Z_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x90170152 }, /* Speaker Surround Playback Switch */
+                       { 0x19, 0x03a19020 }, /* Mic Boost Volume */
+                       { 0x1a, 0x03a11c30 }, /* Mic Boost Volume */
+                       { 0x1e, 0x90170151 }, /* Rear jack, IN OUT EAPD Detect */
+                       { 0x21, 0x03211420 },
+                       { }
+               },
+       },
+       [ALC294_FIXUP_ASUS_COEF_1B] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Set bit 10 to correct noisy output after reboot from
+                        * Windows 10 (due to pop noise reduction?)
+                        */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x1b },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x4e4b },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC289_FIXUP_ASUS_GA401,
+       },
+       [ALC285_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_gpio_led,
+       },
+       [ALC285_FIXUP_HP_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_mute_led,
+       },
+       [ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_spectre_x360_mute_led,
+       },
+       [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_beep,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_MUTE_LED,
+       },
+       [ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = {
+           .type = HDA_FIXUP_FUNC,
+           .v.func = alc236_fixup_hp_mute_led_coefbit2,
+       },
+       [ALC236_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc236_fixup_hp_gpio_led,
+       },
+       [ALC236_FIXUP_HP_MUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc236_fixup_hp_mute_led,
+       },
+       [ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc236_fixup_hp_mute_led_micmute_vref,
+       },
+       [ALC236_FIXUP_LENOVO_INV_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_inv_dmic,
+               .chained = true,
+               .chain_id = ALC283_FIXUP_INT_MIC,
+       },
+       [ALC295_FIXUP_HP_MUTE_LED_COEFBIT11] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc295_fixup_hp_mute_led_coefbit11,
+       },
+       [ALC298_FIXUP_SAMSUNG_AMP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_samsung_amp,
+               .chained = true,
+               .chain_id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET
+       },
+       [ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_samsung_amp_v2_2_amps
+       },
+       [ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_samsung_amp_v2_4_amps
+       },
+       [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc5 },
+                       { }
+               },
+       },
+       [ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x08},
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2fcf},
+                       { }
+               },
+       },
+       [ALC295_FIXUP_ASUS_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x90100120 }, /* use as internal speaker */
+                       { 0x18, 0x02a111f0 }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x01011020 }, /* use as line out */
+                       { },
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC269VC_FIXUP_ACER_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x02a11030 }, /* use as headset mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x18, 0x01a11130 }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MIC
+       },
+       [ALC289_FIXUP_ASUS_GA401] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc289_fixup_asus_ga401,
+               .chained = true,
+               .chain_id = ALC289_FIXUP_ASUS_GA502,
+       },
+       [ALC289_FIXUP_ASUS_GA502] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11020 }, /* headset mic with jack detect */
+                       { }
+               },
+       },
+       [ALC256_FIXUP_ACER_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x02a11120 }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
+       },
+       [ALC285_FIXUP_HP_GPIO_AMP_INIT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_gpio_amp_init,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_GPIO_LED
+       },
+       [ALC269_FIXUP_CZC_B20] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x411111f0 },
+                       { 0x14, 0x90170110 }, /* speaker */
+                       { 0x15, 0x032f1020 }, /* HP out */
+                       { 0x17, 0x411111f0 },
+                       { 0x18, 0x03ab1040 }, /* mic */
+                       { 0x19, 0xb7a7013f },
+                       { 0x1a, 0x0181305f },
+                       { 0x1b, 0x411111f0 },
+                       { 0x1d, 0x411111f0 },
+                       { 0x1e, 0x411111f0 },
+                       { }
+               },
+               .chain_id = ALC269_FIXUP_DMIC,
+       },
+       [ALC269_FIXUP_CZC_TMI] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x4000c000 },
+                       { 0x14, 0x90170110 }, /* speaker */
+                       { 0x15, 0x0421401f }, /* HP out */
+                       { 0x17, 0x411111f0 },
+                       { 0x18, 0x04a19020 }, /* mic */
+                       { 0x19, 0x411111f0 },
+                       { 0x1a, 0x411111f0 },
+                       { 0x1b, 0x411111f0 },
+                       { 0x1d, 0x40448505 },
+                       { 0x1e, 0x411111f0 },
+                       { 0x20, 0x8000ffff },
+                       { }
+               },
+               .chain_id = ALC269_FIXUP_DMIC,
+       },
+       [ALC269_FIXUP_CZC_L101] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x40000000 },
+                       { 0x14, 0x01014010 }, /* speaker */
+                       { 0x15, 0x411111f0 }, /* HP out */
+                       { 0x16, 0x411111f0 },
+                       { 0x18, 0x01a19020 }, /* mic */
+                       { 0x19, 0x02a19021 },
+                       { 0x1a, 0x0181302f },
+                       { 0x1b, 0x0221401f },
+                       { 0x1c, 0x411111f0 },
+                       { 0x1d, 0x4044c601 },
+                       { 0x1e, 0x411111f0 },
+                       { }
+               },
+               .chain_id = ALC269_FIXUP_DMIC,
+       },
+       [ALC269_FIXUP_LEMOTE_A1802] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0x40000000 },
+                       { 0x14, 0x90170110 }, /* speaker */
+                       { 0x17, 0x411111f0 },
+                       { 0x18, 0x03a19040 }, /* mic1 */
+                       { 0x19, 0x90a70130 }, /* mic2 */
+                       { 0x1a, 0x411111f0 },
+                       { 0x1b, 0x411111f0 },
+                       { 0x1d, 0x40489d2d },
+                       { 0x1e, 0x411111f0 },
+                       { 0x20, 0x0003ffff },
+                       { 0x21, 0x03214020 },
+                       { }
+               },
+               .chain_id = ALC269_FIXUP_DMIC,
+       },
+       [ALC269_FIXUP_LEMOTE_A190X] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0121401f }, /* HP out */
+                       { 0x18, 0x01a19c20 }, /* rear  mic */
+                       { 0x19, 0x99a3092f }, /* front mic */
+                       { 0x1b, 0x0201401f }, /* front lineout */
+                       { }
+               },
+               .chain_id = ALC269_FIXUP_DMIC,
+       },
+       [ALC256_FIXUP_INTEL_NUC8_RUGGED] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC256_FIXUP_INTEL_NUC10] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC255_FIXUP_XIAOMI_HEADSET_MIC] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC289_FIXUP_ASUS_GA502
+       },
+       [ALC274_FIXUP_HP_MIC] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
+                       { }
+               },
+       },
+       [ALC274_FIXUP_HP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc274_fixup_hp_headset_mic,
+               .chained = true,
+               .chain_id = ALC274_FIXUP_HP_MIC
+       },
+       [ALC274_FIXUP_HP_ENVY_GPIO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc274_fixup_hp_envy_gpio,
+       },
+       [ALC274_FIXUP_ASUS_ZEN_AIO_27] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x10 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xc420 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x40 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x8800 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0249 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x202b },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x62 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xa007 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5060 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC2XX_FIXUP_HEADSET_MIC,
+       },
+       [ALC256_FIXUP_ASUS_HPE] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* Set EAPD high */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0f },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x7778 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
+       },
+       [ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_jack,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+       },
+       [ALC287_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_hp_gpio_led,
+       },
+       [ALC256_FIXUP_HP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc274_fixup_hp_headset_mic,
+       },
+       [ALC236_FIXUP_DELL_AIO_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_int_mic,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
+       },
+       [ALC282_FIXUP_ACER_DISABLE_LINEOUT] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x411111f0 },
+                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { },
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE
+       },
+       [ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+       },
+       [ALC256_FIXUP_ACER_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x02a1113c }, /* use as headset mic, without its own jack detect */
+                       { 0x1a, 0x90a1092f }, /* use as internal mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC285_FIXUP_IDEAPAD_S740_COEF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_ideapad_s740_coef,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+       },
+       [ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_MUTE_LED,
+       },
+       [ALC295_FIXUP_ASUS_DACS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc295_fixup_asus_dacs,
+       },
+       [ALC295_FIXUP_HP_OMEN] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x12, 0xb7a60130 },
+                       { 0x13, 0x40000000 },
+                       { 0x14, 0x411111f0 },
+                       { 0x16, 0x411111f0 },
+                       { 0x17, 0x90170110 },
+                       { 0x18, 0x411111f0 },
+                       { 0x19, 0x02a11030 },
+                       { 0x1a, 0x411111f0 },
+                       { 0x1b, 0x04a19030 },
+                       { 0x1d, 0x40600001 },
+                       { 0x1e, 0x411111f0 },
+                       { 0x21, 0x03211020 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HP_LINE1_MIC1_LED,
+       },
+       [ALC285_FIXUP_HP_SPECTRE_X360] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_spectre_x360,
+       },
+       [ALC285_FIXUP_HP_SPECTRE_X360_EB1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_spectre_x360_eb1
+       },
+       [ALC285_FIXUP_HP_SPECTRE_X360_DF1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_spectre_x360_df1
+       },
+       [ALC285_FIXUP_HP_ENVY_X360] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_hp_envy_x360,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_GPIO_AMP_INIT,
+       },
+       [ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_ideapad_s740_coef,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+       },
+       [ALC623_FIXUP_LENOVO_THINKSTATION_P340] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_shutup,
+               .chained = true,
+               .chain_id = ALC283_FIXUP_HEADSET_MIC,
+       },
+       [ALC255_FIXUP_ACER_HEADPHONE_AND_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x21, 0x03211030 }, /* Change the Headphone location to Left */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC255_FIXUP_XIAOMI_HEADSET_MIC
+       },
+       [ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
+       },
+       [ALC285_FIXUP_LEGION_Y9000X_SPEAKERS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_ideapad_s740_coef,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE,
+       },
+       [ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_legion_15imhg05_speakers,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
+       },
+       [ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS] = {
+               .type = HDA_FIXUP_VERBS,
+               //.v.verbs = legion_15imhg05_coefs,
+               .v.verbs = (const struct hda_verb[]) {
+                        // set left speaker Legion 7i.
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
+
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x1a },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                        // set right speaker Legion 7i.
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x42 },
+
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2a },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+                        {}
+               },
+               .chained = true,
+               .chain_id = ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
+       },
+       [ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_legion_15imhg05_speakers,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE,
+       },
+       [ALC287_FIXUP_YOGA7_14ITL_SPEAKERS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                        // set left speaker Yoga 7i.
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
+
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x1a },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                        // set right speaker Yoga 7i.
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x46 },
+
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2a },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+                        {}
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE,
+       },
+       [ALC298_FIXUP_LENOVO_C940_DUET7] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc298_fixup_lenovo_c940_duet7,
+       },
+       [ALC287_FIXUP_13S_GEN2_SPEAKERS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x42 },
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE,
+       },
+       [ALC256_FIXUP_SET_COEF_DEFAULTS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_fixup_set_coef_defaults,
+       },
+       [ALC245_FIXUP_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_gpio_led,
+       },
+       [ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11120 }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
+       },
+       [ALC233_FIXUP_NO_AUDIO_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc233_fixup_no_audio_jack,
+       },
+       [ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_fixup_mic_no_presence_and_resume,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC287_FIXUP_LEGION_16ACHG6] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_legion_16achg6_speakers,
+       },
+       [ALC287_FIXUP_CS35L41_I2C_2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_i2c_two,
+       },
+       [ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_i2c_two,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_MUTE_LED,
+       },
+       [ALC287_FIXUP_CS35L41_I2C_4] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_i2c_four,
+       },
+       [ALC245_FIXUP_CS35L41_SPI_2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_spi_two,
+       },
+       [ALC245_FIXUP_CS35L41_SPI_1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_spi_one,
+       },
+       [ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_spi_two,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_GPIO_LED,
+       },
+       [ALC245_FIXUP_CS35L41_SPI_4] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_spi_four,
+       },
+       [ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_spi_four,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_GPIO_LED,
+       },
+       [ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x19 },
+                        { 0x20, AC_VERB_SET_PROC_COEF, 0x8e11 },
+                        { }
+               },
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_MUTE_LED,
+       },
+       [ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_dell4_mic_no_presence_quiet,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+       },
+       [ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x02a1112c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
+       },
+       [ALC287_FIXUP_LEGION_16ITHG6] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_legion_16ithg6_speakers,
+       },
+       [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       // enable left speaker
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x1a },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xf },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x42 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x10 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x40 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       // enable right speaker
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x46 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2a },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xf },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x46 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x10 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x44 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
+
+                       { },
+               },
+       },
+       [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin,
+               .chained = true,
+               .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
+       },
+       [ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin,
+               .chained = true,
+               .chain_id = ALC287_FIXUP_CS35L41_I2C_2,
+       },
+       [ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc295_fixup_dell_inspiron_top_speakers,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+       },
+       [ALC236_FIXUP_DELL_DUAL_CODECS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.func = alc1220_fixup_gb_dual_codecs,
+               .chained = true,
+               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+       },
+       [ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_i2c_two,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
+       },
+       [ALC287_FIXUP_TAS2781_I2C] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = tas2781_fixup_tias_i2c,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+       },
+       [ALC245_FIXUP_TAS2781_SPI_2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = tas2781_fixup_spi,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_HP_GPIO_LED,
+       },
+       [ALC287_FIXUP_TXNW2781_I2C] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = tas2781_fixup_txnw_i2c,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+       },
+       [ALC287_FIXUP_YOGA7_14ARB7_I2C] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = yoga7_14arb7_fixup_i2c,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+       },
+       [ALC245_FIXUP_HP_MUTE_LED_COEFBIT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_mute_led_coefbit,
+       },
+       [ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_mute_led_v1_coefbit,
+       },
+       [ALC245_FIXUP_HP_X360_MUTE_LEDS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_mute_led_coefbit,
+               .chained = true,
+               .chain_id = ALC245_FIXUP_HP_GPIO_LED
+       },
+       [ALC287_FIXUP_THINKPAD_I2S_SPK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_bind_dacs,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
+       },
+       [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_bind_dacs,
+               .chained = true,
+               .chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
+       },
+       [ALC2XX_FIXUP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mic,
+       },
+       [ALC289_FIXUP_DELL_CS35L41_SPI_2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_spi_two,
+               .chained = true,
+               .chain_id = ALC289_FIXUP_DUAL_SPK
+       },
+       [ALC294_FIXUP_CS35L41_I2C_2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_i2c_two,
+       },
+       [ALC256_FIXUP_ACER_SFG16_MICMUTE_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_fixup_acer_sfg16_micmute_led,
+       },
+       [ALC256_FIXUP_HEADPHONE_AMP_VOL] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_decrease_headphone_amp_val,
+       },
+       [ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_spectre_x360_eu0xxx,
+       },
+       [ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_spectre_x360_16_aa0xxx,
+       },
+       [ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc245_fixup_hp_zbook_firefly_g12a,
+       },
+       [ALC285_FIXUP_ASUS_GA403U] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_asus_ga403u,
+       },
+       [ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 },
+                       { 0x1b, 0x03a11c30 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1
+       },
+       [ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC,
+       },
+       [ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 },
+                       { 0x1b, 0x03a11c30 },
+                       { }
+               },
+       },
+       [ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+               .chained = true,
+               .chain_id = ALC285_FIXUP_ASUS_GA403U,
+       },
+       [ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc287_fixup_lenovo_thinkpad_with_alc1318,
+               .chained = true,
+               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
+       },
+       [ALC256_FIXUP_CHROME_BOOK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc256_fixup_chromebook,
+               .chained = true,
+               .chain_id = ALC225_FIXUP_HEADSET_JACK
+       },
+       [ALC245_FIXUP_CLEVO_NOISY_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
+       },
+       [ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+                       { 0x1b, 0x20a11040 }, /* dock mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
+       },
+       [ALC233_FIXUP_MEDION_MTL_SPK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x90170110 },
+                       { }
+               },
+       },
+       [ALC294_FIXUP_BASS_SPEAKER_15] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc294_fixup_bass_speaker_15,
+       },
+       [ALC283_FIXUP_DELL_HP_RESUME] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc283_fixup_dell_hp_resume,
+       },
+       [ALC294_FIXUP_ASUS_CS35L41_SPI_2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs35l41_fixup_spi_two,
+               .chained = true,
+               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC,
+       },
+       [ALC274_FIXUP_HP_AIO_BIND_DACS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc274_fixup_hp_aio_bind_dacs,
+       },
+       [ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 },
+                       { 0x1b, 0x03a11c30 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1
+       },
+       [ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc285_fixup_speaker2_to_dac1,
+       },
+       [ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_limit_int_mic_boost,
+               .chained = true,
+               .chain_id = ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE,
+       },
+};
+
+static const struct hda_quirk alc269_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
+       SND_PCI_QUIRK(0x1025, 0x072d, "Acer Aspire V5-571G", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
+       SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
+       SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
+       SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
+       SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
+       SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF),
+       SND_PCI_QUIRK(0x1025, 0x100c, "Acer Aspire E5-574G", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK),
+       SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x1025, 0x1094, "Acer Aspire E5-575T", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1025, 0x1099, "Acer Aspire E5-523G", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x110e, "Acer Aspire ES1-432", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x1166, "Acer Veriton N4640G", ALC269_FIXUP_LIFEBOOK),
+       SND_PCI_QUIRK(0x1025, 0x1167, "Acer Veriton N6640G", ALC269_FIXUP_LIFEBOOK),
+       SND_PCI_QUIRK(0x1025, 0x1177, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER),
+       SND_PCI_QUIRK(0x1025, 0x1178, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER),
+       SND_PCI_QUIRK(0x1025, 0x1246, "Acer Predator Helios 500", ALC299_FIXUP_PREDATOR_SPK),
+       SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
+       SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x1269, "Acer SWIFT SF314-54", ALC256_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x126a, "Acer Swift SF114-32", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x128f, "Acer Veriton Z6860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x129d, "Acer SWIFT SF313-51", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x1300, "Acer SWIFT SF314-56", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x1330, "Acer TravelMate X514-51T", ALC255_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x1360, "Acer Aspire A115", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x141f, "Acer Spin SP513-54N", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x142b, "Acer Swift SF314-42", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
+       SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
+       SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
+       SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
+       SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
+       SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
+       SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X),
+       SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X),
+       SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X),
+       SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
+       SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0604, "Dell Venue 11 Pro 7130", ALC283_FIXUP_DELL_HP_RESUME),
+       SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
+       SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
+       SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X),
+       SND_PCI_QUIRK(0x1028, 0x062e, "Dell Latitude E7450", ALC292_FIXUP_DELL_E7X),
+       SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
+       SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0665, "Dell XPS 13", ALC288_FIXUP_DELL_XPS_13),
+       SND_PCI_QUIRK(0x1028, 0x0669, "Dell Optiplex 9020m", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x069a, "Dell Vostro 5480", ALC290_FIXUP_SUBWOOFER_HSJACK),
+       SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
+       SND_PCI_QUIRK(0x1028, 0x0706, "Dell Inspiron 7559", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
+       SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
+       SND_PCI_QUIRK(0x1028, 0x0738, "Dell Precision 5820", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1028, 0x075c, "Dell XPS 27 7760", ALC298_FIXUP_SPK_VOLUME),
+       SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
+       SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
+       SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3),
+       SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
+       SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
+       SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB),
+       SND_PCI_QUIRK(0x1028, 0x0879, "Dell Latitude 5420 Rugged", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
+       SND_PCI_QUIRK(0x1028, 0x097d, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x098d, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x09bf, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0a2e, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0a30, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0a38, "Dell Latitude 7520", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET),
+       SND_PCI_QUIRK(0x1028, 0x0a58, "Dell", ALC255_FIXUP_DELL_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1028, 0x0a61, "Dell XPS 15 9510", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0a62, "Dell Precision 5560", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0a9d, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0a9e, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0b19, "Dell XPS 15 9520", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0b27, "Dell", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0b28, "Dell", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
+       SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
+       SND_PCI_QUIRK(0x1028, 0x0beb, "Dell XPS 15 9530 (2023)", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0c0b, "Dell Oasis 14 RPL-P", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0c0d, "Dell Oasis", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0c0e, "Dell Oasis 16", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1028, 0x0c1c, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1028, 0x0c1d, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1028, 0x0c1e, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
+       SND_PCI_QUIRK(0x1028, 0x0c28, "Dell Inspiron 16 Plus 7630", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
+       SND_PCI_QUIRK(0x1028, 0x0c4d, "Dell", ALC287_FIXUP_CS35L41_I2C_4),
+       SND_PCI_QUIRK(0x1028, 0x0c94, "Dell Polaris 3 metal", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1028, 0x0c96, "Dell Polaris 2in1", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1028, 0x0cbd, "Dell Oasis 13 CS MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0cbe, "Dell Oasis 13 2-IN-1 MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0cbf, "Dell Oasis 13 Low Weight MTU-L", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0cc0, "Dell Oasis 13", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x0cc1, "Dell Oasis 14 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0cc2, "Dell Oasis 14 2-in-1 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0cc3, "Dell Oasis 14 Low Weight MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0cc4, "Dell Oasis 16 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1028, 0x0cc5, "Dell Oasis 14", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
+       SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2256, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY),
+       SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS),
+       SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS),
+       SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M),
+       SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+       SND_PCI_QUIRK(0x103c, 0x2b5e, "HP 288 Pro G2 MT", ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x103c, 0x8158, "HP", ALC256_FIXUP_HP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x103c, 0x820d, "HP Pavilion 15", ALC295_FIXUP_HP_X360),
+       SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC),
+       SND_PCI_QUIRK(0x103c, 0x827e, "HP x360", ALC295_FIXUP_HP_X360),
+       SND_PCI_QUIRK(0x103c, 0x827f, "HP x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+       SND_PCI_QUIRK(0x103c, 0x82bf, "HP G3 mini", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x82c0, "HP G3 mini premium", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+       SND_PCI_QUIRK(0x103c, 0x841c, "HP Pavilion 15-CK0xx", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+       SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+       SND_PCI_QUIRK(0x103c, 0x84a6, "HP 250 G7 Notebook PC", ALC269_FIXUP_HP_LINE1_MIC1_LED),
+       SND_PCI_QUIRK(0x103c, 0x84ae, "HP 15-db0403ng", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN),
+       SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
+       SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360),
+       SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11),
+       SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360),
+       SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
+       SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+       SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1),
+       SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+       SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8728, "HP EliteBook 840 G7", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
+       SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x8780, "HP ZBook Fury 17 G7 Mobile Workstation",
+                     ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation",
+                     ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x8786, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x8787, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87d3, "HP Laptop 15-gw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x87df, "HP ProBook 430 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87f1, "HP ProBook 630 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87f2, "HP ProBook 640 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x87f6, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
+       SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
+       SND_PCI_QUIRK(0x103c, 0x87fd, "HP Laptop 14-dq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x87fe, "HP Laptop 15s-fq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x8805, "HP ProBook 650 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x880d, "HP EliteBook 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8811, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+       SND_PCI_QUIRK(0x103c, 0x8812, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
+       SND_PCI_QUIRK(0x103c, 0x881d, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x881e, "HP Laptop 15s-du3xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8862, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x103c, 0x8863, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x8870, "HP ZBook Fury 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x8873, "HP ZBook Studio 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
+       SND_PCI_QUIRK(0x103c, 0x887a, "HP Laptop 15s-eq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x887c, "HP Laptop 14s-fq1xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x888a, "HP ENVY x360 Convertible 15-eu0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
+       SND_PCI_QUIRK(0x103c, 0x888d, "HP ZBook Power 15.6 inch G8 Mobile Workstation PC", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8895, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x88dd, "HP Pavilion 15z-ec200", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x8902, "HP OMEN 16", ALC285_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK(0x103c, 0x890e, "HP 255 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x8919, "HP Pavilion Aero Laptop 13-be0xxx", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x896d, "HP ZBook Firefly 16 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x896e, "HP EliteBook x360 830 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8971, "HP EliteBook 830 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8972, "HP EliteBook 840 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8973, "HP EliteBook 860 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8974, "HP EliteBook 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8975, "HP EliteBook x360 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x897d, "HP mt440 Mobile Thin Client U74", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8981, "HP Elite Dragonfly G3", ALC245_FIXUP_CS35L41_SPI_4),
+       SND_PCI_QUIRK(0x103c, 0x898a, "HP Pavilion 15-eg100", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x898e, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x898f, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8991, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8992, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8994, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8995, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x89a4, "HP ProBook 440 G9", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89a6, "HP ProBook 450 G9", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89aa, "HP EliteBook 630 G9", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89ac, "HP EliteBook 640 G9", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89ae, "HP EliteBook 650 G9", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89c0, "HP ZBook Power 15.6 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89c3, "Zbook Studio G9", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8a28, "HP Envy 13", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a29, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2b, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2c, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
+       SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ab9, "HP EliteBook 840 G8 (MB 8AB8)", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ad8, "HP 800 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
+       SND_PCI_QUIRK(0x103c, 0x8b3a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8b3f, "HP mt440 Mobile Thin Client U91", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b44, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b45, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b46, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b47, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b59, "HP Elite mt645 G7 Mobile Thin Client U89", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b5f, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b63, "HP Elite Dragonfly 13.5 inch G4", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b65, "HP ProBook 455 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b66, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b70, "HP EliteBook 835 G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b72, "HP EliteBook 845 G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b74, "HP EliteBook 845W G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b77, "HP ElieBook 865 G10", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8b7a, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b7d, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b87, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b8a, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b8b, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b8d, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b8f, "HP", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bbe, "HP Victus 16-r0xxx (MB 8BBE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be0, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be1, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be2, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be3, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be5, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be6, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be7, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+       SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX),
+       SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c21, "HP Pavilion Plus Laptop 14-ey0XXX", ALC245_FIXUP_HP_X360_MUTE_LEDS),
+       SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c4d, "HP Omen", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c4e, "HP Omen", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c4f, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c50, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c51, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c66, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c67, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c68, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c6a, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c7b, "HP ProBook 445 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c7c, "HP ProBook 445 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c7d, "HP ProBook 465 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c7e, "HP ProBook 465 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c7f, "HP EliteBook 645 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c80, "HP EliteBook 645 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c81, "HP EliteBook 665 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c89, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c8a, "HP EliteBook 630", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c8c, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c8d, "HP ProBook 440 G11", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c8e, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c90, "HP EliteBook 640", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8c9c, "HP Victus 16-s1xxx (MB 8C9C)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8caf, "HP Elite mt645 G8 Mobile Thin Client", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8cbd, "HP Pavilion Aero Laptop 13-bg0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
+       SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+       SND_PCI_QUIRK(0x103c, 0x8cde, "HP OmniBook Ultra Flip Laptop 14t", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
+       SND_PCI_QUIRK(0x103c, 0x8cdf, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ce0, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d07, "HP Victus 15-fb2xxx (MB 8D07)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
+       SND_PCI_QUIRK(0x103c, 0x8d18, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS),
+       SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d85, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d86, "HP Elite X360 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d8c, "HP EliteBook 13 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d8d, "HP Elite X360 13 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d8e, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d8f, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8d9e, "HP 17 Turbine OmniBook X DIS", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8d9f, "HP 14 Cadet (x360)", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8da0, "HP 16 Clipper OmniBook 7(X360)", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8da1, "HP 16 Clipper OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8da7, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8da8, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8dd4, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS),
+       SND_PCI_QUIRK(0x103c, 0x8de8, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
+       SND_PCI_QUIRK(0x103c, 0x8de9, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
+       SND_PCI_QUIRK(0x103c, 0x8dec, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8ded, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8dee, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8def, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8df0, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8df1, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8dfb, "HP EliteBook 6 G1a 14", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8dfd, "HP EliteBook 6 G1a 16", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
+       SND_PCI_QUIRK(0x103c, 0x8dfe, "HP EliteBook 665 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8e11, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e12, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e13, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e14, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e15, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e16, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e17, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e1b, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e1c, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
+       SND_PCI_QUIRK(0x103c, 0x8e1d, "HP ZBook X Gli 16 G12", ALC236_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8e2c, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
+       SND_PCI_QUIRK(0x103c, 0x8e36, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e37, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e3a, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e3b, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
+       SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
+       SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
+       SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1043, 0x106f, "ASUS VivoBook X515UA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1074, "ASUS G614PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK),
+       SND_PCI_QUIRK(0x1043, 0x10a4, "ASUS TP3407SA", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
+       SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x10d3, "ASUS K6500ZC", ALC294_FIXUP_ASUS_SPK),
+       SND_PCI_QUIRK(0x1043, 0x1154, "ASUS TP3607SH", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1043, 0x1194, "ASUS UM3406KA", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1294, "ASUS B3405CVA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x12a3, "Asus N7691ZM", ALC269_FIXUP_ASUS_N7601ZM),
+       SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x12b4, "ASUS B3405CCA / P3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1314, "ASUS GA605K", ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
+       SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1460, "Asus VivoBook 15", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X/GA402N", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604VI/VC/VE/VG/VJ/VQ/VU/VV/VY/VZ", ALC285_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603VQ/VU/VV/VJ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601VV/VU/VJ/VQ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G614JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS G513PI/PU/PV", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x14f2, "ASUS VivoBook X515JA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1503, "ASUS G733PY/PZ/PZV/PYV", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
+       SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
+       SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x16d3, "ASUS UX5304VA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS UX7602VI/BZ", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS),
+       SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
+       SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY),
+       SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
+       SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC294_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
+       SND_PCI_QUIRK(0x1043, 0x1970, "ASUS UX550VE", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x1982, "ASUS B1400CEPE", ALC256_FIXUP_ASUS_HPE),
+       SND_PCI_QUIRK(0x1043, 0x19ce, "ASUS B9450FA", ALC294_FIXUP_ASUS_HPE),
+       SND_PCI_QUIRK(0x1043, 0x19e1, "ASUS UX581LV", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
+       SND_PCI_QUIRK(0x1043, 0x1a63, "ASUS UX3405MA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B),
+       SND_PCI_QUIRK(0x1043, 0x1b13, "ASUS U41SV/GA403U", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1b93, "ASUS G614JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1c03, "ASUS UM3406HA", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1043, 0x1c33, "ASUS UX5304MA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x1c63, "ASUS GU605M", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
+       SND_PCI_QUIRK(0x1043, 0x1c80, "ASUS VivoBook TP401", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS),
+       SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JU/JV/JI", ALC285_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JY/JZ/JI/JG", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+       SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1ccf, "ASUS G814JU/JV/JI", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1cdf, "ASUS G814JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1cef, "ASUS G834JY/JZ/JI/JG", ALC285_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1d1f, "ASUS G713PI/PU/PV/PVN", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
+       SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606WA", ALC294_FIXUP_BASS_SPEAKER_15),
+       SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15),
+       SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
+       SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1e1f, "ASUS Vivobook 15 X1504VAP", ALC2XX_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
+       SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS),
+       SND_PCI_QUIRK(0x1043, 0x1e63, "ASUS H7606W", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
+       SND_PCI_QUIRK(0x1043, 0x1e83, "ASUS GA605W", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
+       SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE),
+       SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RCLA72", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x1f1f, "ASUS H7604JI/JV/J3D", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1f63, "ASUS P5405CSA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
+       SND_PCI_QUIRK(0x1043, 0x1fb3, "ASUS ROG Flow Z13 GZ302EA", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x3011, "ASUS B5605CVA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
+       SND_PCI_QUIRK(0x1043, 0x3061, "ASUS B3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x3071, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x30c1, "ASUS B3605CCA / P3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x30d1, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x30e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x31d0, "ASUS Zen AIO 27 Z272SD_A272SD", ALC274_FIXUP_ASUS_ZEN_AIO_27),
+       SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+       SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+       SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+       SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+       SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
+       SND_PCI_QUIRK(0x1043, 0x3d78, "ASUS GA603KH", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x3d88, "ASUS GA603KM", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x3e00, "ASUS G814FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x3e20, "ASUS G814PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x1043, 0x3e30, "ASUS TP3607SA", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x3ee0, "ASUS Strix G815_JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x3ef0, "ASUS Strix G635LR_LW_LX", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x3f00, "ASUS Strix G815LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x3f10, "ASUS Strix G835LR_LW_LX", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x3f30, "ASUS Strix G815LR_LW", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x1043, 0x3fd0, "ASUS B3605CVA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x3ff0, "ASUS B5405CVA", ALC245_FIXUP_CS35L41_SPI_2),
+       SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
+       SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
+       SND_PCI_QUIRK(0x1043, 0x88f4, "ASUS NUC14LNS", ALC245_FIXUP_CS35L41_SPI_1),
+       SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
+       SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
+       SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
+       SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX),
+       SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
+       SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT),
+       SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN),
+       SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC),
+       SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
+       SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
+       SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE),
+       SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),
+       SND_PCI_QUIRK(0x10ec, 0x119e, "Positivo SU C1400", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
+       SND_PCI_QUIRK(0x10ec, 0x11bc, "VAIO VJFE-IL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
+       SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc1a3, "Samsung Galaxy Book Pro (NP935XDB-KC1SE)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc1a4, "Samsung Galaxy Book Pro 360 (NT935QBD)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc1a6, "Samsung Galaxy Book Pro 360 (NP930QBD)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
+       SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xca06, "Samsung Galaxy Book3 360 (NP730QFG)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
+       SND_PCI_QUIRK(0x144d, 0xc868, "Samsung Galaxy Book2 Pro (NP930XED)", ALC298_FIXUP_SAMSUNG_AMP),
+       SND_PCI_QUIRK(0x144d, 0xc870, "Samsung Galaxy Book2 Pro (NP950XED)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
+       SND_PCI_QUIRK(0x144d, 0xc872, "Samsung Galaxy Book2 Pro (NP950XEE)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
+       SND_PCI_QUIRK(0x144d, 0xc886, "Samsung Galaxy Book3 Pro (NP964XFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+       SND_PCI_QUIRK(0x144d, 0xc1ca, "Samsung Galaxy Book3 Pro 360 (NP960QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+       SND_PCI_QUIRK(0x144d, 0xc1cc, "Samsung Galaxy Book3 Ultra (NT960XFH)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+       SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x152d, 0x1082, "Quanta NL3", ALC269_FIXUP_LIFEBOOK),
+       SND_PCI_QUIRK(0x152d, 0x1262, "Huawei NBLB-WAX9N", ALC2XX_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1558, 0x0353, "Clevo V35[05]SN[CDE]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x1323, "Clevo N130ZU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x1325, "Clevo N15[01][CW]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x1401, "Clevo L140[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x1403, "Clevo N140CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x2624, "Clevo L240TU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x28c1, "Clevo V370VND", ALC2XX_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1558, 0x35a1, "Clevo V3[56]0EN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x35b1, "Clevo V3[57]0WN[MNP]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x4041, "Clevo NV4[15]PZ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x40a1, "Clevo NL40GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x40c1, "Clevo NL40[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x40d1, "Clevo NL41DU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x5015, "Clevo NH5[58]H[HJK]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x5017, "Clevo NH7[79]H[HJK]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50a3, "Clevo NJ51GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50b3, "Clevo NK50S[BEZ]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50b6, "Clevo NK50S5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50b8, "Clevo NK50SZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50d5, "Clevo NP50D5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50e1, "Clevo NH5[58]HPQ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50e2, "Clevo NH7[79]HPQ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50f0, "Clevo NH50A[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50f2, "Clevo NH50E[PR]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50f3, "Clevo NH58DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50f5, "Clevo NH55EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x50f6, "Clevo NH55DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x5101, "Clevo S510WU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x5157, "Clevo W517GU1", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x51a1, "Clevo NS50MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x51b1, "Clevo NS50AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x51b3, "Clevo NS70AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x5700, "Clevo X560WN[RST]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x70f3, "Clevo NH77DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x7716, "Clevo NS50PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x7717, "Clevo NS70PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x7718, "Clevo L140PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x7724, "Clevo L140AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8535, "Clevo NH50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8536, "Clevo NH79D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8550, "Clevo NH[57][0-9][ER][ACDH]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8551, "Clevo NH[57][0-9][ER][ACDH]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8560, "Clevo NH[57][0-9][ER][ACDH]Q", ALC269_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1558, 0x8561, "Clevo NH[57][0-9][ER][ACDH]Q", ALC269_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[57][0-9]RZ[Q]", ALC269_FIXUP_DMIC),
+       SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x866d, "Clevo NP5[05]PN[HJK]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x867c, "Clevo NP7[01]PNP", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x867d, "Clevo NP7[01]PN[HJK]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME),
+       SND_PCI_QUIRK(0x1558, 0x8a20, "Clevo NH55DCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8a51, "Clevo NH70RCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x8d50, "Clevo NH55RCQ-M", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x951d, "Clevo N950T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x9600, "Clevo N960K[PR]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x961d, "Clevo N960S[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0x971d, "Clevo N970T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL5[03]RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xa554, "VAIO VJFH52", ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xa600, "Clevo NL50NU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xa650, "Clevo NP[567]0SN[CD]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xa671, "Clevo NP70SN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xa741, "Clevo V54x_6x_TNE", ALC245_FIXUP_CLEVO_NOISY_MIC),
+       SND_PCI_QUIRK(0x1558, 0xa743, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC),
+       SND_PCI_QUIRK(0x1558, 0xa763, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC),
+       SND_PCI_QUIRK(0x1558, 0xb018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xb019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xb022, "Clevo NH77D[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xc018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xc019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1558, 0xc022, "Clevo NH77[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS),
+       SND_PCI_QUIRK(0x17aa, 0x1048, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
+       SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440),
+       SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x222d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x222e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2231, "Thinkpad T560", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x2234, "Thinkpad ICE-1", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x2249, "Thinkpad", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
+       SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
+       SND_PCI_QUIRK(0x17aa, 0x22c1, "Thinkpad P1 Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
+       SND_PCI_QUIRK(0x17aa, 0x22c2, "Thinkpad X1 Extreme Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
+       SND_PCI_QUIRK(0x17aa, 0x22f1, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x22f2, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x22f3, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x2316, "Thinkpad P1 Gen 6", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x2317, "Thinkpad P1 Gen 6", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x2318, "Thinkpad Z13 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x2319, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x231e, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
+       SND_PCI_QUIRK(0x17aa, 0x231f, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
+       SND_PCI_QUIRK(0x17aa, 0x2326, "Hera2", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+       SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
+       SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+       SND_PCI_QUIRK(0x17aa, 0x3111, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+       SND_PCI_QUIRK(0x17aa, 0x312a, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+       SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+       SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
+       SND_PCI_QUIRK(0x17aa, 0x3151, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x17aa, 0x3176, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
+       SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x17aa, 0x3384, "ThinkCentre M90a PRO", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
+       SND_PCI_QUIRK(0x17aa, 0x3386, "ThinkCentre M90a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
+       SND_PCI_QUIRK(0x17aa, 0x3387, "ThinkCentre M70a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
+       SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+       HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7),
+       SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
+       HDA_CODEC_QUIRK(0x17aa, 0x3820, "IdeaPad 330-17IKB 81DM", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
+       SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF),
+       SND_PCI_QUIRK(0x17aa, 0x3834, "Lenovo IdeaPad Slim 9i 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x383d, "Legion Y9000X 2019", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3843, "Yoga 9i", ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP),
+       SND_PCI_QUIRK(0x17aa, 0x3847, "Legion 7 16ACHG6", ALC287_FIXUP_LEGION_16ACHG6),
+       SND_PCI_QUIRK(0x17aa, 0x384a, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
+       SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+       HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1),
+       HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */
+       SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x387f, "Yoga S780-16 pro dual LX", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3880, "Yoga S780-16 pro dual YC", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual power mode2 YC", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3882, "Lenovo Yoga Pro 7 14APH8", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x3884, "Y780 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3891, "Lenovo Yoga Pro 7 14AHP9", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x38a5, "Y580P AMD dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x38b5, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x38b6, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x38b7, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x17aa, 0x38b8, "Yoga S780-14.5 proX AMD YC Dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38b9, "Yoga S780-14.5 proX AMD LX Dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38c3, "Y980 DUAL", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38c7, "Thinkbook 13x Gen 4", ALC287_FIXUP_CS35L41_I2C_4),
+       SND_PCI_QUIRK(0x17aa, 0x38c8, "Thinkbook 13x Gen 4", ALC287_FIXUP_CS35L41_I2C_4),
+       SND_PCI_QUIRK(0x17aa, 0x38cb, "Y790 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38cd, "Y790 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38d2, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x38d3, "Yoga S990-16 Pro IMH YC Dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38d4, "Yoga S990-16 Pro IMH VECO Dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38d5, "Yoga S990-16 Pro IMH YC Quad", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38d6, "Yoga S990-16 Pro IMH VECO Quad", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38d7, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x38df, "Yoga Y990 Intel YC Dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
+       SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
+       SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TXNW2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C),
+       SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
+       SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
+       SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
+       SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x504a, "ThinkPad X260", ALC292_FIXUP_TPT440_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
+       SND_PCI_QUIRK(0x17aa, 0x5050, "Thinkpad T560p", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x5051, "Thinkpad L460", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x5053, "Thinkpad T460", ALC292_FIXUP_TPT460),
+       SND_PCI_QUIRK(0x17aa, 0x505d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x505f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x5062, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x508b, "Thinkpad X12 Gen 1", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
+       SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
+       SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
+       SND_PCI_QUIRK(0x17aa, 0x9e56, "Lenovo ZhaoYang CF4620Z", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1849, 0x0269, "Positivo Master C6400", ALC269VB_FIXUP_ASUS_ZENBOOK),
+       SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
+       SND_PCI_QUIRK(0x1849, 0xa233, "Positivo Master C6300", ALC269_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1854, 0x0440, "LG CQ6", ALC256_FIXUP_HEADPHONE_AMP_VOL),
+       SND_PCI_QUIRK(0x1854, 0x0441, "LG CQ6 AIO", ALC256_FIXUP_HEADPHONE_AMP_VOL),
+       SND_PCI_QUIRK(0x1854, 0x0488, "LG gram 16 (16Z90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+       SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
+       SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
+       SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
+       SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
+       SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
+       SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
+       SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
+       SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
+       SND_PCI_QUIRK(0x1c6c, 0x122a, "Positivo N14AP7", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x1c6c, 0x1251, "Positivo N14KP6-TG", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS),
+       SND_PCI_QUIRK(0x1d05, 0x1096, "TongFang GMxMRxx", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1d05, 0x1100, "TongFang GKxNRxx", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1d05, 0x1111, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1d05, 0x1119, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1d05, 0x1129, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1d05, 0x1147, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1d05, 0x115c, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1d05, 0x121b, "TongFang GMxAGxx", ALC269_FIXUP_NO_SHUTUP),
+       SND_PCI_QUIRK(0x1d05, 0x1387, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d05, 0x1409, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
+       SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
+       SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+       SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13),
+       SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
+       SND_PCI_QUIRK(0x2782, 0x1407, "Positivo P15X", ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC),
+       SND_PCI_QUIRK(0x2782, 0x1409, "Positivo K116J", ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC),
+       SND_PCI_QUIRK(0x2782, 0x1701, "Infinix Y4 Max", ALC269VC_FIXUP_INFINIX_Y4_MAX),
+       SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX),
+       SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME),
+       SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK),
+       SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
+       SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
+       SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10),
+       SND_PCI_QUIRK(0x8086, 0x3038, "Intel NUC 13", ALC295_FIXUP_CHROME_BOOK),
+       SND_PCI_QUIRK(0xf111, 0x0001, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0xf111, 0x0006, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0xf111, 0x0009, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0xf111, 0x000c, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
+
+#if 0
+       /* Below is a quirk table taken from the old code.
+        * Basically the device should work as is without the fixup table.
+        * If BIOS doesn't give a proper info, enable the corresponding
+        * fixup entry.
+        */
+       SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
+                     ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_FIXUP_DMIC),
+       SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_AMIC),
+       SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_FIXUP_DMIC),
+       SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_FIXUP_DMIC),
+#endif
+       {}
+};
+
+static const struct hda_quirk alc269_fixup_vendor_tbl[] = {
+       SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
+       SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
+       SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
+       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo XPAD", ALC269_FIXUP_LENOVO_XPAD_ACPI),
+       SND_PCI_QUIRK_VENDOR(0x19e5, "Huawei Matebook", ALC255_FIXUP_MIC_MUTE_LED),
+       {}
+};
+
+static const struct hda_model_fixup alc269_fixup_models[] = {
+       {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
+       {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
+       {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"},
+       {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
+       {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
+       {.id = ALC269_FIXUP_HEADSET_MIC, .name = "headset-mic"},
+       {.id = ALC269_FIXUP_HEADSET_MODE, .name = "headset-mode"},
+       {.id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC, .name = "headset-mode-no-hp-mic"},
+       {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
+       {.id = ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST, .name = "lenovo-dock-limit-boost"},
+       {.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
+       {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic1-led"},
+       {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+       {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"},
+       {.id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, .name = "dell-headset3"},
+       {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, .name = "dell-headset4"},
+       {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET, .name = "dell-headset4-quiet"},
+       {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
+       {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
+       {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
+       {.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
+       {.id = ALC292_FIXUP_TPT460, .name = "tpt460"},
+       {.id = ALC298_FIXUP_TPT470_DOCK_FIX, .name = "tpt470-dock-fix"},
+       {.id = ALC298_FIXUP_TPT470_DOCK, .name = "tpt470-dock"},
+       {.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
+       {.id = ALC700_FIXUP_INTEL_REFERENCE, .name = "alc700-ref"},
+       {.id = ALC269_FIXUP_SONY_VAIO, .name = "vaio"},
+       {.id = ALC269_FIXUP_DELL_M101Z, .name = "dell-m101z"},
+       {.id = ALC269_FIXUP_ASUS_G73JW, .name = "asus-g73jw"},
+       {.id = ALC269_FIXUP_LENOVO_EAPD, .name = "lenovo-eapd"},
+       {.id = ALC275_FIXUP_SONY_HWEQ, .name = "sony-hweq"},
+       {.id = ALC269_FIXUP_PCM_44K, .name = "pcm44k"},
+       {.id = ALC269_FIXUP_LIFEBOOK, .name = "lifebook"},
+       {.id = ALC269_FIXUP_LIFEBOOK_EXTMIC, .name = "lifebook-extmic"},
+       {.id = ALC269_FIXUP_LIFEBOOK_HP_PIN, .name = "lifebook-hp-pin"},
+       {.id = ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC, .name = "lifebook-u7x7"},
+       {.id = ALC269VB_FIXUP_AMIC, .name = "alc269vb-amic"},
+       {.id = ALC269VB_FIXUP_DMIC, .name = "alc269vb-dmic"},
+       {.id = ALC269_FIXUP_HP_MUTE_LED_MIC1, .name = "hp-mute-led-mic1"},
+       {.id = ALC269_FIXUP_HP_MUTE_LED_MIC2, .name = "hp-mute-led-mic2"},
+       {.id = ALC269_FIXUP_HP_MUTE_LED_MIC3, .name = "hp-mute-led-mic3"},
+       {.id = ALC269_FIXUP_HP_GPIO_MIC1_LED, .name = "hp-gpio-mic1"},
+       {.id = ALC269_FIXUP_HP_LINE1_MIC1_LED, .name = "hp-line1-mic1"},
+       {.id = ALC269_FIXUP_NO_SHUTUP, .name = "noshutup"},
+       {.id = ALC286_FIXUP_SONY_MIC_NO_PRESENCE, .name = "sony-nomic"},
+       {.id = ALC269_FIXUP_ASPIRE_HEADSET_MIC, .name = "aspire-headset-mic"},
+       {.id = ALC269_FIXUP_ASUS_X101, .name = "asus-x101"},
+       {.id = ALC271_FIXUP_HP_GATE_MIC_JACK, .name = "acer-ao7xx"},
+       {.id = ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572, .name = "acer-aspire-e1"},
+       {.id = ALC269_FIXUP_ACER_AC700, .name = "acer-ac700"},
+       {.id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST, .name = "limit-mic-boost"},
+       {.id = ALC269VB_FIXUP_ASUS_ZENBOOK, .name = "asus-zenbook"},
+       {.id = ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A, .name = "asus-zenbook-ux31a"},
+       {.id = ALC269VB_FIXUP_ORDISSIMO_EVE2, .name = "ordissimo"},
+       {.id = ALC282_FIXUP_ASUS_TX300, .name = "asus-tx300"},
+       {.id = ALC283_FIXUP_INT_MIC, .name = "alc283-int-mic"},
+       {.id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK, .name = "mono-speakers"},
+       {.id = ALC290_FIXUP_SUBWOOFER_HSJACK, .name = "alc290-subwoofer"},
+       {.id = ALC269_FIXUP_THINKPAD_ACPI, .name = "thinkpad"},
+       {.id = ALC269_FIXUP_LENOVO_XPAD_ACPI, .name = "lenovo-xpad-led"},
+       {.id = ALC269_FIXUP_DMIC_THINKPAD_ACPI, .name = "dmic-thinkpad"},
+       {.id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE, .name = "alc255-acer"},
+       {.id = ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc255-asus"},
+       {.id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc255-dell1"},
+       {.id = ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "alc255-dell2"},
+       {.id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc293-dell1"},
+       {.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"},
+       {.id = ALC255_FIXUP_MIC_MUTE_LED, .name = "alc255-dell-mute"},
+       {.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"},
+       {.id = ALC269VB_FIXUP_ASPIRE_E1_COEF, .name = "aspire-e1-coef"},
+       {.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"},
+       {.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
+       {.id = ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, .name = "hp-gpio2-hotkey"},
+       {.id = ALC280_FIXUP_HP_DOCK_PINS, .name = "hp-dock-pins"},
+       {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic"},
+       {.id = ALC280_FIXUP_HP_9480M, .name = "hp-9480m"},
+       {.id = ALC288_FIXUP_DELL_HEADSET_MODE, .name = "alc288-dell-headset"},
+       {.id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc288-dell1"},
+       {.id = ALC288_FIXUP_DELL_XPS_13, .name = "alc288-dell-xps13"},
+       {.id = ALC292_FIXUP_DELL_E7X, .name = "dell-e7x"},
+       {.id = ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK, .name = "alc293-dell"},
+       {.id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc298-dell1"},
+       {.id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, .name = "alc298-dell-aio"},
+       {.id = ALC275_FIXUP_DELL_XPS, .name = "alc275-dell-xps"},
+       {.id = ALC293_FIXUP_LENOVO_SPK_NOISE, .name = "lenovo-spk-noise"},
+       {.id = ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, .name = "lenovo-hotkey"},
+       {.id = ALC255_FIXUP_DELL_SPK_NOISE, .name = "dell-spk-noise"},
+       {.id = ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc225-dell1"},
+       {.id = ALC295_FIXUP_DISABLE_DAC3, .name = "alc295-disable-dac3"},
+       {.id = ALC285_FIXUP_SPEAKER2_TO_DAC1, .name = "alc285-speaker2-to-dac1"},
+       {.id = ALC280_FIXUP_HP_HEADSET_MIC, .name = "alc280-hp-headset"},
+       {.id = ALC221_FIXUP_HP_FRONT_MIC, .name = "alc221-hp-mic"},
+       {.id = ALC298_FIXUP_SPK_VOLUME, .name = "alc298-spk-volume"},
+       {.id = ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, .name = "dell-inspiron-7559"},
+       {.id = ALC269_FIXUP_ATIV_BOOK_8, .name = "ativ-book"},
+       {.id = ALC221_FIXUP_HP_MIC_NO_PRESENCE, .name = "alc221-hp-mic"},
+       {.id = ALC256_FIXUP_ASUS_HEADSET_MODE, .name = "alc256-asus-headset"},
+       {.id = ALC256_FIXUP_ASUS_MIC, .name = "alc256-asus-mic"},
+       {.id = ALC256_FIXUP_ASUS_AIO_GPIO2, .name = "alc256-asus-aio"},
+       {.id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc233-asus"},
+       {.id = ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, .name = "alc233-eapd"},
+       {.id = ALC294_FIXUP_LENOVO_MIC_LOCATION, .name = "alc294-lenovo-mic"},
+       {.id = ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, .name = "alc225-wyse"},
+       {.id = ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, .name = "alc274-dell-aio"},
+       {.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
+       {.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
+       {.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
+       {.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-headset-jack"},
+       {.id = ALC295_FIXUP_CHROME_BOOK, .name = "alc-chrome-book"},
+       {.id = ALC256_FIXUP_CHROME_BOOK, .name = "alc-2024y-chromebook"},
+       {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"},
+       {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"},
+       {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"},
+       {.id = ALC298_FIXUP_SAMSUNG_AMP, .name = "alc298-samsung-amp"},
+       {.id = ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS, .name = "alc298-samsung-amp-v2-2-amps"},
+       {.id = ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS, .name = "alc298-samsung-amp-v2-4-amps"},
+       {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"},
+       {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"},
+       {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"},
+       {.id = ALC245_FIXUP_HP_X360_AMP, .name = "alc245-hp-x360-amp"},
+       {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"},
+       {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"},
+       {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"},
+       {.id = ALC285_FIXUP_HP_SPECTRE_X360_DF1, .name = "alc285-hp-spectre-x360-df1"},
+       {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"},
+       {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
+       {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"},
+       {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"},
+       {.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"},
+       {.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"},
+       {.id = ALC236_FIXUP_LENOVO_INV_DMIC, .name = "alc236-fixup-lenovo-inv-mic"},
+       {.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"},
+       {}
+};
+#define ALC225_STANDARD_PINS \
+       {0x21, 0x04211020}
+
+#define ALC256_STANDARD_PINS \
+       {0x12, 0x90a60140}, \
+       {0x14, 0x90170110}, \
+       {0x21, 0x02211020}
+
+#define ALC282_STANDARD_PINS \
+       {0x14, 0x90170110}
+
+#define ALC290_STANDARD_PINS \
+       {0x12, 0x99a30130}
+
+#define ALC292_STANDARD_PINS \
+       {0x14, 0x90170110}, \
+       {0x15, 0x0221401f}
+
+#define ALC295_STANDARD_PINS \
+       {0x12, 0xb7a60130}, \
+       {0x14, 0x90170110}, \
+       {0x21, 0x04211020}
+
+#define ALC298_STANDARD_PINS \
+       {0x12, 0x90a60130}, \
+       {0x21, 0x03211020}
+
+static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
+       SND_HDA_PIN_QUIRK(0x10ec0221, 0x103c, "HP Workstation", ALC221_FIXUP_HP_HEADSET_MIC,
+               {0x14, 0x01014020},
+               {0x17, 0x90170110},
+               {0x18, 0x02a11030},
+               {0x19, 0x0181303F},
+               {0x21, 0x0221102f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
+               {0x12, 0x90a601c0},
+               {0x14, 0x90171120},
+               {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x1b, 0x90a70130},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
+               {0x1a, 0x90a70130},
+               {0x1b, 0x90170110},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC225_STANDARD_PINS,
+               {0x12, 0xb7a60130},
+               {0x14, 0x901701a0}),
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC225_STANDARD_PINS,
+               {0x12, 0xb7a60130},
+               {0x14, 0x901701b0}),
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC225_STANDARD_PINS,
+               {0x12, 0xb7a60150},
+               {0x14, 0x901701a0}),
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC225_STANDARD_PINS,
+               {0x12, 0xb7a60150},
+               {0x14, 0x901701b0}),
+       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC225_STANDARD_PINS,
+               {0x12, 0xb7a60130},
+               {0x1b, 0x90170110}),
+       SND_HDA_PIN_QUIRK(0x10ec0233, 0x8086, "Intel NUC Skull Canyon", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x1b, 0x01111010},
+               {0x1e, 0x01451130},
+               {0x21, 0x02211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
+               {0x12, 0x90a60140},
+               {0x14, 0x90170110},
+               {0x19, 0x02a11030},
+               {0x21, 0x02211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
+               {0x14, 0x90170110},
+               {0x19, 0x02a11030},
+               {0x1a, 0x02a11040},
+               {0x1b, 0x01014020},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
+               {0x14, 0x90170110},
+               {0x19, 0x02a11030},
+               {0x1a, 0x02a11040},
+               {0x1b, 0x01011020},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
+               {0x14, 0x90170110},
+               {0x19, 0x02a11020},
+               {0x1a, 0x02a11030},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC,
+               {0x21, 0x02211010}),
+       SND_HDA_PIN_QUIRK(0x10ec0236, 0x103c, "HP", ALC256_FIXUP_HP_HEADSET_MIC,
+               {0x14, 0x90170110},
+               {0x19, 0x02a11020},
+               {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x21, 0x02211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170130},
+               {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60140},
+               {0x14, 0x90170110},
+               {0x21, 0x02211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60160},
+               {0x14, 0x90170120},
+               {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x1b, 0x02011020},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x1b, 0x01011020},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170130},
+               {0x1b, 0x01014020},
+               {0x21, 0x0221103f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170130},
+               {0x1b, 0x01011020},
+               {0x21, 0x0221103f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170130},
+               {0x1b, 0x02011020},
+               {0x21, 0x0221103f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170150},
+               {0x1b, 0x02011020},
+               {0x21, 0x0221105f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x14, 0x90170110},
+               {0x1b, 0x01014020},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60160},
+               {0x14, 0x90170120},
+               {0x17, 0x90170140},
+               {0x21, 0x0321102f}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60160},
+               {0x14, 0x90170130},
+               {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60160},
+               {0x14, 0x90170140},
+               {0x21, 0x02211050}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60170},
+               {0x14, 0x90170120},
+               {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60170},
+               {0x14, 0x90170130},
+               {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60170},
+               {0x14, 0x90171130},
+               {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60170},
+               {0x14, 0x90170140},
+               {0x21, 0x02211050}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5548", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60180},
+               {0x14, 0x90170130},
+               {0x21, 0x02211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5565", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60180},
+               {0x14, 0x90170120},
+               {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x1b, 0x01011020},
+               {0x21, 0x02211010}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
+               {0x14, 0x90170110},
+               {0x1b, 0x90a70130},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
+               {0x14, 0x90170110},
+               {0x1b, 0x90a70130},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
+               {0x12, 0x90a60130},
+               {0x14, 0x90170110},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
+               {0x12, 0x90a60130},
+               {0x14, 0x90170110},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
+               {0x1a, 0x90a70130},
+               {0x1b, 0x90170110},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x103c, "HP", ALC256_FIXUP_HP_HEADSET_MIC,
+               {0x14, 0x90170110},
+               {0x19, 0x02a11020},
+               {0x21, 0x0221101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0274, 0x103c, "HP", ALC274_FIXUP_HP_HEADSET_MIC,
+               {0x17, 0x90170110},
+               {0x19, 0x03a11030},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
+               {0x12, 0x90a60130},
+               {0x14, 0x90170110},
+               {0x15, 0x0421101f},
+               {0x1a, 0x04a11020}),
+       SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED,
+               {0x12, 0x90a60140},
+               {0x14, 0x90170110},
+               {0x15, 0x0421101f},
+               {0x18, 0x02811030},
+               {0x1a, 0x04a1103f},
+               {0x1b, 0x02011020}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x19, 0x03a11020},
+               {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x19, 0x03a11020},
+               {0x21, 0x03211040}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x19, 0x03a11030},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x99a30130},
+               {0x19, 0x04a11020},
+               {0x21, 0x0421101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x90a60140},
+               {0x19, 0x04a11030},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x1025, "Acer", ALC282_FIXUP_ACER_DISABLE_LINEOUT,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x90a609c0},
+               {0x18, 0x03a11830},
+               {0x19, 0x04a19831},
+               {0x1a, 0x0481303f},
+               {0x1b, 0x04211020},
+               {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0282, 0x1025, "Acer", ALC282_FIXUP_ACER_DISABLE_LINEOUT,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x90a60940},
+               {0x18, 0x03a11830},
+               {0x19, 0x04a19831},
+               {0x1a, 0x0481303f},
+               {0x1b, 0x04211020},
+               {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x90a60130},
+               {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60160},
+               {0x14, 0x90170120},
+               {0x21, 0x02211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC282_STANDARD_PINS,
+               {0x12, 0x90a60130},
+               {0x19, 0x03a11020},
+               {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE,
+               {0x12, 0x90a60130},
+               {0x14, 0x90170110},
+               {0x19, 0x04a11040},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE,
+               {0x14, 0x90170110},
+               {0x19, 0x04a11040},
+               {0x1d, 0x40600001},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
+               {0x14, 0x90170110},
+               {0x19, 0x04a11040},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_HEADSET_JACK,
+               {0x14, 0x90170110},
+               {0x17, 0x90170111},
+               {0x19, 0x03a11030},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC287_FIXUP_THINKPAD_I2S_SPK,
+               {0x17, 0x90170110},
+               {0x19, 0x03a11030},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC287_FIXUP_THINKPAD_I2S_SPK,
+               {0x17, 0x90170110}, /* 0x231f with RTK I2S AMP */
+               {0x19, 0x04a11040},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0286, 0x1025, "Acer", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE,
+               {0x12, 0x90a60130},
+               {0x17, 0x90170110},
+               {0x21, 0x02211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x12, 0x90a60120},
+               {0x14, 0x90170110},
+               {0x21, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x15, 0x04211040},
+               {0x18, 0x90170112},
+               {0x1a, 0x04a11020}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x15, 0x04211040},
+               {0x18, 0x90170110},
+               {0x1a, 0x04a11020}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x15, 0x0421101f},
+               {0x1a, 0x04a11020}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x15, 0x04211020},
+               {0x1a, 0x04a11040}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x90170110},
+               {0x15, 0x04211020},
+               {0x1a, 0x04a11040}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x90170110},
+               {0x15, 0x04211020},
+               {0x1a, 0x04a11020}),
+       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
+               ALC290_STANDARD_PINS,
+               {0x14, 0x90170110},
+               {0x15, 0x0421101f},
+               {0x1a, 0x04a11020}),
+       SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x12, 0x90a60140},
+               {0x16, 0x01014020},
+               {0x19, 0x01a19030}),
+       SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x12, 0x90a60140},
+               {0x16, 0x01014020},
+               {0x18, 0x02a19031},
+               {0x19, 0x01a1903e}),
+       SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x12, 0x90a60140}),
+       SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x13, 0x90a60140},
+               {0x16, 0x21014020},
+               {0x19, 0x21a19030}),
+       SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC292_STANDARD_PINS,
+               {0x13, 0x90a60140}),
+       SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_HPE,
+               {0x17, 0x90170110},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_MIC,
+               {0x14, 0x90170110},
+               {0x1b, 0x90a70130},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_SPK,
+               {0x12, 0x90a60130},
+               {0x17, 0x90170110},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_SPK,
+               {0x12, 0x90a60130},
+               {0x17, 0x90170110},
+               {0x21, 0x04211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1043, "ASUS", ALC294_FIXUP_ASUS_SPK,
+               {0x12, 0x90a60130},
+               {0x17, 0x90170110},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1043, "ASUS", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
+               {0x12, 0x90a60120},
+               {0x17, 0x90170110},
+               {0x21, 0x04211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1043, "ASUS", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
+               {0x12, 0x90a60130},
+               {0x17, 0x90170110},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1043, "ASUS", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
+               {0x12, 0x90a60130},
+               {0x17, 0x90170110},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC298_STANDARD_PINS,
+               {0x17, 0x90170110}),
+       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC298_STANDARD_PINS,
+               {0x17, 0x90170140}),
+       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
+               ALC298_STANDARD_PINS,
+               {0x17, 0x90170150}),
+       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME,
+               {0x12, 0xb7a60140},
+               {0x13, 0xb7a60150},
+               {0x17, 0x90170110},
+               {0x1a, 0x03011020},
+               {0x21, 0x03211030}),
+       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE,
+               {0x12, 0xb7a60140},
+               {0x17, 0x90170110},
+               {0x1a, 0x03a11030},
+               {0x21, 0x03211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0299, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+               ALC225_STANDARD_PINS,
+               {0x12, 0xb7a60130},
+               {0x17, 0x90170110}),
+       SND_HDA_PIN_QUIRK(0x10ec0623, 0x17aa, "Lenovo", ALC283_FIXUP_HEADSET_MIC,
+               {0x14, 0x01014010},
+               {0x17, 0x90170120},
+               {0x18, 0x02a11030},
+               {0x19, 0x02a1103f},
+               {0x21, 0x0221101f}),
+       {}
+};
+
+/* This is the fallback pin_fixup_tbl for alc269 family, to make the tbl match
+ * more machines, don't need to match all valid pins, just need to match
+ * all the pins defined in the tbl. Just because of this reason, it is possible
+ * that a single machine matches multiple tbls, so there is one limitation:
+ *   at most one tbl is allowed to define for the same vendor and same codec
+ */
+static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = {
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1025, "Acer", ALC2XX_FIXUP_HEADSET_MIC,
+               {0x19, 0x40000000}),
+       SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
+               {0x19, 0x40000000},
+               {0x1b, 0x40000000}),
+       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET,
+               {0x19, 0x40000000},
+               {0x1b, 0x40000000}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
+               {0x19, 0x40000000},
+               {0x1a, 0x40000000}),
+       SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
+               {0x19, 0x40000000},
+               {0x1a, 0x40000000}),
+       SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
+               {0x19, 0x40000000},
+               {0x1a, 0x40000000}),
+       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC2XX_FIXUP_HEADSET_MIC,
+               {0x19, 0x40000000}),
+       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1558, "Clevo", ALC2XX_FIXUP_HEADSET_MIC,
+               {0x19, 0x40000000}),
+       {}
+};
+
+static void alc269_fill_coef(struct hda_codec *codec)
+{
+       struct alc_spec *spec = codec->spec;
+       int val;
+
+       if (spec->codec_variant != ALC269_TYPE_ALC269VB)
+               return;
+
+       if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
+               alc_write_coef_idx(codec, 0xf, 0x960b);
+               alc_write_coef_idx(codec, 0xe, 0x8817);
+       }
+
+       if ((alc_get_coef0(codec) & 0x00ff) == 0x016) {
+               alc_write_coef_idx(codec, 0xf, 0x960b);
+               alc_write_coef_idx(codec, 0xe, 0x8814);
+       }
+
+       if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
+               /* Power up output pin */
+               alc_update_coef_idx(codec, 0x04, 0, 1<<11);
+       }
+
+       if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
+               val = alc_read_coef_idx(codec, 0xd);
+               if (val != -1 && (val & 0x0c00) >> 10 != 0x1) {
+                       /* Capless ramp up clock control */
+                       alc_write_coef_idx(codec, 0xd, val | (1<<10));
+               }
+               val = alc_read_coef_idx(codec, 0x17);
+               if (val != -1 && (val & 0x01c0) >> 6 != 0x4) {
+                       /* Class D power on reset */
+                       alc_write_coef_idx(codec, 0x17, val | (1<<7));
+               }
+       }
+
+       /* HP */
+       alc_update_coef_idx(codec, 0x4, 0, 1<<11);
+}
+
+/*
+ */
+static int patch_alc269(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err;
+
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->gen.shared_mic_vref_pin = 0x18;
+       codec->power_save_node = 0;
+       spec->en_3kpull_low = true;
+
+       codec->patch_ops.suspend = alc269_suspend;
+       codec->patch_ops.resume = alc269_resume;
+       spec->shutup = alc_default_shutup;
+       spec->init_hook = alc_default_init;
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0269:
+               spec->codec_variant = ALC269_TYPE_ALC269VA;
+               switch (alc_get_coef0(codec) & 0x00f0) {
+               case 0x0010:
+                       if (codec->bus->pci &&
+                           codec->bus->pci->subsystem_vendor == 0x1025 &&
+                           spec->cdefine.platform_type == 1)
+                               err = alc_codec_rename(codec, "ALC271X");
+                       spec->codec_variant = ALC269_TYPE_ALC269VB;
+                       break;
+               case 0x0020:
+                       if (codec->bus->pci &&
+                           codec->bus->pci->subsystem_vendor == 0x17aa &&
+                           codec->bus->pci->subsystem_device == 0x21f3)
+                               err = alc_codec_rename(codec, "ALC3202");
+                       spec->codec_variant = ALC269_TYPE_ALC269VC;
+                       break;
+               case 0x0030:
+                       spec->codec_variant = ALC269_TYPE_ALC269VD;
+                       break;
+               default:
+                       alc_fix_pll_init(codec, 0x20, 0x04, 15);
+               }
+               if (err < 0)
+                       goto error;
+               spec->shutup = alc269_shutup;
+               spec->init_hook = alc269_fill_coef;
+               alc269_fill_coef(codec);
+               break;
+
+       case 0x10ec0280:
+       case 0x10ec0290:
+               spec->codec_variant = ALC269_TYPE_ALC280;
+               break;
+       case 0x10ec0282:
+               spec->codec_variant = ALC269_TYPE_ALC282;
+               spec->shutup = alc282_shutup;
+               spec->init_hook = alc282_init;
+               break;
+       case 0x10ec0233:
+       case 0x10ec0283:
+               spec->codec_variant = ALC269_TYPE_ALC283;
+               spec->shutup = alc283_shutup;
+               spec->init_hook = alc283_init;
+               break;
+       case 0x10ec0284:
+       case 0x10ec0292:
+               spec->codec_variant = ALC269_TYPE_ALC284;
+               break;
+       case 0x10ec0293:
+               spec->codec_variant = ALC269_TYPE_ALC293;
+               break;
+       case 0x10ec0286:
+       case 0x10ec0288:
+               spec->codec_variant = ALC269_TYPE_ALC286;
+               break;
+       case 0x10ec0298:
+               spec->codec_variant = ALC269_TYPE_ALC298;
+               break;
+       case 0x10ec0235:
+       case 0x10ec0255:
+               spec->codec_variant = ALC269_TYPE_ALC255;
+               spec->shutup = alc256_shutup;
+               spec->init_hook = alc256_init;
+               break;
+       case 0x10ec0230:
+       case 0x10ec0236:
+       case 0x10ec0256:
+       case 0x19e58326:
+               spec->codec_variant = ALC269_TYPE_ALC256;
+               spec->shutup = alc256_shutup;
+               spec->init_hook = alc256_init;
+               spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
+               if (codec->core.vendor_id == 0x10ec0236 &&
+                   codec->bus->pci->vendor != PCI_VENDOR_ID_AMD)
+                       spec->en_3kpull_low = false;
+               break;
+       case 0x10ec0257:
+               spec->codec_variant = ALC269_TYPE_ALC257;
+               spec->shutup = alc256_shutup;
+               spec->init_hook = alc256_init;
+               spec->gen.mixer_nid = 0;
+               spec->en_3kpull_low = false;
+               break;
+       case 0x10ec0215:
+       case 0x10ec0245:
+       case 0x10ec0285:
+       case 0x10ec0289:
+               if (alc_get_coef0(codec) & 0x0010)
+                       spec->codec_variant = ALC269_TYPE_ALC245;
+               else
+                       spec->codec_variant = ALC269_TYPE_ALC215;
+               spec->shutup = alc225_shutup;
+               spec->init_hook = alc225_init;
+               spec->gen.mixer_nid = 0;
+               break;
+       case 0x10ec0225:
+       case 0x10ec0295:
+       case 0x10ec0299:
+               spec->codec_variant = ALC269_TYPE_ALC225;
+               spec->shutup = alc225_shutup;
+               spec->init_hook = alc225_init;
+               spec->gen.mixer_nid = 0; /* no loopback on ALC225, ALC295 and ALC299 */
+               break;
+       case 0x10ec0287:
+               spec->codec_variant = ALC269_TYPE_ALC287;
+               spec->shutup = alc225_shutup;
+               spec->init_hook = alc225_init;
+               spec->gen.mixer_nid = 0; /* no loopback on ALC287 */
+               break;
+       case 0x10ec0234:
+       case 0x10ec0274:
+       case 0x10ec0294:
+               spec->codec_variant = ALC269_TYPE_ALC294;
+               spec->gen.mixer_nid = 0; /* ALC2x4 does not have any loopback mixer path */
+               alc_update_coef_idx(codec, 0x6b, 0x0018, (1<<4) | (1<<3)); /* UAJ MIC Vref control by verb */
+               spec->init_hook = alc294_init;
+               break;
+       case 0x10ec0300:
+               spec->codec_variant = ALC269_TYPE_ALC300;
+               spec->gen.mixer_nid = 0; /* no loopback on ALC300 */
+               break;
+       case 0x10ec0222:
+       case 0x10ec0623:
+               spec->codec_variant = ALC269_TYPE_ALC623;
+               spec->shutup = alc222_shutup;
+               spec->init_hook = alc222_init;
+               break;
+       case 0x10ec0700:
+       case 0x10ec0701:
+       case 0x10ec0703:
+       case 0x10ec0711:
+               spec->codec_variant = ALC269_TYPE_ALC700;
+               spec->gen.mixer_nid = 0; /* ALC700 does not have any loopback mixer path */
+               alc_update_coef_idx(codec, 0x4a, 1 << 15, 0); /* Combo jack auto trigger control */
+               spec->init_hook = alc294_init;
+               break;
+
+       }
+
+       if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
+               spec->has_alc5505_dsp = 1;
+               spec->init_hook = alc5505_dsp_init;
+       }
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, alc269_fixup_models,
+                      alc269_fixup_tbl, alc269_fixups);
+       /* FIXME: both TX300 and ROG Strix G17 have the same SSID, and
+        * the quirk breaks the latter (bko#214101).
+        * Clear the wrong entry.
+        */
+       if (codec->fixup_id == ALC282_FIXUP_ASUS_TX300 &&
+           codec->core.vendor_id == 0x10ec0294) {
+               codec_dbg(codec, "Clear wrong fixup for ASUS ROG Strix G17\n");
+               codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
+       }
+
+       snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups, true);
+       snd_hda_pick_pin_fixup(codec, alc269_fallback_pin_fixup_tbl, alc269_fixups, false);
+       snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl,
+                          alc269_fixups);
+
+       /*
+        * Check whether ACPI describes companion amplifiers that require
+        * component binding
+        */
+       find_cirrus_companion_amps(codec);
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       alc_auto_parse_customize_define(codec);
+
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
+       /* automatic parse from the BIOS config */
+       err = alc269_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid) {
+               err = set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT);
+               if (err < 0)
+                       goto error;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+/*
+ * ALC861
+ */
+
+static int alc861_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
+       return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
+}
+
+/* Pin config fixes */
+enum {
+       ALC861_FIXUP_FSC_AMILO_PI1505,
+       ALC861_FIXUP_AMP_VREF_0F,
+       ALC861_FIXUP_NO_JACK_DETECT,
+       ALC861_FIXUP_ASUS_A6RP,
+       ALC660_FIXUP_ASUS_W7J,
+};
+
+/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
+static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
+                       const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       unsigned int val;
+
+       if (action != HDA_FIXUP_ACT_INIT)
+               return;
+       val = snd_hda_codec_get_pin_target(codec, 0x0f);
+       if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
+               val |= AC_PINCTL_IN_EN;
+       val |= AC_PINCTL_VREF_50;
+       snd_hda_set_pin_ctl(codec, 0x0f, val);
+       spec->gen.keep_vref_in_automute = 1;
+}
+
+/* suppress the jack-detection */
+static void alc_fixup_no_jack_detect(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               codec->no_jack_detect = 1;
+}
+
+static const struct hda_fixup alc861_fixups[] = {
+       [ALC861_FIXUP_FSC_AMILO_PI1505] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x0b, 0x0221101f }, /* HP */
+                       { 0x0f, 0x90170310 }, /* speaker */
+                       { }
+               }
+       },
+       [ALC861_FIXUP_AMP_VREF_0F] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc861_fixup_asus_amp_vref_0f,
+       },
+       [ALC861_FIXUP_NO_JACK_DETECT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_jack_detect,
+       },
+       [ALC861_FIXUP_ASUS_A6RP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc861_fixup_asus_amp_vref_0f,
+               .chained = true,
+               .chain_id = ALC861_FIXUP_NO_JACK_DETECT,
+       },
+       [ALC660_FIXUP_ASUS_W7J] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* ASUS W7J needs a magic pin setup on unused NID 0x10
+                        * for enabling outputs
+                        */
+                       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
+                       { }
+               },
+       }
+};
+
+static const struct hda_quirk alc861_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
+       SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
+       SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
+       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
+       SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
+       SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F),
+       SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
+       {}
+};
+
+/*
+ */
+static int patch_alc861(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err;
+
+       err = alc_alloc_spec(codec, 0x15);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x23;
+
+       spec->power_hook = alc_power_eapd;
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       /* automatic parse from the BIOS config */
+       err = alc861_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!spec->gen.no_analog) {
+               err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
+               if (err < 0)
+                       goto error;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+/*
+ * ALC861-VD support
+ *
+ * Based on ALC882
+ *
+ * In addition, an independent DAC
+ */
+static int alc861vd_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
+}
+
+enum {
+       ALC660VD_FIX_ASUS_GPIO1,
+       ALC861VD_FIX_DALLAS,
+};
+
+/* exclude VREF80 */
+static void alc861vd_fixup_dallas(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
+               snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
+       }
+}
+
+/* reset GPIO1 */
+static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->gpio_mask |= 0x02;
+       alc_fixup_gpio(codec, action, 0x01);
+}
+
+static const struct hda_fixup alc861vd_fixups[] = {
+       [ALC660VD_FIX_ASUS_GPIO1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc660vd_fixup_asus_gpio1,
+       },
+       [ALC861VD_FIX_DALLAS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc861vd_fixup_dallas,
+       },
+};
+
+static const struct hda_quirk alc861vd_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
+       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
+       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
+       {}
+};
+
+/*
+ */
+static int patch_alc861vd(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err;
+
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x23;
+
+       spec->shutup = alc_eapd_shutup;
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       /* automatic parse from the BIOS config */
+       err = alc861vd_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!spec->gen.no_analog) {
+               err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+               if (err < 0)
+                       goto error;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+/*
+ * ALC662 support
+ *
+ * ALC662 is almost identical with ALC880 but has cleaner and more flexible
+ * configuration.  Each pin widget can choose any input DACs and a mixer.
+ * Each ADC is connected from a mixer of all inputs.  This makes possible
+ * 6-channel independent captures.
+ *
+ * In addition, an independent DAC for the multi-playback (not used in this
+ * driver yet).
+ */
+
+/*
+ * BIOS auto configuration
+ */
+
+static int alc662_parse_auto_config(struct hda_codec *codec)
+{
+       static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
+       static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
+       static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
+       const hda_nid_t *ssids;
+
+       if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
+           codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
+           codec->core.vendor_id == 0x10ec0671)
+               ssids = alc663_ssids;
+       else
+               ssids = alc662_ssids;
+       return alc_parse_auto_config(codec, alc662_ignore, ssids);
+}
+
+static void alc272_fixup_mario(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
+                                     (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
+                                     (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                     (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                     (0 << AC_AMPCAP_MUTE_SHIFT)))
+               codec_warn(codec, "failed to override amp caps for NID 0x2\n");
+}
+
+static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
+       { .channels = 2,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
+       { .channels = 4,
+         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
+                  SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
+       { }
+};
+
+/* override the 2.1 chmap */
+static void alc_fixup_bass_chmap(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_BUILD) {
+               struct alc_spec *spec = codec->spec;
+               spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
+       }
+}
+
+/* avoid D3 for keeping GPIO up */
+static unsigned int gpio_led_power_filter(struct hda_codec *codec,
+                                         hda_nid_t nid,
+                                         unsigned int power_state)
+{
+       struct alc_spec *spec = codec->spec;
+       if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
+               return AC_PWRST_D0;
+       return power_state;
+}
+
+static void alc662_fixup_led_gpio1(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mute_led_polarity = 1;
+               codec->power_filter = gpio_led_power_filter;
+       }
+}
+
+static void alc662_usi_automute_hook(struct hda_codec *codec,
+                                        struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       int vref;
+       msleep(200);
+       snd_hda_gen_hp_automute(codec, jack);
+
+       vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
+       msleep(100);
+       snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
+                           vref);
+}
+
+static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               spec->gen.hp_automute_hook = alc662_usi_automute_hook;
+       }
+}
+
+static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
+                                       struct hda_jack_callback *cb)
+{
+       /* surround speakers at 0x1b already get muted automatically when
+        * headphones are plugged in, but we have to mute/unmute the remaining
+        * channels manually:
+        * 0x15 - front left/front right
+        * 0x18 - front center/ LFE
+        */
+       if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
+               snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
+               snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
+       } else {
+               snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
+               snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
+       }
+}
+
+static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
+                                       const struct hda_fixup *fix, int action)
+{
+    /* Pin 0x1b: shared headphones jack and surround speakers */
+       if (!is_jack_detectable(codec, 0x1b))
+               return;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_jack_detect_enable_callback(codec, 0x1b,
+                               alc662_aspire_ethos_mute_speakers);
+               /* subwoofer needs an extra GPIO setting to become audible */
+               alc_setup_gpio(codec, 0x02);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               /* Make sure to start in a correct state, i.e. if
+                * headphones have been plugged in before powering up the system
+                */
+               alc662_aspire_ethos_mute_speakers(codec, NULL);
+               break;
+       }
+}
+
+static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
+                                            const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       static const struct hda_pintbl pincfgs[] = {
+               { 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
+               { 0x1b, 0x0181304f },
+               { }
+       };
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               spec->gen.mixer_nid = 0;
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               snd_hda_apply_pincfgs(codec, pincfgs);
+               break;
+       case HDA_FIXUP_ACT_INIT:
+               alc_write_coef_idx(codec, 0x19, 0xa054);
+               break;
+       }
+}
+
+static void alc897_hp_automute_hook(struct hda_codec *codec,
+                                        struct hda_jack_callback *jack)
+{
+       struct alc_spec *spec = codec->spec;
+       int vref;
+
+       snd_hda_gen_hp_automute(codec, jack);
+       vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
+       snd_hda_set_pin_ctl(codec, 0x1b, vref);
+}
+
+static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+               spec->no_shutup_pins = 1;
+       }
+       if (action == HDA_FIXUP_ACT_PROBE) {
+               snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
+       }
+}
+
+static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct alc_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
+               spec->gen.hp_automute_hook = alc897_hp_automute_hook;
+       }
+}
+
+static const struct coef_fw alc668_coefs[] = {
+       WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),
+       WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80),
+       WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b,    0x0),
+       WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f),
+       WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001),
+       WRITE_COEF(0x13,    0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940),
+       WRITE_COEF(0x19,    0x0), WRITE_COEF(0x1a,    0x0), WRITE_COEF(0x1b,    0x0),
+       WRITE_COEF(0x1c,    0x0), WRITE_COEF(0x1d,    0x0), WRITE_COEF(0x1e, 0x7418),
+       WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468),
+       WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418),
+       WRITE_COEF(0x27,    0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00),
+       WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000),
+       WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac,    0x0),
+       WRITE_COEF(0xad,    0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480),
+       WRITE_COEF(0xb0,    0x0), WRITE_COEF(0xb1,    0x0), WRITE_COEF(0xb2,    0x0),
+       WRITE_COEF(0xb3,    0x0), WRITE_COEF(0xb4,    0x0), WRITE_COEF(0xb5, 0x1040),
+       WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697),
+       WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab),
+       WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02),
+       WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6),
+       {}
+};
+
+static void alc668_restore_default_value(struct hda_codec *codec)
+{
+       alc_process_coef_fw(codec, alc668_coefs);
+}
+
+enum {
+       ALC662_FIXUP_ASPIRE,
+       ALC662_FIXUP_LED_GPIO1,
+       ALC662_FIXUP_IDEAPAD,
+       ALC272_FIXUP_MARIO,
+       ALC662_FIXUP_CZC_ET26,
+       ALC662_FIXUP_CZC_P10T,
+       ALC662_FIXUP_SKU_IGNORE,
+       ALC662_FIXUP_HP_RP5800,
+       ALC662_FIXUP_ASUS_MODE1,
+       ALC662_FIXUP_ASUS_MODE2,
+       ALC662_FIXUP_ASUS_MODE3,
+       ALC662_FIXUP_ASUS_MODE4,
+       ALC662_FIXUP_ASUS_MODE5,
+       ALC662_FIXUP_ASUS_MODE6,
+       ALC662_FIXUP_ASUS_MODE7,
+       ALC662_FIXUP_ASUS_MODE8,
+       ALC662_FIXUP_NO_JACK_DETECT,
+       ALC662_FIXUP_ZOTAC_Z68,
+       ALC662_FIXUP_INV_DMIC,
+       ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
+       ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
+       ALC662_FIXUP_HEADSET_MODE,
+       ALC668_FIXUP_HEADSET_MODE,
+       ALC662_FIXUP_BASS_MODE4_CHMAP,
+       ALC662_FIXUP_BASS_16,
+       ALC662_FIXUP_BASS_1A,
+       ALC662_FIXUP_BASS_CHMAP,
+       ALC668_FIXUP_AUTO_MUTE,
+       ALC668_FIXUP_DELL_DISABLE_AAMIX,
+       ALC668_FIXUP_DELL_XPS13,
+       ALC662_FIXUP_ASUS_Nx50,
+       ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
+       ALC668_FIXUP_ASUS_Nx51,
+       ALC668_FIXUP_MIC_COEF,
+       ALC668_FIXUP_ASUS_G751,
+       ALC891_FIXUP_HEADSET_MODE,
+       ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+       ALC662_FIXUP_ACER_VERITON,
+       ALC892_FIXUP_ASROCK_MOBO,
+       ALC662_FIXUP_USI_FUNC,
+       ALC662_FIXUP_USI_HEADSET_MODE,
+       ALC662_FIXUP_LENOVO_MULTI_CODECS,
+       ALC669_FIXUP_ACER_ASPIRE_ETHOS,
+       ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
+       ALC671_FIXUP_HP_HEADSET_MIC2,
+       ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
+       ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
+       ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
+       ALC668_FIXUP_HEADSET_MIC,
+       ALC668_FIXUP_MIC_DET_COEF,
+       ALC897_FIXUP_LENOVO_HEADSET_MIC,
+       ALC897_FIXUP_HEADSET_MIC_PIN,
+       ALC897_FIXUP_HP_HSMIC_VERB,
+       ALC897_FIXUP_LENOVO_HEADSET_MODE,
+       ALC897_FIXUP_HEADSET_MIC_PIN2,
+       ALC897_FIXUP_UNIS_H3C_X500S,
+       ALC897_FIXUP_HEADSET_MIC_PIN3,
+};
+
+static const struct hda_fixup alc662_fixups[] = {
+       [ALC662_FIXUP_ASPIRE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x99130112 }, /* subwoofer */
+                       { }
+               }
+       },
+       [ALC662_FIXUP_LED_GPIO1] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc662_fixup_led_gpio1,
+       },
+       [ALC662_FIXUP_IDEAPAD] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x17, 0x99130112 }, /* subwoofer */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_LED_GPIO1,
+       },
+       [ALC272_FIXUP_MARIO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc272_fixup_mario,
+       },
+       [ALC662_FIXUP_CZC_ET26] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       {0x12, 0x403cc000},
+                       {0x14, 0x90170110}, /* speaker */
+                       {0x15, 0x411111f0},
+                       {0x16, 0x411111f0},
+                       {0x18, 0x01a19030}, /* mic */
+                       {0x19, 0x90a7013f}, /* int-mic */
+                       {0x1a, 0x01014020},
+                       {0x1b, 0x0121401f},
+                       {0x1c, 0x411111f0},
+                       {0x1d, 0x411111f0},
+                       {0x1e, 0x40478e35},
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_CZC_P10T] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
+                       {}
+               }
+       },
+       [ALC662_FIXUP_SKU_IGNORE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_sku_ignore,
+       },
+       [ALC662_FIXUP_HP_RP5800] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x0221201f }, /* HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_ASUS_MODE1] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x18, 0x01a19c20 }, /* mic */
+                       { 0x19, 0x99a3092f }, /* int-mic */
+                       { 0x21, 0x0121401f }, /* HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_ASUS_MODE2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x18, 0x01a19820 }, /* mic */
+                       { 0x19, 0x99a3092f }, /* int-mic */
+                       { 0x1b, 0x0121401f }, /* HP out */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_ASUS_MODE3] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0121441f }, /* HP */
+                       { 0x18, 0x01a19840 }, /* mic */
+                       { 0x19, 0x99a3094f }, /* int-mic */
+                       { 0x21, 0x01211420 }, /* HP2 */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_ASUS_MODE4] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x16, 0x99130111 }, /* speaker */
+                       { 0x18, 0x01a19840 }, /* mic */
+                       { 0x19, 0x99a3094f }, /* int-mic */
+                       { 0x21, 0x0121441f }, /* HP */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_ASUS_MODE5] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x0121441f }, /* HP */
+                       { 0x16, 0x99130111 }, /* speaker */
+                       { 0x18, 0x01a19840 }, /* mic */
+                       { 0x19, 0x99a3094f }, /* int-mic */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_ASUS_MODE6] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x15, 0x01211420 }, /* HP2 */
+                       { 0x18, 0x01a19840 }, /* mic */
+                       { 0x19, 0x99a3094f }, /* int-mic */
+                       { 0x1b, 0x0121441f }, /* HP */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_ASUS_MODE7] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x17, 0x99130111 }, /* speaker */
+                       { 0x18, 0x01a19840 }, /* mic */
+                       { 0x19, 0x99a3094f }, /* int-mic */
+                       { 0x1b, 0x01214020 }, /* HP */
+                       { 0x21, 0x0121401f }, /* HP */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_ASUS_MODE8] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x14, 0x99130110 }, /* speaker */
+                       { 0x12, 0x99a30970 }, /* int-mic */
+                       { 0x15, 0x01214020 }, /* HP */
+                       { 0x17, 0x99130111 }, /* speaker */
+                       { 0x18, 0x01a19840 }, /* mic */
+                       { 0x21, 0x0121401f }, /* HP */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_SKU_IGNORE
+       },
+       [ALC662_FIXUP_NO_JACK_DETECT] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_no_jack_detect,
+       },
+       [ALC662_FIXUP_ZOTAC_Z68] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x02214020 }, /* Front HP */
+                       { }
+               }
+       },
+       [ALC662_FIXUP_INV_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_inv_dmic,
+       },
+       [ALC668_FIXUP_DELL_XPS13] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_dell_xps13,
+               .chained = true,
+               .chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX
+       },
+       [ALC668_FIXUP_DELL_DISABLE_AAMIX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_disable_aamix,
+               .chained = true,
+               .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
+       },
+       [ALC668_FIXUP_AUTO_MUTE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_auto_mute_via_amp,
+               .chained = true,
+               .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
+       },
+       [ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+                       /* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_HEADSET_MODE
+       },
+       [ALC662_FIXUP_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_alc662,
+       },
+       [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+                       { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC668_FIXUP_HEADSET_MODE
+       },
+       [ALC668_FIXUP_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_alc668,
+       },
+       [ALC662_FIXUP_BASS_MODE4_CHMAP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_bass_chmap,
+               .chained = true,
+               .chain_id = ALC662_FIXUP_ASUS_MODE4
+       },
+       [ALC662_FIXUP_BASS_16] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       {0x16, 0x80106111}, /* bass speaker */
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_BASS_CHMAP,
+       },
+       [ALC662_FIXUP_BASS_1A] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       {0x1a, 0x80106111}, /* bass speaker */
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_BASS_CHMAP,
+       },
+       [ALC662_FIXUP_BASS_CHMAP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_bass_chmap,
+       },
+       [ALC662_FIXUP_ASUS_Nx50] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_auto_mute_via_amp,
+               .chained = true,
+               .chain_id = ALC662_FIXUP_BASS_1A
+       },
+       [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode_alc668,
+               .chain_id = ALC662_FIXUP_BASS_CHMAP
+       },
+       [ALC668_FIXUP_ASUS_Nx51] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+                       { 0x1a, 0x90170151 }, /* bass speaker */
+                       { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
+       },
+       [ALC668_FIXUP_MIC_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
+                       {}
+               },
+       },
+       [ALC668_FIXUP_ASUS_G751] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x16, 0x0421101f }, /* HP */
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC668_FIXUP_MIC_COEF
+       },
+       [ALC891_FIXUP_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc_fixup_headset_mode,
+       },
+       [ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
+                       { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC891_FIXUP_HEADSET_MODE
+       },
+       [ALC662_FIXUP_ACER_VERITON] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x50170120 }, /* no internal speaker */
+                       { }
+               }
+       },
+       [ALC892_FIXUP_ASROCK_MOBO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x40f000f0 }, /* disabled */
+                       { 0x16, 0x40f000f0 }, /* disabled */
+                       { }
+               }
+       },
+       [ALC662_FIXUP_USI_FUNC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc662_fixup_usi_headset_mic,
+       },
+       [ALC662_FIXUP_USI_HEADSET_MODE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
+                       { 0x18, 0x01a1903d },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_USI_FUNC
+       },
+       [ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
+       },
+       [ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc662_fixup_aspire_ethos_hp,
+       },
+       [ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x15, 0x92130110 }, /* front speakers */
+                       { 0x18, 0x99130111 }, /* center/subwoofer */
+                       { 0x1b, 0x11130012 }, /* surround plus jack for HP */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
+       },
+       [ALC671_FIXUP_HP_HEADSET_MIC2] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc671_fixup_hp_headset_mic2,
+       },
+       [ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_USI_FUNC
+       },
+       [ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
+                       { 0x1b, 0x0221144f },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC662_FIXUP_USI_FUNC
+       },
+       [ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1b, 0x04a1112c },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC668_FIXUP_HEADSET_MIC
+       },
+       [ALC668_FIXUP_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc269_fixup_headset_mic,
+               .chained = true,
+               .chain_id = ALC668_FIXUP_MIC_DET_COEF
+       },
+       [ALC668_FIXUP_MIC_DET_COEF] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
+                       {}
+               },
+       },
+       [ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc897_fixup_lenovo_headset_mic,
+       },
+       [ALC897_FIXUP_HEADSET_MIC_PIN] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x03a11050 },
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
+       },
+       [ALC897_FIXUP_HP_HSMIC_VERB] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+       },
+       [ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc897_fixup_lenovo_headset_mode,
+       },
+       [ALC897_FIXUP_HEADSET_MIC_PIN2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
+                       { }
+               },
+               .chained = true,
+               .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
+       },
+       [ALC897_FIXUP_UNIS_H3C_X500S] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       { 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 },
+                       {}
+               },
+       },
+       [ALC897_FIXUP_HEADSET_MIC_PIN3] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x19, 0x03a11050 }, /* use as headset mic */
+                       { }
+               },
+       },
+};
+
+static const struct hda_quirk alc662_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3),
+       SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
+       SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
+       SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
+       SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
+       SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
+       SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
+       SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
+       SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13),
+       SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13),
+       SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
+       SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+       SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+       SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
+       SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
+       SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
+       SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
+       SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
+       SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
+       SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
+       SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
+       SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+       SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
+       SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
+       SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
+       SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
+       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
+       SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
+       SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
+       SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
+       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
+       SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
+       SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
+       SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN),
+       SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
+       SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
+       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
+       SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
+       SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
+       SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
+       SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
+       SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
+       SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
+
+#if 0
+       /* Below is a quirk table taken from the old code.
+        * Basically the device should work as is without the fixup table.
+        * If BIOS doesn't give a proper info, enable the corresponding
+        * fixup entry.
+        */
+       SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
+       SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
+       SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
+       SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
+       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
+       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
+       SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
+       SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
+       SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
+#endif
+       {}
+};
+
+static const struct hda_model_fixup alc662_fixup_models[] = {
+       {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
+       {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
+       {.id = ALC272_FIXUP_MARIO, .name = "mario"},
+       {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
+       {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
+       {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
+       {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
+       {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
+       {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
+       {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
+       {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
+       {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
+       {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
+       {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
+       {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
+       {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
+       {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
+       {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
+       {.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
+       {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
+       {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
+       {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
+       {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
+       {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
+       {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
+       {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
+       {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
+       {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
+       {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
+       {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
+       {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
+       {.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
+       {.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"},
+       {}
+};
+
+static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
+       SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+               {0x17, 0x02211010},
+               {0x18, 0x01a19030},
+               {0x1a, 0x01813040},
+               {0x21, 0x01014020}),
+       SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
+               {0x16, 0x01813030},
+               {0x17, 0x02211010},
+               {0x18, 0x01a19040},
+               {0x21, 0x01014020}),
+       SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
+               {0x14, 0x01014010},
+               {0x18, 0x01a19020},
+               {0x1a, 0x0181302f},
+               {0x1b, 0x0221401f}),
+       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+               {0x12, 0x99a30130},
+               {0x14, 0x90170110},
+               {0x15, 0x0321101f},
+               {0x16, 0x03011020}),
+       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+               {0x12, 0x99a30140},
+               {0x14, 0x90170110},
+               {0x15, 0x0321101f},
+               {0x16, 0x03011020}),
+       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+               {0x12, 0x99a30150},
+               {0x14, 0x90170110},
+               {0x15, 0x0321101f},
+               {0x16, 0x03011020}),
+       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
+               {0x14, 0x90170110},
+               {0x15, 0x0321101f},
+               {0x16, 0x03011020}),
+       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE,
+               {0x12, 0x90a60130},
+               {0x14, 0x90170110},
+               {0x15, 0x0321101f}),
+       SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+               {0x14, 0x01014010},
+               {0x17, 0x90170150},
+               {0x19, 0x02a11060},
+               {0x1b, 0x01813030},
+               {0x21, 0x02211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+               {0x14, 0x01014010},
+               {0x18, 0x01a19040},
+               {0x1b, 0x01813030},
+               {0x21, 0x02211020}),
+       SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
+               {0x14, 0x01014020},
+               {0x17, 0x90170110},
+               {0x18, 0x01a19050},
+               {0x1b, 0x01813040},
+               {0x21, 0x02211030}),
+       {}
+};
+
+/*
+ */
+static int patch_alc662(struct hda_codec *codec)
+{
+       struct alc_spec *spec;
+       int err;
+
+       err = alc_alloc_spec(codec, 0x0b);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+
+       spec->shutup = alc_eapd_shutup;
+
+       /* handle multiple HPs as is */
+       spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
+
+       alc_fix_pll_init(codec, 0x20, 0x04, 15);
+
+       switch (codec->core.vendor_id) {
+       case 0x10ec0668:
+               spec->init_hook = alc668_restore_default_value;
+               break;
+       }
+
+       alc_pre_init(codec);
+
+       snd_hda_pick_fixup(codec, alc662_fixup_models,
+                      alc662_fixup_tbl, alc662_fixups);
+       snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       alc_auto_parse_customize_define(codec);
+
+       if (has_cdefine_beep(codec))
+               spec->gen.beep_nid = 0x01;
+
+       if ((alc_get_coef0(codec) & (1 << 14)) &&
+           codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
+           spec->cdefine.platform_type == 1) {
+               err = alc_codec_rename(codec, "ALC272X");
+               if (err < 0)
+                       goto error;
+       }
+
+       /* automatic parse from the BIOS config */
+       err = alc662_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!spec->gen.no_analog && spec->gen.beep_nid) {
+               switch (codec->core.vendor_id) {
+               case 0x10ec0662:
+                       err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
+                       break;
+               case 0x10ec0272:
+               case 0x10ec0663:
+               case 0x10ec0665:
+               case 0x10ec0668:
+                       err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
+                       break;
+               case 0x10ec0273:
+                       err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
+                       break;
+               }
+               if (err < 0)
+                       goto error;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       alc_free(codec);
+       return err;
+}
+
+/*
+ * ALC680 support
+ */
+
+static int alc680_parse_auto_config(struct hda_codec *codec)
+{
+       return alc_parse_auto_config(codec, NULL, NULL);
+}
+
+/*
+ */
+static int patch_alc680(struct hda_codec *codec)
+{
+       int err;
+
+       /* ALC680 has no aa-loopback mixer */
+       err = alc_alloc_spec(codec, 0);
+       if (err < 0)
+               return err;
+
+       /* automatic parse from the BIOS config */
+       err = alc680_parse_auto_config(codec);
+       if (err < 0) {
+               alc_free(codec);
+               return err;
+       }
+
+       return 0;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_realtek[] = {
+       HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0230, "ALC236", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0245, "ALC245", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
+       HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
+       HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
+       HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
+       HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0274, "ALC274", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0280, "ALC280", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0287, "ALC287", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0289, "ALC289", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0300, "ALC300", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0623, "ALC623", patch_alc269),
+       HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
+       HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
+       HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
+       HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
+       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
+       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
+       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
+       HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0711, "ALC711", patch_alc269),
+       HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
+       HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
+       HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
+       HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
+       HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662),
+       HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
+       HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
+       HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek HD-audio codec");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
+
+static struct hda_codec_driver realtek_driver = {
+       .id = snd_hda_id_realtek,
+};
+
+module_hda_codec_driver(realtek_driver);
diff --git a/sound/hda/codecs/senarytech.c b/sound/hda/codecs/senarytech.c
new file mode 100644 (file)
index 0000000..9a253ad
--- /dev/null
@@ -0,0 +1,244 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio interface patch for Senary HDA audio codec
+ *
+ * Initially based on conexant.c
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+struct senary_spec {
+       struct hda_gen_spec gen;
+
+       /* extra EAPD pins */
+       unsigned int num_eapds;
+       hda_nid_t eapds[4];
+       hda_nid_t mute_led_eapd;
+
+       unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
+
+       int mute_led_polarity;
+       unsigned int gpio_led;
+       unsigned int gpio_mute_led_mask;
+       unsigned int gpio_mic_led_mask;
+};
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; private_value will be overwritten */
+static const struct snd_kcontrol_new senary_beep_mixer[] = {
+       HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
+};
+
+static int set_beep_amp(struct senary_spec *spec, hda_nid_t nid,
+                       int idx, int dir)
+{
+       struct snd_kcontrol_new *knew;
+       unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+       int i;
+
+       spec->gen.beep_nid = nid;
+       for (i = 0; i < ARRAY_SIZE(senary_beep_mixer); i++) {
+               knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+                                           &senary_beep_mixer[i]);
+               if (!knew)
+                       return -ENOMEM;
+               knew->private_value = beep_amp;
+       }
+       return 0;
+}
+
+static int senary_auto_parse_beep(struct hda_codec *codec)
+{
+       struct senary_spec *spec = codec->spec;
+       hda_nid_t nid;
+
+       for_each_hda_codec_node(nid, codec)
+               if ((get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) &&
+                       (get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_AMP_OVRD)))
+                       return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+       return 0;
+}
+#else
+#define senary_auto_parse_beep(codec)  0
+#endif
+
+/* parse EAPDs */
+static void senary_auto_parse_eapd(struct hda_codec *codec)
+{
+       struct senary_spec *spec = codec->spec;
+       hda_nid_t nid;
+
+       for_each_hda_codec_node(nid, codec) {
+               if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
+                       continue;
+               if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
+                       continue;
+               spec->eapds[spec->num_eapds++] = nid;
+               if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
+                       break;
+       }
+}
+
+static void senary_auto_turn_eapd(struct hda_codec *codec, int num_pins,
+                             const hda_nid_t *pins, bool on)
+{
+       int i;
+
+       for (i = 0; i < num_pins; i++) {
+               if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
+                       snd_hda_codec_write(codec, pins[i], 0,
+                                           AC_VERB_SET_EAPD_BTLENABLE,
+                                           on ? 0x02 : 0);
+       }
+}
+
+/* turn on/off EAPD according to Master switch */
+static void senary_auto_vmaster_hook(void *private_data, int enabled)
+{
+       struct hda_codec *codec = private_data;
+       struct senary_spec *spec = codec->spec;
+
+       senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
+}
+
+static void senary_init_gpio_led(struct hda_codec *codec)
+{
+       struct senary_spec *spec = codec->spec;
+       unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
+
+       if (mask) {
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
+                                   mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
+                                   mask);
+               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
+                                   spec->gpio_led);
+       }
+}
+
+static int senary_auto_init(struct hda_codec *codec)
+{
+       snd_hda_gen_init(codec);
+       senary_init_gpio_led(codec);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
+
+       return 0;
+}
+
+static void senary_auto_shutdown(struct hda_codec *codec)
+{
+       struct senary_spec *spec = codec->spec;
+
+       /* Turn the problematic codec into D3 to avoid spurious noises
+        * from the internal speaker during (and after) reboot
+        */
+       senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
+}
+
+static void senary_auto_free(struct hda_codec *codec)
+{
+       senary_auto_shutdown(codec);
+       snd_hda_gen_free(codec);
+}
+
+static int senary_auto_suspend(struct hda_codec *codec)
+{
+       senary_auto_shutdown(codec);
+       return 0;
+}
+
+static const struct hda_codec_ops senary_auto_patch_ops = {
+       .build_controls = snd_hda_gen_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = senary_auto_init,
+       .free = senary_auto_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .suspend = senary_auto_suspend,
+       .check_power_status = snd_hda_gen_check_power_status,
+};
+
+static int patch_senary_auto(struct hda_codec *codec)
+{
+       struct senary_spec *spec;
+       int err;
+
+       codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       snd_hda_gen_spec_init(&spec->gen);
+       codec->spec = spec;
+       codec->patch_ops = senary_auto_patch_ops;
+
+       senary_auto_parse_eapd(codec);
+       spec->gen.own_eapd_ctl = 1;
+
+       if (!spec->gen.vmaster_mute.hook)
+               spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
+                                      spec->parse_flags);
+       if (err < 0)
+               goto error;
+
+       err = senary_auto_parse_beep(codec);
+       if (err < 0)
+               goto error;
+
+       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+       if (err < 0)
+               goto error;
+
+       /* Some laptops with Senary chips show stalls in S3 resume,
+        * which falls into the single-cmd mode.
+        * Better to make reset, then.
+        */
+       if (!codec->bus->core.sync_write) {
+               codec_info(codec,
+                          "Enable sync_write for stable communication\n");
+               codec->bus->core.sync_write = 1;
+               codec->bus->allow_bus_reset = 1;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+
+ error:
+       senary_auto_free(codec);
+       return err;
+}
+
+/*
+ */
+
+static const struct hda_device_id snd_hda_id_senary[] = {
+       HDA_CODEC_ENTRY(0x1fa86186, "SN6186", patch_senary_auto),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_senary);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Senarytech HD-audio codec");
+
+static struct hda_codec_driver senary_driver = {
+       .id = snd_hda_id_senary,
+};
+
+module_hda_codec_driver(senary_driver);
diff --git a/sound/hda/codecs/si3054.c b/sound/hda/codecs/si3054.c
new file mode 100644 (file)
index 0000000..763eae8
--- /dev/null
@@ -0,0 +1,304 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for Silicon Labs 3054/5 modem codec
+ *
+ * Copyright (c) 2005 Sasha Khapyorsky <sashak@alsa-project.org>
+ *                    Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+
+/* si3054 verbs */
+#define SI3054_VERB_READ_NODE  0x900
+#define SI3054_VERB_WRITE_NODE 0x100
+
+/* si3054 nodes (registers) */
+#define SI3054_EXTENDED_MID    2
+#define SI3054_LINE_RATE       3
+#define SI3054_LINE_LEVEL      4
+#define SI3054_GPIO_CFG        5
+#define SI3054_GPIO_POLARITY   6
+#define SI3054_GPIO_STICKY     7
+#define SI3054_GPIO_WAKEUP     8
+#define SI3054_GPIO_STATUS     9
+#define SI3054_GPIO_CONTROL   10
+#define SI3054_MISC_AFE       11
+#define SI3054_CHIPID         12
+#define SI3054_LINE_CFG1      13
+#define SI3054_LINE_STATUS    14
+#define SI3054_DC_TERMINATION 15
+#define SI3054_LINE_CONFIG    16
+#define SI3054_CALLPROG_ATT   17
+#define SI3054_SQ_CONTROL     18
+#define SI3054_MISC_CONTROL   19
+#define SI3054_RING_CTRL1     20
+#define SI3054_RING_CTRL2     21
+
+/* extended MID */
+#define SI3054_MEI_READY 0xf
+
+/* line level */
+#define SI3054_ATAG_MASK 0x00f0
+#define SI3054_DTAG_MASK 0xf000
+
+/* GPIO bits */
+#define SI3054_GPIO_OH    0x0001
+#define SI3054_GPIO_CID   0x0002
+
+/* chipid and revisions */
+#define SI3054_CHIPID_CODEC_REV_MASK 0x000f
+#define SI3054_CHIPID_DAA_REV_MASK   0x00f0
+#define SI3054_CHIPID_INTERNATIONAL  0x0100
+#define SI3054_CHIPID_DAA_ID         0x0f00
+#define SI3054_CHIPID_CODEC_ID      (1<<12)
+
+/* si3054 codec registers (nodes) access macros */
+#define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0))
+#define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val))
+#define SET_REG_CACHE(codec,reg,val) \
+       snd_hda_codec_write_cache(codec,reg,0,SI3054_VERB_WRITE_NODE,val)
+
+
+struct si3054_spec {
+       unsigned international;
+};
+
+
+/*
+ * Modem mixer
+ */
+
+#define PRIVATE_VALUE(reg,mask) ((reg<<16)|(mask&0xffff))
+#define PRIVATE_REG(val) ((val>>16)&0xffff)
+#define PRIVATE_MASK(val) (val&0xffff)
+
+#define si3054_switch_info     snd_ctl_boolean_mono_info
+
+static int si3054_switch_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *uvalue)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 reg  = PRIVATE_REG(kcontrol->private_value);
+       u16 mask = PRIVATE_MASK(kcontrol->private_value);
+       uvalue->value.integer.value[0] = (GET_REG(codec, reg)) & mask ? 1 : 0 ;
+       return 0;
+}
+
+static int si3054_switch_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *uvalue)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       u16 reg  = PRIVATE_REG(kcontrol->private_value);
+       u16 mask = PRIVATE_MASK(kcontrol->private_value);
+       if (uvalue->value.integer.value[0])
+               SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) | mask);
+       else
+               SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) & ~mask);
+       return 0;
+}
+
+#define SI3054_KCONTROL(kname,reg,mask) { \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = kname, \
+       .subdevice = HDA_SUBDEV_NID_FLAG | reg, \
+       .info = si3054_switch_info, \
+       .get  = si3054_switch_get, \
+       .put  = si3054_switch_put, \
+       .private_value = PRIVATE_VALUE(reg,mask), \
+}
+               
+
+static const struct snd_kcontrol_new si3054_modem_mixer[] = {
+       SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
+       SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
+       {}
+};
+
+static int si3054_build_controls(struct hda_codec *codec)
+{
+       return snd_hda_add_new_ctls(codec, si3054_modem_mixer);
+}
+
+
+/*
+ * PCM callbacks
+ */
+
+static int si3054_pcm_prepare(struct hda_pcm_stream *hinfo,
+                             struct hda_codec *codec,
+                             unsigned int stream_tag,
+                             unsigned int format,
+                             struct snd_pcm_substream *substream)
+{
+       u16 val;
+
+       SET_REG(codec, SI3054_LINE_RATE, substream->runtime->rate);
+       val = GET_REG(codec, SI3054_LINE_LEVEL);
+       val &= 0xff << (8 * (substream->stream != SNDRV_PCM_STREAM_PLAYBACK));
+       val |= ((stream_tag & 0xf) << 4) << (8 * (substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
+       SET_REG(codec, SI3054_LINE_LEVEL, val);
+
+       snd_hda_codec_setup_stream(codec, hinfo->nid,
+                                  stream_tag, 0, format);
+       return 0;
+}
+
+static int si3054_pcm_open(struct hda_pcm_stream *hinfo,
+                          struct hda_codec *codec,
+                           struct snd_pcm_substream *substream)
+{
+       static const unsigned int rates[] = { 8000, 9600, 16000 };
+       static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
+               .count = ARRAY_SIZE(rates),
+               .list = rates,
+               .mask = 0,
+       };
+       substream->runtime->hw.period_bytes_min = 80;
+       return snd_pcm_hw_constraint_list(substream->runtime, 0,
+                       SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
+}
+
+
+static const struct hda_pcm_stream si3054_pcm = {
+       .substreams = 1,
+       .channels_min = 1,
+       .channels_max = 1,
+       .nid = 0x1,
+       .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_KNOT,
+       .formats = SNDRV_PCM_FMTBIT_S16_LE,
+       .maxbps = 16,
+       .ops = {
+               .open = si3054_pcm_open,
+               .prepare = si3054_pcm_prepare,
+       },
+};
+
+
+static int si3054_build_pcms(struct hda_codec *codec)
+{
+       struct hda_pcm *info;
+
+       info = snd_hda_codec_pcm_new(codec, "Si3054 Modem");
+       if (!info)
+               return -ENOMEM;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
+       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->core.mfg;
+       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = codec->core.mfg;
+       info->pcm_type = HDA_PCM_TYPE_MODEM;
+       return 0;
+}
+
+
+/*
+ * Init part
+ */
+
+static int si3054_init(struct hda_codec *codec)
+{
+       struct si3054_spec *spec = codec->spec;
+       unsigned wait_count;
+       u16 val;
+
+       if (snd_hdac_regmap_add_vendor_verb(&codec->core,
+                                           SI3054_VERB_WRITE_NODE))
+               return -ENOMEM;
+
+       snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0);
+       snd_hda_codec_write(codec, codec->core.mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0);
+       SET_REG(codec, SI3054_LINE_RATE, 9600);
+       SET_REG(codec, SI3054_LINE_LEVEL, SI3054_DTAG_MASK|SI3054_ATAG_MASK);
+       SET_REG(codec, SI3054_EXTENDED_MID, 0);
+
+       wait_count = 10;
+       do {
+               msleep(2);
+               val = GET_REG(codec, SI3054_EXTENDED_MID);
+       } while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--);
+
+       if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
+               codec_err(codec, "si3054: cannot initialize. EXT MID = %04x\n", val);
+               /* let's pray that this is no fatal error */
+               /* return -EACCES; */
+       }
+
+       SET_REG(codec, SI3054_GPIO_POLARITY, 0xffff);
+       SET_REG(codec, SI3054_GPIO_CFG, 0x0);
+       SET_REG(codec, SI3054_MISC_AFE, 0);
+       SET_REG(codec, SI3054_LINE_CFG1,0x200);
+
+       if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) {
+               codec_dbg(codec,
+                         "Link Frame Detect(FDT) is not ready (line status: %04x)\n",
+                               GET_REG(codec,SI3054_LINE_STATUS));
+       }
+
+       spec->international = GET_REG(codec, SI3054_CHIPID) & SI3054_CHIPID_INTERNATIONAL;
+
+       return 0;
+}
+
+static void si3054_free(struct hda_codec *codec)
+{
+       kfree(codec->spec);
+}
+
+
+/*
+ */
+
+static const struct hda_codec_ops si3054_patch_ops = {
+       .build_controls = si3054_build_controls,
+       .build_pcms = si3054_build_pcms,
+       .init = si3054_init,
+       .free = si3054_free,
+};
+
+static int patch_si3054(struct hda_codec *codec)
+{
+       struct si3054_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return -ENOMEM;
+       codec->spec = spec;
+       codec->patch_ops = si3054_patch_ops;
+       return 0;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_si3054[] = {
+       HDA_CODEC_ENTRY(0x163c3055, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x163c3155, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x11c13026, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x11c13055, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x11c13155, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x10573055, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x10573057, "Si3054", patch_si3054),
+       HDA_CODEC_ENTRY(0x10573155, "Si3054", patch_si3054),
+       /* VIA HDA on Clevo m540 */
+       HDA_CODEC_ENTRY(0x11063288, "Si3054", patch_si3054),
+       /* Asus A8J Modem (SM56) */
+       HDA_CODEC_ENTRY(0x15433155, "Si3054", patch_si3054),
+       /* LG LW20 modem */
+       HDA_CODEC_ENTRY(0x18540018, "Si3054", patch_si3054),
+       {}
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_si3054);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
+
+static struct hda_codec_driver si3054_driver = {
+       .id = snd_hda_id_si3054,
+};
+
+module_hda_codec_driver(si3054_driver);
diff --git a/sound/hda/codecs/side-codecs/Kconfig b/sound/hda/codecs/side-codecs/Kconfig
new file mode 100644 (file)
index 0000000..cbf1847
--- /dev/null
@@ -0,0 +1,128 @@
+config SND_HDA_CIRRUS_SCODEC
+       tristate
+
+config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
+       tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS
+       depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT
+       default KUNIT_ALL_TESTS
+       help
+         This builds KUnit tests for the cirrus side-codec library.
+         For more information on KUnit and unit tests in general,
+         please refer to the KUnit documentation in
+         Documentation/dev-tools/kunit/.
+         If in doubt, say "N".
+
+config SND_HDA_SCODEC_CS35L41
+       tristate
+       select SND_HDA_GENERIC
+       select REGMAP_IRQ
+       select FW_CS_DSP
+
+config SND_HDA_SCODEC_COMPONENT
+       tristate
+
+config SND_HDA_SCODEC_CS35L41_I2C
+       tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
+       depends on I2C
+       depends on ACPI
+       depends on EFI
+       depends on SND_SOC
+       select SND_SOC_CS35L41_LIB
+       select SND_HDA_SCODEC_CS35L41
+       select SND_SOC_CS_AMP_LIB
+       help
+         Say Y or M here to include CS35L41 I2C HD-audio side codec support
+         in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+       depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_I2C=m
+
+config SND_HDA_SCODEC_CS35L41_SPI
+       tristate "Build CS35L41 HD-audio codec support for SPI Bus"
+       depends on SPI_MASTER
+       depends on ACPI
+       depends on EFI
+       depends on SND_SOC
+       select SND_SOC_CS35L41_LIB
+       select SND_HDA_SCODEC_CS35L41
+       select SND_SOC_CS_AMP_LIB
+       help
+         Say Y or M here to include CS35L41 SPI HD-audio side codec support
+         in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+       depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_SPI=m
+
+config SND_HDA_SCODEC_CS35L56
+       tristate
+
+config SND_HDA_SCODEC_CS35L56_I2C
+       tristate "Build CS35L56 HD-audio side codec support for I2C Bus"
+       depends on I2C
+       depends on ACPI
+       depends on SND_SOC
+       select FW_CS_DSP
+       imply SERIAL_MULTI_INSTANTIATE
+       select SND_HDA_GENERIC
+       select SND_SOC_CS35L56_SHARED
+       select SND_HDA_SCODEC_CS35L56
+       select SND_HDA_CIRRUS_SCODEC
+       select SND_SOC_CS_AMP_LIB
+       help
+         Say Y or M here to include CS35L56 amplifier support with
+         I2C control.
+
+config SND_HDA_SCODEC_CS35L56_SPI
+       tristate "Build CS35L56 HD-audio side codec support for SPI Bus"
+       depends on SPI_MASTER
+       depends on ACPI
+       depends on SND_SOC
+       select FW_CS_DSP
+       imply SERIAL_MULTI_INSTANTIATE
+       select SND_HDA_GENERIC
+       select SND_SOC_CS35L56_SHARED
+       select SND_HDA_SCODEC_CS35L56
+       select SND_HDA_CIRRUS_SCODEC
+       select SND_SOC_CS_AMP_LIB
+       help
+         Say Y or M here to include CS35L56 amplifier support with
+         SPI control.
+
+config SND_HDA_SCODEC_TAS2781
+       tristate
+       select SND_HDA_GENERIC
+
+config SND_HDA_SCODEC_TAS2781_I2C
+       tristate "Build TAS2781 HD-audio side codec support for I2C Bus"
+       depends on I2C
+       depends on ACPI
+       depends on EFI
+       depends on SND_SOC
+       select SND_HDA_SCODEC_TAS2781
+       select SND_SOC_TAS2781_COMLIB_I2C
+       select SND_SOC_TAS2781_FMWLIB
+       select CRC32
+       help
+         Say Y or M here to include TAS2781 I2C HD-audio side codec support
+         in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+       depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m
+
+config SND_HDA_SCODEC_TAS2781_SPI
+       tristate "Build TAS2781 HD-audio side codec support for SPI Bus"
+       depends on SPI_MASTER
+       depends on ACPI
+       depends on EFI
+       depends on SND_SOC
+       select SND_HDA_SCODEC_TAS2781
+       select SND_SOC_TAS2781_COMLIB
+       select SND_SOC_TAS2781_FMWLIB
+       select CRC8
+       select CRC32
+       help
+         Say Y or M here to include TAS2781 SPI HD-audio side codec support
+         in snd-hda-intel driver, such as ALC287.
+
+comment "Set to Y if you want auto-loading the side codec driver"
+       depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m
diff --git a/sound/hda/codecs/side-codecs/Makefile b/sound/hda/codecs/side-codecs/Makefile
new file mode 100644 (file)
index 0000000..245e84f
--- /dev/null
@@ -0,0 +1,28 @@
+# SPDX-License-Identifier: GPL-2.0
+subdir-ccflags-y += -I$(src)/../../common
+
+snd-hda-cirrus-scodec-y :=     cirrus_scodec.o
+snd-hda-cirrus-scodec-test-y :=        cirrus_scodec_test.o
+snd-hda-scodec-cs35l41-y :=    cs35l41_hda.o cs35l41_hda_property.o
+snd-hda-scodec-cs35l41-i2c-y :=        cs35l41_hda_i2c.o
+snd-hda-scodec-cs35l41-spi-y :=        cs35l41_hda_spi.o
+snd-hda-scodec-cs35l56-y :=    cs35l56_hda.o
+snd-hda-scodec-cs35l56-i2c-y :=        cs35l56_hda_i2c.o
+snd-hda-scodec-cs35l56-spi-y :=        cs35l56_hda_spi.o
+snd-hda-scodec-component-y :=  hda_component.o
+snd-hda-scodec-tas2781-y :=    tas2781_hda.o
+snd-hda-scodec-tas2781-i2c-y :=        tas2781_hda_i2c.o
+snd-hda-scodec-tas2781-spi-y :=        tas2781_hda_spi.o
+
+obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
+obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
+obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
+obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec.c b/sound/hda/codecs/side-codecs/cirrus_scodec.c
new file mode 100644 (file)
index 0000000..3c67020
--- /dev/null
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// Common code for Cirrus side-codecs.
+//
+// Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
+//               Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/dev_printk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+
+#include "cirrus_scodec.h"
+
+int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index,
+                                int num_amps, int fixed_gpio_id)
+{
+       struct gpio_desc *speaker_id_desc;
+       int speaker_id = -ENOENT;
+
+       if (fixed_gpio_id >= 0) {
+               dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id);
+               speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN);
+               if (IS_ERR(speaker_id_desc)) {
+                       speaker_id = PTR_ERR(speaker_id_desc);
+                       return speaker_id;
+               }
+               speaker_id = gpiod_get_value_cansleep(speaker_id_desc);
+               gpiod_put(speaker_id_desc);
+       } else {
+               int base_index;
+               int gpios_per_amp;
+               int count;
+               int tmp;
+               int i;
+
+               count = gpiod_count(dev, "spk-id");
+               if (count > 0) {
+                       speaker_id = 0;
+                       gpios_per_amp = count / num_amps;
+                       base_index = gpios_per_amp * amp_index;
+
+                       if (count % num_amps)
+                               return -EINVAL;
+
+                       dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp);
+
+                       for (i = 0; i < gpios_per_amp; i++) {
+                               speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index,
+                                                                 GPIOD_IN);
+                               if (IS_ERR(speaker_id_desc)) {
+                                       speaker_id = PTR_ERR(speaker_id_desc);
+                                       break;
+                               }
+                               tmp = gpiod_get_value_cansleep(speaker_id_desc);
+                               gpiod_put(speaker_id_desc);
+                               if (tmp < 0) {
+                                       speaker_id = tmp;
+                                       break;
+                               }
+                               speaker_id |= tmp << i;
+                       }
+               }
+       }
+
+       dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
+
+       return speaker_id;
+}
+EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, "SND_HDA_CIRRUS_SCODEC");
+
+MODULE_DESCRIPTION("HDA Cirrus side-codec library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec.h b/sound/hda/codecs/side-codecs/cirrus_scodec.h
new file mode 100644 (file)
index 0000000..ba2041d
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * Copyright (C) 2023 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef CIRRUS_SCODEC_H
+#define CIRRUS_SCODEC_H
+
+int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index,
+                                int num_amps, int fixed_gpio_id);
+
+#endif /* CIRRUS_SCODEC_H */
diff --git a/sound/hda/codecs/side-codecs/cirrus_scodec_test.c b/sound/hda/codecs/side-codecs/cirrus_scodec_test.c
new file mode 100644 (file)
index 0000000..93b9cbf
--- /dev/null
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// KUnit test for the Cirrus side-codec library.
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <kunit/platform_device.h>
+#include <kunit/resource.h>
+#include <kunit/test.h>
+#include <linux/device.h>
+#include <linux/device/faux.h>
+#include <linux/gpio/driver.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "cirrus_scodec.h"
+
+KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
+                           struct faux_device *)
+KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper,
+                           device_remove_software_node,
+                           struct device *)
+
+struct cirrus_scodec_test_gpio {
+       unsigned int pin_state;
+       struct gpio_chip chip;
+};
+
+struct cirrus_scodec_test_priv {
+       struct faux_device *amp_dev;
+       struct platform_device *gpio_pdev;
+       struct cirrus_scodec_test_gpio *gpio_priv;
+};
+
+static int cirrus_scodec_test_gpio_get_direction(struct gpio_chip *chip,
+                                                unsigned int offset)
+{
+       return GPIO_LINE_DIRECTION_IN;
+}
+
+static int cirrus_scodec_test_gpio_direction_in(struct gpio_chip *chip,
+                                               unsigned int offset)
+{
+       return 0;
+}
+
+static int cirrus_scodec_test_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+       struct cirrus_scodec_test_gpio *gpio_priv = gpiochip_get_data(chip);
+
+       return !!(gpio_priv->pin_state & BIT(offset));
+}
+
+static int cirrus_scodec_test_gpio_direction_out(struct gpio_chip *chip,
+                                                unsigned int offset, int value)
+{
+       return -EOPNOTSUPP;
+}
+
+static int cirrus_scodec_test_gpio_set(struct gpio_chip *chip,
+                                      unsigned int offset, int value)
+{
+       return -EOPNOTSUPP;
+}
+
+static int cirrus_scodec_test_gpio_set_config(struct gpio_chip *gc,
+                                             unsigned int offset,
+                                             unsigned long config)
+{
+       switch (pinconf_to_config_param(config)) {
+       case PIN_CONFIG_OUTPUT:
+       case PIN_CONFIG_OUTPUT_ENABLE:
+               return -EOPNOTSUPP;
+       default:
+               return 0;
+       }
+}
+
+static const struct gpio_chip cirrus_scodec_test_gpio_chip = {
+       .label                  = "cirrus_scodec_test_gpio",
+       .owner                  = THIS_MODULE,
+       .request                = gpiochip_generic_request,
+       .free                   = gpiochip_generic_free,
+       .get_direction          = cirrus_scodec_test_gpio_get_direction,
+       .direction_input        = cirrus_scodec_test_gpio_direction_in,
+       .get                    = cirrus_scodec_test_gpio_get,
+       .direction_output       = cirrus_scodec_test_gpio_direction_out,
+       .set_rv                 = cirrus_scodec_test_gpio_set,
+       .set_config             = cirrus_scodec_test_gpio_set_config,
+       .base                   = -1,
+       .ngpio                  = 32,
+};
+
+static int cirrus_scodec_test_gpio_probe(struct platform_device *pdev)
+{
+       struct cirrus_scodec_test_gpio *gpio_priv;
+       int ret;
+
+       gpio_priv = devm_kzalloc(&pdev->dev, sizeof(*gpio_priv), GFP_KERNEL);
+       if (!gpio_priv)
+               return -ENOMEM;
+
+       /* GPIO core modifies our struct gpio_chip so use a copy */
+       gpio_priv->chip = cirrus_scodec_test_gpio_chip;
+       ret = devm_gpiochip_add_data(&pdev->dev, &gpio_priv->chip, gpio_priv);
+       if (ret)
+               return dev_err_probe(&pdev->dev, ret, "Failed to add gpiochip\n");
+
+       dev_set_drvdata(&pdev->dev, gpio_priv);
+
+       return 0;
+}
+
+static struct platform_driver cirrus_scodec_test_gpio_driver = {
+       .driver.name    = "cirrus_scodec_test_gpio_drv",
+       .driver.owner   = THIS_MODULE,
+       .probe          = cirrus_scodec_test_gpio_probe,
+};
+
+/* software_node referencing the gpio driver */
+static const struct software_node cirrus_scodec_test_gpio_swnode = {
+       .name = "cirrus_scodec_test_gpio",
+};
+
+static void cirrus_scodec_test_create_gpio(struct kunit *test)
+{
+       struct cirrus_scodec_test_priv *priv = test->priv;
+
+       KUNIT_ASSERT_EQ(test, 0,
+                       kunit_platform_driver_register(test, &cirrus_scodec_test_gpio_driver));
+
+       priv->gpio_pdev = kunit_platform_device_alloc(test,
+                                                     cirrus_scodec_test_gpio_driver.driver.name,
+                                                     PLATFORM_DEVID_NONE);
+       KUNIT_ASSERT_NOT_NULL(test, priv->gpio_pdev);
+
+       KUNIT_ASSERT_EQ(test, 0, device_add_software_node(&priv->gpio_pdev->dev,
+                                                         &cirrus_scodec_test_gpio_swnode));
+       KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test,
+                                                          device_remove_software_node_wrapper,
+                                                          &priv->gpio_pdev->dev));
+
+       KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, priv->gpio_pdev));
+
+       priv->gpio_priv = dev_get_drvdata(&priv->gpio_pdev->dev);
+       KUNIT_ASSERT_NOT_NULL(test, priv->gpio_priv);
+}
+
+static void cirrus_scodec_test_set_gpio_ref_arg(struct software_node_ref_args *arg,
+                                               int gpio_num)
+{
+       struct software_node_ref_args template =
+               SOFTWARE_NODE_REFERENCE(&cirrus_scodec_test_gpio_swnode, gpio_num, 0);
+
+       *arg = template;
+}
+
+static int cirrus_scodec_test_set_spkid_swnode(struct kunit *test,
+                                              struct device *dev,
+                                              struct software_node_ref_args *args,
+                                              int num_args)
+{
+       const struct property_entry props_template[] = {
+               PROPERTY_ENTRY_REF_ARRAY_LEN("spk-id-gpios", args, num_args),
+               { }
+       };
+       struct property_entry *props;
+       struct software_node *node;
+
+       node = kunit_kzalloc(test, sizeof(*node), GFP_KERNEL);
+       if (!node)
+               return -ENOMEM;
+
+       props = kunit_kzalloc(test, sizeof(props_template), GFP_KERNEL);
+       if (!props)
+               return -ENOMEM;
+
+       memcpy(props, props_template, sizeof(props_template));
+       node->properties = props;
+
+       return device_add_software_node(dev, node);
+}
+
+struct cirrus_scodec_test_spkid_param {
+       int num_amps;
+       int gpios_per_amp;
+       int num_amps_sharing;
+};
+
+static void cirrus_scodec_test_spkid_parse(struct kunit *test)
+{
+       struct cirrus_scodec_test_priv *priv = test->priv;
+       const struct cirrus_scodec_test_spkid_param *param = test->param_value;
+       int num_spk_id_refs = param->num_amps * param->gpios_per_amp;
+       struct software_node_ref_args *refs;
+       struct device *dev = &priv->amp_dev->dev;
+       unsigned int v;
+       int i, ret;
+
+       refs = kunit_kcalloc(test, num_spk_id_refs, sizeof(*refs), GFP_KERNEL);
+       KUNIT_ASSERT_NOT_NULL(test, refs);
+
+       for (i = 0, v = 0; i < num_spk_id_refs; ) {
+               cirrus_scodec_test_set_gpio_ref_arg(&refs[i++], v++);
+
+               /*
+                * If amps are sharing GPIOs repeat the last set of
+                * GPIOs until we've done that number of amps.
+                * We have done all GPIOs for an amp when i is a multiple
+                * of gpios_per_amp.
+                * We have done all amps sharing the same GPIOs when i is
+                * a multiple of (gpios_per_amp * num_amps_sharing).
+                */
+               if (!(i % param->gpios_per_amp) &&
+                   (i % (param->gpios_per_amp * param->num_amps_sharing)))
+                       v -= param->gpios_per_amp;
+       }
+
+       ret = cirrus_scodec_test_set_spkid_swnode(test, dev, refs, num_spk_id_refs);
+       KUNIT_EXPECT_EQ_MSG(test, ret, 0, "Failed to add swnode\n");
+
+       for (i = 0; i < param->num_amps; ++i) {
+               for (v = 0; v < (1 << param->gpios_per_amp); ++v) {
+                       /* Set only the GPIO bits used by this amp */
+                       priv->gpio_priv->pin_state =
+                               v << (param->gpios_per_amp * (i / param->num_amps_sharing));
+
+                       ret = cirrus_scodec_get_speaker_id(dev, i, param->num_amps, -1);
+                       KUNIT_EXPECT_EQ_MSG(test, ret, v,
+                                           "get_speaker_id failed amp:%d pin_state:%#x\n",
+                                           i, priv->gpio_priv->pin_state);
+               }
+       }
+}
+
+static void cirrus_scodec_test_no_spkid(struct kunit *test)
+{
+       struct cirrus_scodec_test_priv *priv = test->priv;
+       struct device *dev = &priv->amp_dev->dev;
+       int ret;
+
+       ret = cirrus_scodec_get_speaker_id(dev, 0, 4, -1);
+       KUNIT_EXPECT_EQ(test, ret, -ENOENT);
+}
+
+static int cirrus_scodec_test_case_init(struct kunit *test)
+{
+       struct cirrus_scodec_test_priv *priv;
+
+       priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       test->priv = priv;
+
+       /* Create dummy GPIO */
+       cirrus_scodec_test_create_gpio(test);
+
+       /* Create dummy amp driver dev */
+       priv->amp_dev = faux_device_create("cirrus_scodec_test_amp_drv", NULL, NULL);
+       KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev);
+       KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test,
+                                                          faux_device_destroy_wrapper,
+                                                          priv->amp_dev));
+
+       return 0;
+}
+
+static const struct cirrus_scodec_test_spkid_param cirrus_scodec_test_spkid_param_cases[] = {
+       { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 1 },
+       { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 1 },
+       { .num_amps = 2, .gpios_per_amp = 3, .num_amps_sharing = 1 },
+       { .num_amps = 2, .gpios_per_amp = 4, .num_amps_sharing = 1 },
+       { .num_amps = 3, .gpios_per_amp = 1, .num_amps_sharing = 1 },
+       { .num_amps = 3, .gpios_per_amp = 2, .num_amps_sharing = 1 },
+       { .num_amps = 3, .gpios_per_amp = 3, .num_amps_sharing = 1 },
+       { .num_amps = 3, .gpios_per_amp = 4, .num_amps_sharing = 1 },
+       { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 1 },
+       { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 1 },
+       { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 1 },
+       { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 1 },
+
+       /* Same GPIO shared by all amps */
+       { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 2 },
+       { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 2 },
+       { .num_amps = 2, .gpios_per_amp = 3, .num_amps_sharing = 2 },
+       { .num_amps = 2, .gpios_per_amp = 4, .num_amps_sharing = 2 },
+       { .num_amps = 3, .gpios_per_amp = 1, .num_amps_sharing = 3 },
+       { .num_amps = 3, .gpios_per_amp = 2, .num_amps_sharing = 3 },
+       { .num_amps = 3, .gpios_per_amp = 3, .num_amps_sharing = 3 },
+       { .num_amps = 3, .gpios_per_amp = 4, .num_amps_sharing = 3 },
+       { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 4 },
+       { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 4 },
+       { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 4 },
+       { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 4 },
+
+       /* Two sets of shared GPIOs */
+       { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 2 },
+       { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 2 },
+       { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 2 },
+       { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 2 },
+};
+
+static void cirrus_scodec_test_spkid_param_desc(const struct cirrus_scodec_test_spkid_param *param,
+                                               char *desc)
+{
+       snprintf(desc, KUNIT_PARAM_DESC_SIZE, "amps:%d gpios_per_amp:%d num_amps_sharing:%d",
+                param->num_amps, param->gpios_per_amp, param->num_amps_sharing);
+}
+
+KUNIT_ARRAY_PARAM(cirrus_scodec_test_spkid, cirrus_scodec_test_spkid_param_cases,
+                 cirrus_scodec_test_spkid_param_desc);
+
+static struct kunit_case cirrus_scodec_test_cases[] = {
+       KUNIT_CASE_PARAM(cirrus_scodec_test_spkid_parse, cirrus_scodec_test_spkid_gen_params),
+       KUNIT_CASE(cirrus_scodec_test_no_spkid),
+       { } /* terminator */
+};
+
+static struct kunit_suite cirrus_scodec_test_suite = {
+       .name = "snd-hda-scodec-cs35l56-test",
+       .init = cirrus_scodec_test_case_init,
+       .test_cases = cirrus_scodec_test_cases,
+};
+
+kunit_test_suite(cirrus_scodec_test_suite);
+
+MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC");
+MODULE_DESCRIPTION("KUnit test for the Cirrus side-codec library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.c b/sound/hda/codecs/side-codecs/cs35l41_hda.c
new file mode 100644 (file)
index 0000000..37f2cdc
--- /dev/null
@@ -0,0 +1,2112 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS35l41 ALSA HDA audio driver
+//
+// Copyright 2021 Cirrus Logic, Inc.
+//
+// Author: Lucas Tanure <tanureal@opensource.cirrus.com>
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <sound/hda_codec.h>
+#include <sound/soc.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+#include <linux/vmalloc.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "../generic.h"
+#include "hda_component.h"
+#include "cs35l41_hda.h"
+#include "cs35l41_hda_property.h"
+
+#define CS35L41_PART "cs35l41"
+
+#define HALO_STATE_DSP_CTL_NAME                "HALO_STATE"
+#define HALO_STATE_DSP_CTL_TYPE                5
+#define HALO_STATE_DSP_CTL_ALG         262308
+#define CAL_R_DSP_CTL_NAME             "CAL_R"
+#define CAL_STATUS_DSP_CTL_NAME                "CAL_STATUS"
+#define CAL_CHECKSUM_DSP_CTL_NAME      "CAL_CHECKSUM"
+#define CAL_AMBIENT_DSP_CTL_NAME       "CAL_AMBIENT"
+#define CAL_DSP_CTL_TYPE               5
+#define CAL_DSP_CTL_ALG                        205
+#define CS35L41_UUID                   "50d90cdc-3de4-4f18-b528-c7fe3b71f40d"
+#define CS35L41_DSM_GET_MUTE           5
+#define CS35L41_NOTIFY_EVENT           0x91
+#define CS35L41_TUNING_SIG             0x109A4A35
+
+enum cs35l41_tuning_param_types {
+       TUNING_PARAM_GAIN,
+};
+
+struct cs35l41_tuning_param_hdr {
+       __le32 tuning_index;
+       __le32 type;
+       __le32 size;
+} __packed;
+
+struct cs35l41_tuning_param {
+       struct cs35l41_tuning_param_hdr hdr;
+       union {
+               __le32 gain;
+       };
+} __packed;
+
+struct cs35l41_tuning_params {
+       __le32 signature;
+       __le32 version;
+       __le32 size;
+       __le32 num_entries;
+       u8 data[];
+} __packed;
+
+/* Firmware calibration controls */
+static const struct cirrus_amp_cal_controls cs35l41_calibration_controls = {
+       .alg_id =       CAL_DSP_CTL_ALG,
+       .mem_region =   CAL_DSP_CTL_TYPE,
+       .ambient =      CAL_AMBIENT_DSP_CTL_NAME,
+       .calr =         CAL_R_DSP_CTL_NAME,
+       .status =       CAL_STATUS_DSP_CTL_NAME,
+       .checksum =     CAL_CHECKSUM_DSP_CTL_NAME,
+};
+
+enum cs35l41_hda_fw_id {
+       CS35L41_HDA_FW_SPK_PROT,
+       CS35L41_HDA_FW_SPK_CALI,
+       CS35L41_HDA_FW_SPK_DIAG,
+       CS35L41_HDA_FW_MISC,
+       CS35L41_HDA_NUM_FW
+};
+
+static const char * const cs35l41_hda_fw_ids[CS35L41_HDA_NUM_FW] = {
+       [CS35L41_HDA_FW_SPK_PROT] = "spk-prot",
+       [CS35L41_HDA_FW_SPK_CALI] = "spk-cali",
+       [CS35L41_HDA_FW_SPK_DIAG] = "spk-diag",
+       [CS35L41_HDA_FW_MISC] =     "misc",
+};
+
+static bool firmware_autostart = 1;
+module_param(firmware_autostart, bool, 0444);
+MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot"
+                            "(0=Disable, 1=Enable) (default=1); ");
+
+static const char channel_name[3] = { 'L', 'R', 'C' };
+
+static const struct reg_sequence cs35l41_hda_config[] = {
+       { CS35L41_PLL_CLK_CTRL,         0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
+       { CS35L41_DSP_CLK_CTRL,         0x00000003 }, // DSP CLK EN
+       { CS35L41_GLOBAL_CLK_CTRL,      0x00000003 }, // GLOBAL_FS = 48 kHz
+       { CS35L41_SP_RATE_CTRL,         0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
+       { CS35L41_SP_FORMAT,            0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
+       { CS35L41_SP_TX_WL,             0x00000018 }, // 24 cycles/slot
+       { CS35L41_SP_RX_WL,             0x00000018 }, // 24 cycles/slot
+       { CS35L41_ASP_TX1_SRC,          0x00000018 }, // ASPTX1 SRC = VMON
+       { CS35L41_ASP_TX2_SRC,          0x00000019 }, // ASPTX2 SRC = IMON
+       { CS35L41_DSP1_RX3_SRC,         0x00000018 }, // DSP1RX3 SRC = VMON
+       { CS35L41_DSP1_RX4_SRC,         0x00000019 }, // DSP1RX4 SRC = IMON
+};
+
+static const struct reg_sequence cs35l41_hda_config_no_dsp[] = {
+       { CS35L41_SP_HIZ_CTRL,          0x00000002 }, // Hi-Z unused
+       { CS35L41_DAC_PCM1_SRC,         0x00000008 }, // DACPCM1_SRC = ASPRX1
+       { CS35L41_ASP_TX3_SRC,          0x00000000 }, // ASPTX3 SRC = ZERO FILL
+       { CS35L41_ASP_TX4_SRC,          0x00000000 }, // ASPTX4 SRC = ZERO FILL
+       { CS35L41_DSP1_RX5_SRC,         0x00000020 }, // DSP1RX5 SRC = ERRVOL
+       { CS35L41_DSP1_RX6_SRC,         0x00000021 }, // DSP1RX6 SRC = CLASSH_TGT
+};
+
+static const struct reg_sequence cs35l41_hda_config_dsp[] = {
+       { CS35L41_SP_HIZ_CTRL,          0x00000003 }, // Hi-Z unused/disabled
+       { CS35L41_DAC_PCM1_SRC,         0x00000032 }, // DACPCM1_SRC = DSP1TX1
+       { CS35L41_ASP_TX3_SRC,          0x00000028 }, // ASPTX3 SRC = VPMON
+       { CS35L41_ASP_TX4_SRC,          0x00000029 }, // ASPTX4 SRC = VBSTMON
+       { CS35L41_DSP1_RX6_SRC,         0x00000029 }, // DSP1RX6 SRC = VBSTMON
+};
+
+static const struct reg_sequence cs35l41_hda_unmute[] = {
+       { CS35L41_AMP_DIG_VOL_CTRL,     0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM  0.0 dB
+       { CS35L41_AMP_GAIN_CTRL,        0x00000084 }, // AMP_GAIN_PCM 4.5 dB
+};
+
+static const struct reg_sequence cs35l41_hda_mute[] = {
+       { CS35L41_AMP_GAIN_CTRL,        0x00000000 }, // AMP_GAIN_PCM 0.5 dB
+       { CS35L41_AMP_DIG_VOL_CTRL,     0x0000A678 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM Mute
+};
+
+static const struct cs_dsp_client_ops client_ops = {
+       /* cs_dsp requires the client to provide this even if it is empty */
+};
+
+static int cs35l41_request_tuning_param_file(struct cs35l41_hda *cs35l41, char *tuning_filename,
+                                            const struct firmware **firmware, char **filename,
+                                            const char *ssid)
+{
+       int ret = 0;
+
+       /* Filename is the same as the tuning file with "cfg" suffix */
+       *filename = kasprintf(GFP_KERNEL, "%scfg", tuning_filename);
+       if (*filename == NULL)
+               return -ENOMEM;
+
+       ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev);
+       if (ret != 0) {
+               dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename);
+               kfree(*filename);
+               *filename = NULL;
+       }
+
+       return ret;
+}
+
+static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41,
+                                        const struct firmware **firmware, char **filename,
+                                        const char *ssid, const char *amp_name,
+                                        int spkid, const char *filetype)
+{
+       const char * const dsp_name = cs35l41->cs_dsp.name;
+       char *s, c;
+       int ret = 0;
+
+       if (spkid > -1 && ssid && amp_name)
+               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART,
+                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
+                                     ssid, spkid, amp_name, filetype);
+       else if (spkid > -1 && ssid)
+               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d.%s", CS35L41_PART,
+                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
+                                     ssid, spkid, filetype);
+       else if (ssid && amp_name)
+               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-%s.%s", CS35L41_PART,
+                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
+                                     ssid, amp_name, filetype);
+       else if (ssid)
+               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s.%s", CS35L41_PART,
+                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
+                                     ssid, filetype);
+       else
+               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s.%s", CS35L41_PART,
+                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
+                                     filetype);
+
+       if (*filename == NULL)
+               return -ENOMEM;
+
+       /*
+        * Make sure that filename is lower-case and any non alpha-numeric
+        * characters except full stop and '/' are replaced with hyphens.
+        */
+       s = *filename;
+       while (*s) {
+               c = *s;
+               if (isalnum(c))
+                       *s = tolower(c);
+               else if (c != '.' && c != '/')
+                       *s = '-';
+               s++;
+       }
+
+       ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev);
+       if (ret != 0) {
+               dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename);
+               kfree(*filename);
+               *filename = NULL;
+       }
+
+       return ret;
+}
+
+static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
+                                               const struct firmware **wmfw_firmware,
+                                               char **wmfw_filename,
+                                               const struct firmware **coeff_firmware,
+                                               char **coeff_filename)
+{
+       int ret;
+
+       /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                           cs35l41->speaker_id, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                                   cs35l41->speaker_id, "bin");
+               if (ret)
+                       goto coeff_err;
+
+               return 0;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           cs35l41->acpi_subsystem_id,
+                                           cs35l41->amp_name, -1, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                                   cs35l41->speaker_id, "bin");
+               if (ret)
+                       goto coeff_err;
+
+               return 0;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           cs35l41->acpi_subsystem_id,
+                                           NULL, cs35l41->speaker_id, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   cs35l41->acpi_subsystem_id,
+                                                   cs35l41->amp_name, cs35l41->speaker_id, "bin");
+               if (ret)
+                       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
+                       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
+                                                           coeff_filename,
+                                                           cs35l41->acpi_subsystem_id, NULL,
+                                                           cs35l41->speaker_id, "bin");
+               if (ret)
+                       goto coeff_err;
+
+               return 0;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           cs35l41->acpi_subsystem_id,
+                                           NULL, -1, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                                   cs35l41->speaker_id, "bin");
+               if (ret)
+                       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
+                       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
+                                                           coeff_filename,
+                                                           cs35l41->acpi_subsystem_id, NULL,
+                                                           cs35l41->speaker_id, "bin");
+               if (ret)
+                       goto coeff_err;
+       }
+
+       return ret;
+coeff_err:
+       release_firmware(*wmfw_firmware);
+       kfree(*wmfw_filename);
+       return ret;
+}
+
+static int cs35l41_fallback_firmware_file(struct cs35l41_hda *cs35l41,
+                                         const struct firmware **wmfw_firmware,
+                                         char **wmfw_filename,
+                                         const struct firmware **coeff_firmware,
+                                         char **coeff_filename)
+{
+       int ret;
+
+       /* Handle fallback */
+       dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
+
+       /* fallback try cirrus/part-dspN-fwtype.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           NULL, NULL, -1, "wmfw");
+       if (ret)
+               goto err;
+
+       /* fallback try cirrus/part-dspN-fwtype.bin */
+       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                           NULL, NULL, -1, "bin");
+       if (ret) {
+               release_firmware(*wmfw_firmware);
+               kfree(*wmfw_filename);
+               goto err;
+       }
+       return 0;
+
+err:
+       dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
+       return ret;
+}
+
+static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
+                                         const struct firmware **wmfw_firmware,
+                                         char **wmfw_filename,
+                                         const struct firmware **coeff_firmware,
+                                         char **coeff_filename)
+{
+       int ret;
+
+       if (cs35l41->speaker_id > -1) {
+               ret = cs35l41_request_firmware_files_spkid(cs35l41, wmfw_firmware, wmfw_filename,
+                                                          coeff_firmware, coeff_filename);
+               goto out;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           cs35l41->acpi_subsystem_id,
+                                           cs35l41->amp_name, -1, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
+                                                   -1, "bin");
+               if (ret)
+                       goto coeff_err;
+
+               goto out;
+       }
+
+       /* try cirrus/part-dspN-fwtype-sub.wmfw */
+       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                           cs35l41->acpi_subsystem_id,
+                                           NULL, -1, "wmfw");
+       if (!ret) {
+               /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
+               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                   cs35l41->acpi_subsystem_id,
+                                                   cs35l41->amp_name, -1, "bin");
+               if (ret)
+                       /* try cirrus/part-dspN-fwtype-sub.bin */
+                       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
+                                                           cs35l41->acpi_subsystem_id, NULL, -1,
+                                                           "bin");
+               if (ret)
+                       goto coeff_err;
+       }
+
+out:
+       if (ret)
+               /* if all attempts at finding firmware fail, try fallback */
+               goto fallback;
+
+       return 0;
+
+coeff_err:
+       release_firmware(*wmfw_firmware);
+       kfree(*wmfw_filename);
+fallback:
+       return cs35l41_fallback_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
+                                             coeff_firmware, coeff_filename);
+}
+
+
+static void cs35l41_hda_apply_calibration(struct cs35l41_hda *cs35l41)
+{
+       int ret;
+
+       if (!cs35l41->cal_data_valid)
+               return;
+
+       ret = cs_amp_write_cal_coeffs(&cs35l41->cs_dsp, &cs35l41_calibration_controls,
+                                     &cs35l41->cal_data);
+       if (ret < 0)
+               dev_warn(cs35l41->dev, "Failed to apply calibration: %d\n", ret);
+       else
+               dev_info(cs35l41->dev, "Calibration applied: R0=%d\n", cs35l41->cal_data.calR);
+}
+
+static int cs35l41_read_silicon_uid(struct cs35l41_hda *cs35l41, u64 *uid)
+{
+       u32 tmp;
+       int ret;
+
+       ret = regmap_read(cs35l41->regmap, CS35L41_DIE_STS2, &tmp);
+       if (ret) {
+               dev_err(cs35l41->dev, "Cannot obtain CS35L41_DIE_STS2: %d\n", ret);
+               return ret;
+       }
+
+       *uid = tmp;
+       *uid <<= 32;
+
+       ret = regmap_read(cs35l41->regmap, CS35L41_DIE_STS1, &tmp);
+       if (ret) {
+               dev_err(cs35l41->dev, "Cannot obtain CS35L41_DIE_STS1: %d\n", ret);
+               return ret;
+       }
+
+       *uid |= tmp;
+
+       dev_dbg(cs35l41->dev, "UniqueID = %#llx\n", *uid);
+
+       return 0;
+}
+
+static int cs35l41_get_calibration(struct cs35l41_hda *cs35l41)
+{
+       u64 silicon_uid;
+       int ret;
+
+       ret = cs35l41_read_silicon_uid(cs35l41, &silicon_uid);
+       if (ret < 0)
+               return ret;
+
+       ret = cs_amp_get_efi_calibration_data(cs35l41->dev, silicon_uid,
+                                             cs35l41->index,
+                                             &cs35l41->cal_data);
+
+       /* Only return an error status if probe should be aborted */
+       if ((ret == -ENOENT) || (ret == -EOVERFLOW))
+               return 0;
+
+       if (ret < 0)
+               return ret;
+
+       cs35l41->cal_data_valid = true;
+
+       return 0;
+}
+
+
+static void cs35l41_set_default_tuning_params(struct cs35l41_hda *cs35l41)
+{
+       cs35l41->tuning_gain = DEFAULT_AMP_GAIN_PCM;
+}
+
+static int cs35l41_read_tuning_params(struct cs35l41_hda *cs35l41, const struct firmware *firmware)
+{
+       struct cs35l41_tuning_params *params;
+       unsigned int offset = 0;
+       unsigned int end;
+       int i;
+
+       params = (void *)&firmware->data[0];
+
+       if (le32_to_cpu(params->size) != firmware->size) {
+               dev_err(cs35l41->dev, "Wrong Size for Tuning Param file. Expected %d got %zu\n",
+                       le32_to_cpu(params->size), firmware->size);
+               return -EINVAL;
+       }
+
+       if (le32_to_cpu(params->version) != 1) {
+               dev_err(cs35l41->dev, "Unsupported Tuning Param Version: %d\n",
+                       le32_to_cpu(params->version));
+               return -EINVAL;
+       }
+
+       if (le32_to_cpu(params->signature) != CS35L41_TUNING_SIG) {
+               dev_err(cs35l41->dev,
+                       "Mismatched Signature for Tuning Param file. Expected %#x got %#x\n",
+                       CS35L41_TUNING_SIG, le32_to_cpu(params->signature));
+               return -EINVAL;
+       }
+
+       end = firmware->size - sizeof(struct cs35l41_tuning_params);
+
+       for (i = 0; i < le32_to_cpu(params->num_entries); i++) {
+               struct cs35l41_tuning_param *param;
+
+               if ((offset >= end) || ((offset + sizeof(struct cs35l41_tuning_param_hdr)) >= end))
+                       return -EFAULT;
+
+               param = (void *)&params->data[offset];
+               offset += le32_to_cpu(param->hdr.size);
+
+               if (offset > end)
+                       return -EFAULT;
+
+               switch (le32_to_cpu(param->hdr.type)) {
+               case TUNING_PARAM_GAIN:
+                       cs35l41->tuning_gain = le32_to_cpu(param->gain);
+                       dev_dbg(cs35l41->dev, "Applying Gain: %d\n", cs35l41->tuning_gain);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_filename)
+{
+       const struct firmware *tuning_param_file = NULL;
+       char *tuning_param_filename = NULL;
+       int ret;
+
+       ret = cs35l41_request_tuning_param_file(cs35l41, tuning_filename, &tuning_param_file,
+                                               &tuning_param_filename, cs35l41->acpi_subsystem_id);
+       if (ret) {
+               dev_dbg(cs35l41->dev, "Missing Tuning Param for file: %s: %d\n", tuning_filename,
+                       ret);
+               return 0;
+       }
+
+       ret = cs35l41_read_tuning_params(cs35l41, tuning_param_file);
+       if (ret) {
+               dev_err(cs35l41->dev, "Error reading Tuning Params from file: %s: %d\n",
+                       tuning_param_filename, ret);
+               /* Reset to default Tuning Parameters */
+               cs35l41_set_default_tuning_params(cs35l41);
+       }
+
+       release_firmware(tuning_param_file);
+       kfree(tuning_param_filename);
+
+       return ret;
+}
+
+static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
+{
+       const struct firmware *coeff_firmware = NULL;
+       const struct firmware *wmfw_firmware = NULL;
+       struct cs_dsp *dsp = &cs35l41->cs_dsp;
+       char *coeff_filename = NULL;
+       char *wmfw_filename = NULL;
+       int ret;
+
+       if (!cs35l41->halo_initialized) {
+               cs35l41_configure_cs_dsp(cs35l41->dev, cs35l41->regmap, dsp);
+               dsp->client_ops = &client_ops;
+
+               ret = cs_dsp_halo_init(&cs35l41->cs_dsp);
+               if (ret)
+                       return ret;
+               cs35l41->halo_initialized = true;
+       }
+
+       cs35l41_set_default_tuning_params(cs35l41);
+
+       ret = cs35l41_request_firmware_files(cs35l41, &wmfw_firmware, &wmfw_filename,
+                                            &coeff_firmware, &coeff_filename);
+       if (ret < 0)
+               return ret;
+
+       dev_dbg(cs35l41->dev, "Loading WMFW Firmware: %s\n", wmfw_filename);
+       if (coeff_filename) {
+               dev_dbg(cs35l41->dev, "Loading Coefficient File: %s\n", coeff_filename);
+               ret = cs35l41_load_tuning_params(cs35l41, coeff_filename);
+               if (ret)
+                       dev_warn(cs35l41->dev, "Unable to load Tuning Parameters: %d\n", ret);
+       } else {
+               dev_warn(cs35l41->dev, "No Coefficient File available.\n");
+       }
+
+       ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename,
+                             cs35l41_hda_fw_ids[cs35l41->firmware_type]);
+       if (ret)
+               goto err;
+
+       cs35l41_hda_apply_calibration(cs35l41);
+
+err:
+       if (ret)
+               cs35l41_set_default_tuning_params(cs35l41);
+       release_firmware(wmfw_firmware);
+       release_firmware(coeff_firmware);
+       kfree(wmfw_filename);
+       kfree(coeff_filename);
+
+       return ret;
+}
+
+static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41)
+{
+       struct cs_dsp *dsp = &cs35l41->cs_dsp;
+
+       cs35l41_set_default_tuning_params(cs35l41);
+       cs_dsp_stop(dsp);
+       cs_dsp_power_down(dsp);
+       dev_dbg(cs35l41->dev, "Unloaded Firmware\n");
+}
+
+static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41)
+{
+       struct cs_dsp *dsp = &cs35l41->cs_dsp;
+
+       cancel_work_sync(&cs35l41->fw_load_work);
+
+       mutex_lock(&cs35l41->fw_mutex);
+       cs35l41_shutdown_dsp(cs35l41);
+       cs_dsp_remove(dsp);
+       cs35l41->halo_initialized = false;
+       mutex_unlock(&cs35l41->fw_mutex);
+}
+
+/* Protection release cycle to get the speaker out of Safe-Mode */
+static void cs35l41_error_release(struct device *dev, struct regmap *regmap, unsigned int mask)
+{
+       regmap_write(regmap, CS35L41_PROTECT_REL_ERR_IGN, 0);
+       regmap_set_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
+       regmap_clear_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
+}
+
+/* Clear all errors to release safe mode. Global Enable must be cleared first. */
+static void cs35l41_irq_release(struct cs35l41_hda *cs35l41)
+{
+       cs35l41_error_release(cs35l41->dev, cs35l41->regmap, cs35l41->irq_errors);
+       cs35l41->irq_errors = 0;
+}
+
+static void cs35l41_update_mixer(struct cs35l41_hda *cs35l41)
+{
+       struct regmap *reg = cs35l41->regmap;
+       unsigned int asp_en = 0;
+       unsigned int dsp1rx2_src = 0;
+
+       regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
+
+       if (cs35l41->cs_dsp.running) {
+               asp_en |= CS35L41_ASP_TX1_EN_MASK; // ASP_TX1_EN = 1
+               regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
+                                      ARRAY_SIZE(cs35l41_hda_config_dsp));
+               if (cs35l41->hw_cfg.bst_type == CS35L41_INT_BOOST)
+                       regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VPMON);
+               else
+                       regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VBSTMON);
+       } else {
+               regmap_multi_reg_write(reg, cs35l41_hda_config_no_dsp,
+                                      ARRAY_SIZE(cs35l41_hda_config_no_dsp));
+       }
+
+       if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER) {
+               asp_en |= CS35L41_ASP_RX2_EN_MASK; // ASP_RX2_EN = 1
+               dsp1rx2_src = 0x00000009; // DSP1RX2 SRC = ASPRX2
+       } else {
+               dsp1rx2_src = 0x00000008; // DSP1RX2 SRC = ASPRX1
+       }
+
+       asp_en |= CS35L41_ASP_RX1_EN_MASK; // ASP_RX1_EN = 1
+
+       regmap_write(reg, CS35L41_SP_ENABLES, asp_en);
+       regmap_write(reg, CS35L41_DSP1_RX1_SRC, 0x00000008); // DSP1RX1 SRC = ASPRX1
+       regmap_write(reg, CS35L41_DSP1_RX2_SRC, dsp1rx2_src);
+}
+
+static void cs35l41_hda_play_start(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       struct regmap *reg = cs35l41->regmap;
+
+       dev_dbg(dev, "Play (Start)\n");
+
+       if (cs35l41->playback_started) {
+               dev_dbg(dev, "Playback already started.");
+               return;
+       }
+
+       cs35l41->playback_started = true;
+
+       cs35l41_update_mixer(cs35l41);
+
+       if (cs35l41->cs_dsp.running) {
+               regmap_update_bits(reg, CS35L41_PWR_CTRL2,
+                                  CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
+                                  1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT);
+               cs35l41_set_cspl_mbox_cmd(cs35l41->dev, reg, CSPL_MBOX_CMD_RESUME);
+       }
+       regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+               regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
+
+}
+
+static void cs35l41_mute(struct device *dev, bool mute)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       struct regmap *reg = cs35l41->regmap;
+       unsigned int amp_gain;
+
+       dev_dbg(dev, "Mute(%d:%d) Playback Started: %d\n", mute, cs35l41->mute_override,
+               cs35l41->playback_started);
+
+       if (cs35l41->playback_started) {
+               if (mute || cs35l41->mute_override) {
+                       dev_dbg(dev, "Muting\n");
+                       regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
+               } else {
+                       dev_dbg(dev, "Unmuting\n");
+                       if (cs35l41->cs_dsp.running) {
+                               dev_dbg(dev, "Using Tuned Gain: %d\n", cs35l41->tuning_gain);
+                               amp_gain = (cs35l41->tuning_gain << CS35L41_AMP_GAIN_PCM_SHIFT) |
+                                       (DEFAULT_AMP_GAIN_PDM << CS35L41_AMP_GAIN_PDM_SHIFT);
+
+                               /* AMP_HPF_PCM_EN = 1, AMP_VOL_PCM  0.0 dB */
+                               regmap_write(reg, CS35L41_AMP_DIG_VOL_CTRL, 0x00008000);
+                               regmap_write(reg, CS35L41_AMP_GAIN_CTRL, amp_gain);
+                       } else {
+                               regmap_multi_reg_write(reg, cs35l41_hda_unmute,
+                                               ARRAY_SIZE(cs35l41_hda_unmute));
+                       }
+               }
+       }
+}
+
+static void cs35l41_hda_play_done(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       struct regmap *reg = cs35l41->regmap;
+
+       dev_dbg(dev, "Play (Complete)\n");
+
+       cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1,
+                             &cs35l41->cs_dsp);
+       cs35l41_mute(dev, false);
+}
+
+static void cs35l41_hda_pause_start(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       struct regmap *reg = cs35l41->regmap;
+
+       dev_dbg(dev, "Pause (Start)\n");
+
+       cs35l41_mute(dev, true);
+       cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0,
+                             &cs35l41->cs_dsp);
+}
+
+static void cs35l41_hda_pause_done(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       struct regmap *reg = cs35l41->regmap;
+
+       dev_dbg(dev, "Pause (Complete)\n");
+
+       regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+               regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
+       if (cs35l41->cs_dsp.running) {
+               cs35l41_set_cspl_mbox_cmd(dev, reg, CSPL_MBOX_CMD_PAUSE);
+               regmap_update_bits(reg, CS35L41_PWR_CTRL2,
+                                  CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
+                                  0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT);
+       }
+       cs35l41_irq_release(cs35l41);
+       cs35l41->playback_started = false;
+}
+
+static void cs35l41_hda_pre_playback_hook(struct device *dev, int action)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+       switch (action) {
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               mutex_lock(&cs35l41->fw_mutex);
+               cs35l41_hda_pause_start(dev);
+               mutex_unlock(&cs35l41->fw_mutex);
+               break;
+       default:
+               break;
+       }
+}
+static void cs35l41_hda_playback_hook(struct device *dev, int action)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+       switch (action) {
+       case HDA_GEN_PCM_ACT_OPEN:
+               /*
+                * All amps must be resumed before we can start playing back.
+                * This ensures, for external boost, that all amps are in AMP_SAFE mode.
+                * Do this in HDA_GEN_PCM_ACT_OPEN, since this is run prior to any of the
+                * other actions.
+                */
+               pm_runtime_get_sync(dev);
+               break;
+       case HDA_GEN_PCM_ACT_PREPARE:
+               mutex_lock(&cs35l41->fw_mutex);
+               cs35l41_hda_play_start(dev);
+               mutex_unlock(&cs35l41->fw_mutex);
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               mutex_lock(&cs35l41->fw_mutex);
+               cs35l41_hda_pause_done(dev);
+               mutex_unlock(&cs35l41->fw_mutex);
+               break;
+       case HDA_GEN_PCM_ACT_CLOSE:
+               mutex_lock(&cs35l41->fw_mutex);
+               if (!cs35l41->cs_dsp.running && cs35l41->request_fw_load &&
+                   !cs35l41->fw_request_ongoing) {
+                       dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n");
+                       cs35l41->fw_request_ongoing = true;
+                       schedule_work(&cs35l41->fw_load_work);
+               }
+               mutex_unlock(&cs35l41->fw_mutex);
+
+               /*
+                * Playback must be finished for all amps before we start runtime suspend.
+                * This ensures no amps are playing back when we start putting them to sleep.
+                */
+               pm_runtime_put_autosuspend(dev);
+               break;
+       default:
+               break;
+       }
+}
+
+static void cs35l41_hda_post_playback_hook(struct device *dev, int action)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               mutex_lock(&cs35l41->fw_mutex);
+               cs35l41_hda_play_done(dev);
+               mutex_unlock(&cs35l41->fw_mutex);
+               break;
+       default:
+               break;
+       }
+}
+
+static int cs35l41_hda_channel_map(struct cs35l41_hda *cs35l41)
+{
+       unsigned int tx_num = 0;
+       unsigned int *tx_slot = NULL;
+       unsigned int rx_num;
+       unsigned int *rx_slot;
+       unsigned int mono = 0;
+
+       if (!cs35l41->amp_name) {
+               if (cs35l41->hw_cfg.spk_pos >= ARRAY_SIZE(channel_name))
+                       return -EINVAL;
+
+               cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%c%d",
+                                                  channel_name[cs35l41->hw_cfg.spk_pos],
+                                                  cs35l41->channel_index);
+               if (!cs35l41->amp_name)
+                       return -ENOMEM;
+       }
+
+       rx_num = 1;
+       if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER)
+               rx_slot = &mono;
+       else
+               rx_slot = &cs35l41->hw_cfg.spk_pos;
+
+       return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_num, tx_slot, rx_num,
+                                   rx_slot);
+}
+
+static int cs35l41_verify_id(struct cs35l41_hda *cs35l41, unsigned int *regid, unsigned int *reg_revid)
+{
+       unsigned int mtl_revid, chipid;
+       int ret;
+
+       ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, regid);
+       if (ret) {
+               dev_err_probe(cs35l41->dev, ret, "Get Device ID failed\n");
+               return ret;
+       }
+
+       ret = regmap_read(cs35l41->regmap, CS35L41_REVID, reg_revid);
+       if (ret) {
+               dev_err_probe(cs35l41->dev, ret, "Get Revision ID failed\n");
+               return ret;
+       }
+
+       mtl_revid = *reg_revid & CS35L41_MTLREVID_MASK;
+
+       chipid = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID;
+       if (*regid != chipid) {
+               dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", *regid, chipid);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41)
+{
+       mutex_lock(&cs35l41->fw_mutex);
+       if (cs35l41->cs_dsp.running) {
+               cs35l41->cs_dsp.running = false;
+               cs35l41->cs_dsp.booted = false;
+       }
+       regcache_mark_dirty(cs35l41->regmap);
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       return 0;
+}
+
+static int cs35l41_system_suspend_prep(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+       dev_dbg(cs35l41->dev, "System Suspend Prepare\n");
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
+               dev_err_once(cs35l41->dev, "System Suspend not supported\n");
+               return 0; /* don't block the whole system suspend */
+       }
+
+       mutex_lock(&cs35l41->fw_mutex);
+       if (cs35l41->playback_started)
+               cs35l41_hda_pause_start(dev);
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       return 0;
+}
+
+static int cs35l41_system_suspend(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(cs35l41->dev, "System Suspend\n");
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
+               dev_err_once(cs35l41->dev, "System Suspend not supported\n");
+               return 0; /* don't block the whole system suspend */
+       }
+
+       mutex_lock(&cs35l41->fw_mutex);
+       if (cs35l41->playback_started)
+               cs35l41_hda_pause_done(dev);
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       ret = pm_runtime_force_suspend(dev);
+       if (ret) {
+               dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret);
+               return ret;
+       }
+
+       /* Shutdown DSP before system suspend */
+       ret = cs35l41_ready_for_reset(cs35l41);
+       if (ret)
+               dev_err(dev, "System Suspend Failed, not ready for Reset: %d\n", ret);
+
+       if (cs35l41->reset_gpio) {
+               dev_info(cs35l41->dev, "Asserting Reset\n");
+               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
+               usleep_range(2000, 2100);
+       }
+
+       dev_dbg(cs35l41->dev, "System Suspended\n");
+
+       return ret;
+}
+
+static int cs35l41_wait_boot_done(struct cs35l41_hda *cs35l41)
+{
+       unsigned int int_status;
+       int ret;
+
+       ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, int_status,
+                                      int_status & CS35L41_OTP_BOOT_DONE, 1000, 100000);
+       if (ret) {
+               dev_err(cs35l41->dev, "Failed waiting for OTP_BOOT_DONE\n");
+               return ret;
+       }
+
+       ret = regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_status);
+       if (ret || (int_status & CS35L41_OTP_BOOT_ERR)) {
+               dev_err(cs35l41->dev, "OTP Boot status %x error\n",
+                       int_status & CS35L41_OTP_BOOT_ERR);
+               if (!ret)
+                       ret = -EIO;
+               return ret;
+       }
+
+       return 0;
+}
+
+static int cs35l41_system_resume(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       int ret;
+
+       dev_dbg(cs35l41->dev, "System Resume\n");
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
+               dev_err_once(cs35l41->dev, "System Resume not supported\n");
+               return 0; /* don't block the whole system resume */
+       }
+
+       if (cs35l41->reset_gpio) {
+               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
+               usleep_range(2000, 2100);
+               gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
+       }
+
+       usleep_range(2000, 2100);
+
+       regcache_cache_only(cs35l41->regmap, false);
+
+       regmap_write(cs35l41->regmap, CS35L41_SFT_RESET, CS35L41_SOFTWARE_RESET);
+       usleep_range(2000, 2100);
+
+       ret = cs35l41_wait_boot_done(cs35l41);
+       if (ret)
+               return ret;
+
+       regcache_cache_only(cs35l41->regmap, true);
+
+       ret = pm_runtime_force_resume(dev);
+       if (ret) {
+               dev_err(dev, "System Resume Failed: Unable to runtime resume: %d\n", ret);
+               return ret;
+       }
+
+       mutex_lock(&cs35l41->fw_mutex);
+
+       if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) {
+               cs35l41->fw_request_ongoing = true;
+               schedule_work(&cs35l41->fw_load_work);
+       }
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       return ret;
+}
+
+static int cs35l41_runtime_idle(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
+               return -EBUSY; /* suspend not supported yet on this model */
+       return 0;
+}
+
+static int cs35l41_runtime_suspend(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       int ret = 0;
+
+       dev_dbg(cs35l41->dev, "Runtime Suspend\n");
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
+               dev_dbg(cs35l41->dev, "Runtime Suspend not supported\n");
+               return 0;
+       }
+
+       mutex_lock(&cs35l41->fw_mutex);
+
+       if (cs35l41->cs_dsp.running) {
+               ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap,
+                                             cs35l41->hw_cfg.bst_type);
+               if (ret)
+                       goto err;
+       } else {
+               cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
+       }
+
+       regcache_cache_only(cs35l41->regmap, true);
+       regcache_mark_dirty(cs35l41->regmap);
+
+err:
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       return ret;
+}
+
+static int cs35l41_runtime_resume(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       unsigned int regid, reg_revid;
+       int ret = 0;
+
+       dev_dbg(cs35l41->dev, "Runtime Resume\n");
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
+               dev_dbg(cs35l41->dev, "Runtime Resume not supported\n");
+               return 0;
+       }
+
+       mutex_lock(&cs35l41->fw_mutex);
+
+       regcache_cache_only(cs35l41->regmap, false);
+
+       if (cs35l41->cs_dsp.running)    {
+               ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
+               if (ret) {
+                       dev_warn(cs35l41->dev, "Unable to exit Hibernate.");
+                       goto err;
+               }
+       }
+
+       ret = cs35l41_verify_id(cs35l41, &regid, &reg_revid);
+       if (ret)
+               goto err;
+
+       /* Test key needs to be unlocked to allow the OTP settings to re-apply */
+       cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
+       ret = regcache_sync(cs35l41->regmap);
+       cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
+       if (ret) {
+               dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
+               goto err;
+       }
+
+       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
+               cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
+
+       dev_dbg(cs35l41->dev, "CS35L41 Resumed (%x), Revision: %02X\n", regid, reg_revid);
+
+err:
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       return ret;
+}
+
+static int cs35l41_hda_read_ctl(struct cs_dsp *dsp, const char *name, int type,
+                               unsigned int alg, void *buf, size_t len)
+{
+       int ret;
+
+       mutex_lock(&dsp->pwr_lock);
+       ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len);
+       mutex_unlock(&dsp->pwr_lock);
+
+       return ret;
+}
+
+static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
+{
+       unsigned int fw_status;
+       __be32 halo_sts;
+       int ret;
+
+       if (cs35l41->bypass_fw) {
+               dev_warn(cs35l41->dev, "Bypassing Firmware.\n");
+               return 0;
+       }
+
+       ret = cs35l41_init_dsp(cs35l41);
+       if (ret) {
+               dev_warn(cs35l41->dev, "Cannot Initialize Firmware. Error: %d\n", ret);
+               goto clean_dsp;
+       }
+
+       ret = cs35l41_write_fs_errata(cs35l41->dev, cs35l41->regmap);
+       if (ret) {
+               dev_err(cs35l41->dev, "Cannot Write FS Errata: %d\n", ret);
+               goto clean_dsp;
+       }
+
+       ret = cs_dsp_run(&cs35l41->cs_dsp);
+       if (ret) {
+               dev_err(cs35l41->dev, "Fail to start dsp: %d\n", ret);
+               goto clean_dsp;
+       }
+
+       ret = read_poll_timeout(cs35l41_hda_read_ctl, ret,
+                               be32_to_cpu(halo_sts) == HALO_STATE_CODE_RUN,
+                               1000, 15000, false, &cs35l41->cs_dsp, HALO_STATE_DSP_CTL_NAME,
+                               HALO_STATE_DSP_CTL_TYPE, HALO_STATE_DSP_CTL_ALG,
+                               &halo_sts, sizeof(halo_sts));
+
+       if (ret) {
+               dev_err(cs35l41->dev, "Timeout waiting for HALO Core to start. State: %u\n",
+                        halo_sts);
+               goto clean_dsp;
+       }
+
+       ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &fw_status);
+       if (ret < 0) {
+               dev_err(cs35l41->dev,
+                       "Failed to read firmware status: %d\n", ret);
+               goto clean_dsp;
+       }
+
+       switch (fw_status) {
+       case CSPL_MBOX_STS_RUNNING:
+       case CSPL_MBOX_STS_PAUSED:
+               break;
+       default:
+               dev_err(cs35l41->dev, "Firmware status is invalid: %u\n",
+                       fw_status);
+               ret = -EINVAL;
+               goto clean_dsp;
+       }
+
+       ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE);
+       if (ret) {
+               dev_err(cs35l41->dev, "Error waiting for DSP to pause: %u\n", ret);
+               goto clean_dsp;
+       }
+
+       dev_info(cs35l41->dev, "Firmware Loaded - Type: %s, Gain: %d\n",
+                cs35l41_hda_fw_ids[cs35l41->firmware_type], cs35l41->tuning_gain);
+
+       return 0;
+
+clean_dsp:
+       cs35l41_shutdown_dsp(cs35l41);
+       return ret;
+}
+
+static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load)
+{
+       if (cs35l41->cs_dsp.running && !load) {
+               dev_dbg(cs35l41->dev, "Unloading Firmware\n");
+               cs35l41_shutdown_dsp(cs35l41);
+       } else if (!cs35l41->cs_dsp.running && load) {
+               dev_dbg(cs35l41->dev, "Loading Firmware\n");
+               cs35l41_smart_amp(cs35l41);
+       } else {
+               dev_dbg(cs35l41->dev, "Unable to Load firmware.\n");
+       }
+}
+
+static int cs35l41_fw_load_ctl_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = cs35l41->request_fw_load;
+       return 0;
+}
+
+static int cs35l41_mute_override_ctl_get(struct snd_kcontrol *kcontrol,
+                                        struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = cs35l41->mute_override;
+       return 0;
+}
+
+static void cs35l41_fw_load_work(struct work_struct *work)
+{
+       struct cs35l41_hda *cs35l41 = container_of(work, struct cs35l41_hda, fw_load_work);
+
+       pm_runtime_get_sync(cs35l41->dev);
+
+       mutex_lock(&cs35l41->fw_mutex);
+
+       /* Recheck if playback is ongoing, mutex will block playback during firmware loading */
+       if (cs35l41->playback_started)
+               dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback. Retrying...\n");
+       else
+               cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load);
+
+       cs35l41->fw_request_ongoing = false;
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       pm_runtime_put_autosuspend(cs35l41->dev);
+}
+
+static int cs35l41_fw_load_ctl_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+       if (cs35l41->request_fw_load == ucontrol->value.integer.value[0])
+               return 0;
+
+       if (cs35l41->fw_request_ongoing) {
+               dev_dbg(cs35l41->dev, "Existing request not complete\n");
+               return -EBUSY;
+       }
+
+       /* Check if playback is ongoing when initial request is made */
+       if (cs35l41->playback_started) {
+               dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n");
+               return -EBUSY;
+       }
+
+       cs35l41->fw_request_ongoing = true;
+       cs35l41->request_fw_load = ucontrol->value.integer.value[0];
+       schedule_work(&cs35l41->fw_load_work);
+
+       return 1;
+}
+
+static int cs35l41_fw_type_ctl_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.enumerated.item[0] = cs35l41->firmware_type;
+
+       return 0;
+}
+
+static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
+
+       if (ucontrol->value.enumerated.item[0] < CS35L41_HDA_NUM_FW) {
+               if (cs35l41->firmware_type != ucontrol->value.enumerated.item[0]) {
+                       cs35l41->firmware_type = ucontrol->value.enumerated.item[0];
+                       return 1;
+               } else {
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
+{
+       return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(cs35l41_hda_fw_ids), cs35l41_hda_fw_ids);
+}
+
+static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
+{
+       char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char fw_load_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       char mute_override_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+       struct snd_kcontrol_new fw_type_ctl = {
+               .name = fw_type_ctl_name,
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = cs35l41_fw_type_ctl_info,
+               .get = cs35l41_fw_type_ctl_get,
+               .put = cs35l41_fw_type_ctl_put,
+       };
+       struct snd_kcontrol_new fw_load_ctl = {
+               .name = fw_load_ctl_name,
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = snd_ctl_boolean_mono_info,
+               .get = cs35l41_fw_load_ctl_get,
+               .put = cs35l41_fw_load_ctl_put,
+       };
+       struct snd_kcontrol_new mute_override_ctl = {
+               .name = mute_override_ctl_name,
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = snd_ctl_boolean_mono_info,
+               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+               .get = cs35l41_mute_override_ctl_get,
+       };
+       int ret;
+
+       scnprintf(fw_type_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Type",
+                 cs35l41->amp_name);
+       scnprintf(fw_load_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Load",
+                 cs35l41->amp_name);
+       scnprintf(mute_override_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s Forced Mute Status",
+                 cs35l41->amp_name);
+
+       ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_type_ctl, cs35l41));
+       if (ret) {
+               dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_type_ctl.name, ret);
+               return ret;
+       }
+
+       dev_dbg(cs35l41->dev, "Added Control %s\n", fw_type_ctl.name);
+
+       ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_load_ctl, cs35l41));
+       if (ret) {
+               dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_load_ctl.name, ret);
+               return ret;
+       }
+
+       dev_dbg(cs35l41->dev, "Added Control %s\n", fw_load_ctl.name);
+
+       ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&mute_override_ctl, cs35l41));
+       if (ret) {
+               dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", mute_override_ctl.name,
+                       ret);
+               return ret;
+       }
+
+       dev_dbg(cs35l41->dev, "Added Control %s\n", mute_override_ctl.name);
+
+       return 0;
+}
+
+static bool cs35l41_dsm_supported(acpi_handle handle, unsigned int commands)
+{
+       guid_t guid;
+
+       guid_parse(CS35L41_UUID, &guid);
+
+       return acpi_check_dsm(handle, &guid, 0, BIT(commands));
+}
+
+static int cs35l41_get_acpi_mute_state(struct cs35l41_hda *cs35l41, acpi_handle handle)
+{
+       guid_t guid;
+       union acpi_object *ret;
+       int mute = -ENODEV;
+
+       guid_parse(CS35L41_UUID, &guid);
+
+       if (cs35l41_dsm_supported(handle, CS35L41_DSM_GET_MUTE)) {
+               ret = acpi_evaluate_dsm(handle, &guid, 0, CS35L41_DSM_GET_MUTE, NULL);
+               mute = *ret->buffer.pointer;
+               dev_dbg(cs35l41->dev, "CS35L41_DSM_GET_MUTE: %d\n", mute);
+       }
+
+       dev_dbg(cs35l41->dev, "%s: %d\n", __func__, mute);
+
+       return mute;
+}
+
+static void cs35l41_acpi_device_notify(acpi_handle handle, u32 event, struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       int mute;
+
+       if (event != CS35L41_NOTIFY_EVENT)
+               return;
+
+       mute = cs35l41_get_acpi_mute_state(cs35l41, handle);
+       if (mute < 0) {
+               dev_warn(cs35l41->dev, "Unable to retrieve mute state: %d\n", mute);
+               return;
+       }
+
+       dev_dbg(cs35l41->dev, "Requesting mute value: %d\n", mute);
+       cs35l41->mute_override = (mute > 0);
+       cs35l41_mute(cs35l41->dev, cs35l41->mute_override);
+}
+
+static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       struct hda_component_parent *parent = master_data;
+       struct hda_component *comp;
+       unsigned int sleep_flags;
+       int ret = 0;
+
+       comp = hda_component_from_index(parent, cs35l41->index);
+       if (!comp)
+               return -EINVAL;
+
+       if (comp->dev)
+               return -EBUSY;
+
+       pm_runtime_get_sync(dev);
+
+       mutex_lock(&cs35l41->fw_mutex);
+
+       comp->dev = dev;
+       cs35l41->codec = parent->codec;
+       if (!cs35l41->acpi_subsystem_id)
+               cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x",
+                                                      cs35l41->codec->core.subsystem_id);
+
+       strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+
+       cs35l41->firmware_type = CS35L41_HDA_FW_SPK_PROT;
+
+       if (firmware_autostart) {
+               dev_dbg(cs35l41->dev, "Firmware Autostart.\n");
+               cs35l41->request_fw_load = true;
+               if (cs35l41_smart_amp(cs35l41) < 0)
+                       dev_warn(cs35l41->dev, "Cannot Run Firmware, reverting to dsp bypass...\n");
+       } else {
+               dev_dbg(cs35l41->dev, "Firmware Autostart is disabled.\n");
+       }
+
+       ret = cs35l41_create_controls(cs35l41);
+
+       comp->playback_hook = cs35l41_hda_playback_hook;
+       comp->pre_playback_hook = cs35l41_hda_pre_playback_hook;
+       comp->post_playback_hook = cs35l41_hda_post_playback_hook;
+       comp->acpi_notify = cs35l41_acpi_device_notify;
+       comp->adev = cs35l41->dacpi;
+
+       comp->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comp->adev),
+               CS35L41_DSM_GET_MUTE);
+
+       cs35l41->mute_override = cs35l41_get_acpi_mute_state(cs35l41,
+                                               acpi_device_handle(cs35l41->dacpi)) > 0;
+
+       mutex_unlock(&cs35l41->fw_mutex);
+
+       sleep_flags = lock_system_sleep();
+       if (!device_link_add(&cs35l41->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS))
+               dev_warn(dev, "Unable to create device link\n");
+       unlock_system_sleep(sleep_flags);
+
+       pm_runtime_put_autosuspend(dev);
+
+       dev_info(cs35l41->dev,
+                "CS35L41 Bound - SSID: %s, BST: %d, VSPK: %d, CH: %c, FW EN: %d, SPKID: %d\n",
+                cs35l41->acpi_subsystem_id, cs35l41->hw_cfg.bst_type,
+                cs35l41->hw_cfg.gpio1.func == CS35l41_VSPK_SWITCH,
+                channel_name[cs35l41->hw_cfg.spk_pos],
+                cs35l41->cs_dsp.running, cs35l41->speaker_id);
+
+       return ret;
+}
+
+static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+       struct hda_component_parent *parent = master_data;
+       struct hda_component *comp;
+       unsigned int sleep_flags;
+
+       comp = hda_component_from_index(parent, cs35l41->index);
+       if (!comp)
+               return;
+
+       if (comp->dev == dev) {
+               sleep_flags = lock_system_sleep();
+               device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev);
+               unlock_system_sleep(sleep_flags);
+               memset(comp, 0, sizeof(*comp));
+       }
+}
+
+static const struct component_ops cs35l41_hda_comp_ops = {
+       .bind = cs35l41_hda_bind,
+       .unbind = cs35l41_hda_unbind,
+};
+
+static irqreturn_t cs35l41_bst_short_err(int irq, void *data)
+{
+       struct cs35l41_hda *cs35l41 = data;
+
+       dev_crit_ratelimited(cs35l41->dev, "LBST Error\n");
+       set_bit(CS35L41_BST_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_bst_dcm_uvp_err(int irq, void *data)
+{
+       struct cs35l41_hda *cs35l41 = data;
+
+       dev_crit_ratelimited(cs35l41->dev, "DCM VBST Under Voltage Error\n");
+       set_bit(CS35L41_BST_UVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_bst_ovp_err(int irq, void *data)
+{
+       struct cs35l41_hda *cs35l41 = data;
+
+       dev_crit_ratelimited(cs35l41->dev, "VBST Over Voltage error\n");
+       set_bit(CS35L41_BST_OVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_temp_err(int irq, void *data)
+{
+       struct cs35l41_hda *cs35l41 = data;
+
+       dev_crit_ratelimited(cs35l41->dev, "Over temperature error\n");
+       set_bit(CS35L41_TEMP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_temp_warn(int irq, void *data)
+{
+       struct cs35l41_hda *cs35l41 = data;
+
+       dev_crit_ratelimited(cs35l41->dev, "Over temperature warning\n");
+       set_bit(CS35L41_TEMP_WARN_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t cs35l41_amp_short(int irq, void *data)
+{
+       struct cs35l41_hda *cs35l41 = data;
+
+       dev_crit_ratelimited(cs35l41->dev, "Amp short error\n");
+       set_bit(CS35L41_AMP_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
+
+       return IRQ_HANDLED;
+}
+
+static const struct cs35l41_irq cs35l41_irqs[] = {
+       CS35L41_IRQ(BST_OVP_ERR, "Boost Overvoltage Error", cs35l41_bst_ovp_err),
+       CS35L41_IRQ(BST_DCM_UVP_ERR, "Boost Undervoltage Error", cs35l41_bst_dcm_uvp_err),
+       CS35L41_IRQ(BST_SHORT_ERR, "Boost Inductor Short Error", cs35l41_bst_short_err),
+       CS35L41_IRQ(TEMP_WARN, "Temperature Warning", cs35l41_temp_warn),
+       CS35L41_IRQ(TEMP_ERR, "Temperature Error", cs35l41_temp_err),
+       CS35L41_IRQ(AMP_SHORT_ERR, "Amp Short", cs35l41_amp_short),
+};
+
+static const struct regmap_irq cs35l41_reg_irqs[] = {
+       CS35L41_REG_IRQ(IRQ1_STATUS1, BST_OVP_ERR),
+       CS35L41_REG_IRQ(IRQ1_STATUS1, BST_DCM_UVP_ERR),
+       CS35L41_REG_IRQ(IRQ1_STATUS1, BST_SHORT_ERR),
+       CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_WARN),
+       CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_ERR),
+       CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR),
+};
+
+static const struct regmap_irq_chip cs35l41_regmap_irq_chip = {
+       .name = "cs35l41 IRQ1 Controller",
+       .status_base = CS35L41_IRQ1_STATUS1,
+       .mask_base = CS35L41_IRQ1_MASK1,
+       .ack_base = CS35L41_IRQ1_STATUS1,
+       .num_regs = 4,
+       .irqs = cs35l41_reg_irqs,
+       .num_irqs = ARRAY_SIZE(cs35l41_reg_irqs),
+       .runtime_pm = true,
+};
+
+static void cs35l41_configure_interrupt(struct cs35l41_hda *cs35l41, int irq_pol)
+{
+       int irq;
+       int ret;
+       int i;
+
+       if (!cs35l41->irq) {
+               dev_warn(cs35l41->dev, "No Interrupt Found");
+               goto err;
+       }
+
+       ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq,
+                                       IRQF_ONESHOT | IRQF_SHARED | irq_pol,
+                                       0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data);
+       if (ret) {
+               dev_dbg(cs35l41->dev, "Unable to add IRQ Chip: %d.", ret);
+               goto err;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) {
+               irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq);
+               if (irq < 0) {
+                       ret = irq;
+                       dev_dbg(cs35l41->dev, "Unable to map IRQ %s: %d.", cs35l41_irqs[i].name,
+                               ret);
+                       goto err;
+               }
+
+               ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL,
+                                               cs35l41_irqs[i].handler,
+                                               IRQF_ONESHOT | IRQF_SHARED | irq_pol,
+                                               cs35l41_irqs[i].name, cs35l41);
+               if (ret) {
+                       dev_dbg(cs35l41->dev, "Unable to allocate IRQ %s:: %d.",
+                               cs35l41_irqs[i].name, ret);
+                       goto err;
+               }
+       }
+       return;
+err:
+       dev_warn(cs35l41->dev,
+                "IRQ Config Failed. Amp errors may not be recoverable without reboot.");
+}
+
+static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
+{
+       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+       bool using_irq = false;
+       int irq_pol;
+       int ret;
+
+       if (!cs35l41->hw_cfg.valid)
+               return -EINVAL;
+
+       ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg);
+       if (ret)
+               return ret;
+
+       if (hw_cfg->gpio1.valid) {
+               switch (hw_cfg->gpio1.func) {
+               case CS35L41_NOT_USED:
+                       break;
+               case CS35l41_VSPK_SWITCH:
+                       hw_cfg->gpio1.func = CS35L41_GPIO1_GPIO;
+                       hw_cfg->gpio1.out_en = true;
+                       break;
+               case CS35l41_SYNC:
+                       hw_cfg->gpio1.func = CS35L41_GPIO1_MDSYNC;
+                       break;
+               default:
+                       dev_err(cs35l41->dev, "Invalid function %d for GPIO1\n",
+                               hw_cfg->gpio1.func);
+                       return -EINVAL;
+               }
+       }
+
+       if (hw_cfg->gpio2.valid) {
+               switch (hw_cfg->gpio2.func) {
+               case CS35L41_NOT_USED:
+                       break;
+               case CS35L41_INTERRUPT:
+                       using_irq = true;
+                       hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN;
+                       break;
+               default:
+                       dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func);
+                       return -EINVAL;
+               }
+       }
+
+       irq_pol = cs35l41_gpio_config(cs35l41->regmap, hw_cfg);
+
+       if (using_irq)
+               cs35l41_configure_interrupt(cs35l41, irq_pol);
+
+       return cs35l41_hda_channel_map(cs35l41);
+}
+
+int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id)
+{
+       struct gpio_desc *speaker_id_desc;
+       int speaker_id = -ENODEV;
+
+       if (fixed_gpio_id >= 0) {
+               dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id);
+               speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN);
+               if (IS_ERR(speaker_id_desc)) {
+                       speaker_id = PTR_ERR(speaker_id_desc);
+                       return speaker_id;
+               }
+               speaker_id = gpiod_get_value_cansleep(speaker_id_desc);
+               gpiod_put(speaker_id_desc);
+               dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
+       } else {
+               int base_index;
+               int gpios_per_amp;
+               int count;
+               int tmp;
+               int i;
+
+               count = gpiod_count(dev, "spk-id");
+               if (count > 0) {
+                       speaker_id = 0;
+                       gpios_per_amp = count / num_amps;
+                       base_index = gpios_per_amp * amp_index;
+
+                       if (count % num_amps)
+                               return -EINVAL;
+
+                       dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp);
+
+                       for (i = 0; i < gpios_per_amp; i++) {
+                               speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index,
+                                                                 GPIOD_IN);
+                               if (IS_ERR(speaker_id_desc)) {
+                                       speaker_id = PTR_ERR(speaker_id_desc);
+                                       break;
+                               }
+                               tmp = gpiod_get_value_cansleep(speaker_id_desc);
+                               gpiod_put(speaker_id_desc);
+                               if (tmp < 0) {
+                                       speaker_id = tmp;
+                                       break;
+                               }
+                               speaker_id |= tmp << i;
+                       }
+                       dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
+               }
+       }
+       return speaker_id;
+}
+
+int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id)
+{
+       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+       u32 values[HDA_MAX_COMPONENTS];
+       char *property;
+       size_t nval;
+       int i, ret;
+
+       property = "cirrus,dev-index";
+       ret = device_property_count_u32(physdev, property);
+       if (ret <= 0)
+               goto err;
+
+       if (ret > ARRAY_SIZE(values)) {
+               ret = -EINVAL;
+               goto err;
+       }
+       nval = ret;
+
+       ret = device_property_read_u32_array(physdev, property, values, nval);
+       if (ret)
+               goto err;
+
+       cs35l41->index = -1;
+       for (i = 0; i < nval; i++) {
+               if (values[i] == id) {
+                       cs35l41->index = i;
+                       break;
+               }
+       }
+       if (cs35l41->index == -1) {
+               dev_err(cs35l41->dev, "No index found in %s\n", property);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       /* To use the same release code for all laptop variants we can't use devm_ version of
+        * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node
+        */
+       cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
+                                                    cs35l41->index, GPIOD_OUT_LOW,
+                                                    "cs35l41-reset");
+
+       property = "cirrus,speaker-position";
+       ret = device_property_read_u32_array(physdev, property, values, nval);
+       if (ret)
+               goto err;
+       hw_cfg->spk_pos = values[cs35l41->index];
+
+       cs35l41->channel_index = 0;
+       for (i = 0; i < cs35l41->index; i++)
+               if (values[i] == hw_cfg->spk_pos)
+                       cs35l41->channel_index++;
+
+       property = "cirrus,gpio1-func";
+       ret = device_property_read_u32_array(physdev, property, values, nval);
+       if (ret)
+               goto err;
+       hw_cfg->gpio1.func = values[cs35l41->index];
+       hw_cfg->gpio1.valid = true;
+
+       property = "cirrus,gpio2-func";
+       ret = device_property_read_u32_array(physdev, property, values, nval);
+       if (ret)
+               goto err;
+       hw_cfg->gpio2.func = values[cs35l41->index];
+       hw_cfg->gpio2.valid = true;
+
+       property = "cirrus,boost-peak-milliamp";
+       ret = device_property_read_u32_array(physdev, property, values, nval);
+       if (ret == 0)
+               hw_cfg->bst_ipk = values[cs35l41->index];
+       else
+               hw_cfg->bst_ipk = -1;
+
+       property = "cirrus,boost-ind-nanohenry";
+       ret = device_property_read_u32_array(physdev, property, values, nval);
+       if (ret == 0)
+               hw_cfg->bst_ind = values[cs35l41->index];
+       else
+               hw_cfg->bst_ind = -1;
+
+       property = "cirrus,boost-cap-microfarad";
+       ret = device_property_read_u32_array(physdev, property, values, nval);
+       if (ret == 0)
+               hw_cfg->bst_cap = values[cs35l41->index];
+       else
+               hw_cfg->bst_cap = -1;
+
+       cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, nval, -1);
+
+       if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
+               hw_cfg->bst_type = CS35L41_INT_BOOST;
+       else
+               hw_cfg->bst_type = CS35L41_EXT_BOOST;
+
+       hw_cfg->valid = true;
+
+       return 0;
+err:
+       dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
+       hw_cfg->valid = false;
+       hw_cfg->gpio1.valid = false;
+       hw_cfg->gpio2.valid = false;
+       acpi_dev_put(cs35l41->dacpi);
+
+       return ret;
+}
+
+static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
+{
+       struct acpi_device *adev;
+       struct device *physdev;
+       struct spi_device *spi;
+       const char *sub;
+       int ret;
+
+       adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
+       if (!adev) {
+               dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
+               return -ENODEV;
+       }
+
+       cs35l41->dacpi = adev;
+       physdev = get_device(acpi_get_first_physical_node(adev));
+
+       sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
+       if (IS_ERR(sub))
+               sub = NULL;
+       cs35l41->acpi_subsystem_id = sub;
+
+       ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid);
+       if (!ret) {
+               dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n");
+               goto out;
+       }
+
+       ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id);
+       if (ret) {
+               put_device(physdev);
+               return ret;
+       }
+out:
+       put_device(physdev);
+
+       cs35l41->bypass_fw = false;
+       if (cs35l41->control_bus == SPI) {
+               spi = to_spi_device(cs35l41->dev);
+               if (spi->max_speed_hz < CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ) {
+                       dev_warn(cs35l41->dev,
+                                "SPI speed is too slow to support firmware download: %d Hz.\n",
+                                spi->max_speed_hz);
+                       cs35l41->bypass_fw = true;
+               }
+       }
+
+       return 0;
+}
+
+int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
+                     struct regmap *regmap, enum control_bus control_bus)
+{
+       unsigned int regid, reg_revid;
+       struct cs35l41_hda *cs35l41;
+       int ret;
+
+       BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != ARRAY_SIZE(cs35l41_reg_irqs));
+       BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != CS35L41_NUM_IRQ);
+
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
+       cs35l41 = devm_kzalloc(dev, sizeof(*cs35l41), GFP_KERNEL);
+       if (!cs35l41)
+               return -ENOMEM;
+
+       cs35l41->dev = dev;
+       cs35l41->irq = irq;
+       cs35l41->regmap = regmap;
+       cs35l41->control_bus = control_bus;
+       dev_set_drvdata(dev, cs35l41);
+
+       ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
+       if (ret)
+               return dev_err_probe(cs35l41->dev, ret, "Platform not supported\n");
+
+       if (IS_ERR(cs35l41->reset_gpio)) {
+               ret = PTR_ERR(cs35l41->reset_gpio);
+               cs35l41->reset_gpio = NULL;
+               if (ret == -EBUSY) {
+                       dev_info(cs35l41->dev, "Reset line busy, assuming shared reset\n");
+               } else {
+                       dev_err_probe(cs35l41->dev, ret, "Failed to get reset GPIO\n");
+                       goto err;
+               }
+       }
+       if (cs35l41->reset_gpio) {
+               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
+               usleep_range(2000, 2100);
+               gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
+       }
+
+       usleep_range(2000, 2100);
+       regmap_write(cs35l41->regmap, CS35L41_SFT_RESET, CS35L41_SOFTWARE_RESET);
+       usleep_range(2000, 2100);
+
+       ret = cs35l41_wait_boot_done(cs35l41);
+       if (ret)
+               goto err;
+
+       ret = cs35l41_verify_id(cs35l41, &regid, &reg_revid);
+       if (ret)
+               goto err;
+
+       ret = cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
+       if (ret)
+               goto err;
+
+       ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid);
+       if (ret)
+               goto err;
+
+       ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
+       if (ret) {
+               dev_err_probe(cs35l41->dev, ret, "OTP Unpack failed\n");
+               goto err;
+       }
+
+       ret = cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
+       if (ret)
+               goto err;
+
+       ret = cs35l41_get_calibration(cs35l41);
+       if (ret && ret != -ENOENT)
+               goto err;
+
+       cs35l41_mute(cs35l41->dev, true);
+
+       INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work);
+       mutex_init(&cs35l41->fw_mutex);
+
+       pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
+       pm_runtime_use_autosuspend(cs35l41->dev);
+       pm_runtime_set_active(cs35l41->dev);
+       pm_runtime_get_noresume(cs35l41->dev);
+       pm_runtime_enable(cs35l41->dev);
+
+       ret = cs35l41_hda_apply_properties(cs35l41);
+       if (ret)
+               goto err_pm;
+
+       pm_runtime_put_autosuspend(cs35l41->dev);
+
+       ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops);
+       if (ret) {
+               dev_err_probe(cs35l41->dev, ret, "Register component failed\n");
+               goto err_pm;
+       }
+
+       dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", regid, reg_revid);
+
+       return 0;
+
+err_pm:
+       pm_runtime_dont_use_autosuspend(cs35l41->dev);
+       pm_runtime_disable(cs35l41->dev);
+       pm_runtime_put_noidle(cs35l41->dev);
+
+err:
+       if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
+               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
+       gpiod_put(cs35l41->reset_gpio);
+       gpiod_put(cs35l41->cs_gpio);
+       acpi_dev_put(cs35l41->dacpi);
+       kfree(cs35l41->acpi_subsystem_id);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, "SND_HDA_SCODEC_CS35L41");
+
+void cs35l41_hda_remove(struct device *dev)
+{
+       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
+
+       component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
+
+       pm_runtime_get_sync(cs35l41->dev);
+       pm_runtime_dont_use_autosuspend(cs35l41->dev);
+       pm_runtime_disable(cs35l41->dev);
+
+       if (cs35l41->halo_initialized)
+               cs35l41_remove_dsp(cs35l41);
+
+       acpi_dev_put(cs35l41->dacpi);
+
+       pm_runtime_put_noidle(cs35l41->dev);
+
+       if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
+               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
+       gpiod_put(cs35l41->reset_gpio);
+       gpiod_put(cs35l41->cs_gpio);
+       kfree(cs35l41->acpi_subsystem_id);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, "SND_HDA_SCODEC_CS35L41");
+
+const struct dev_pm_ops cs35l41_hda_pm_ops = {
+       RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume,
+                      cs35l41_runtime_idle)
+       .prepare = cs35l41_system_suspend_prep,
+       SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
+};
+EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, "SND_HDA_SCODEC_CS35L41");
+
+MODULE_DESCRIPTION("CS35L41 HDA Driver");
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
+MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("FW_CS_DSP");
+MODULE_FIRMWARE("cirrus/cs35l41-*.wmfw");
+MODULE_FIRMWARE("cirrus/cs35l41-*.bin");
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda.h b/sound/hda/codecs/side-codecs/cs35l41_hda.h
new file mode 100644 (file)
index 0000000..7d003c5
--- /dev/null
@@ -0,0 +1,110 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * CS35L41 ALSA HDA audio driver
+ *
+ * Copyright 2021 Cirrus Logic, Inc.
+ *
+ * Author: Lucas Tanure <tanureal@opensource.cirrus.com>
+ */
+
+#ifndef __CS35L41_HDA_H__
+#define __CS35L41_HDA_H__
+
+#include <linux/acpi.h>
+#include <linux/efi.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
+#include <linux/device.h>
+#include <sound/cs35l41.h>
+#include <sound/cs-amp-lib.h>
+
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/wmfw.h>
+
+#define CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ    1000000
+#define DEFAULT_AMP_GAIN_PCM                   17      /* 17.5dB Gain */
+#define DEFAULT_AMP_GAIN_PDM                   19      /* 19.5dB Gain */
+
+struct cs35l41_amp_cal_data {
+       u32 calTarget[2];
+       u32 calTime[2];
+       s8 calAmbient;
+       u8 calStatus;
+       u16 calR;
+} __packed;
+
+struct cs35l41_amp_efi_data {
+       u32 size;
+       u32 count;
+       struct cs35l41_amp_cal_data data[];
+} __packed;
+
+enum cs35l41_hda_spk_pos {
+       CS35L41_LEFT,
+       CS35L41_RIGHT,
+       CS35L41_CENTER,
+};
+
+enum cs35l41_hda_gpio_function {
+       CS35L41_NOT_USED,
+       CS35l41_VSPK_SWITCH,
+       CS35L41_INTERRUPT,
+       CS35l41_SYNC,
+};
+
+enum control_bus {
+       I2C,
+       SPI
+};
+
+struct cs35l41_hda {
+       struct device *dev;
+       struct regmap *regmap;
+       struct gpio_desc *reset_gpio;
+       struct gpio_desc *cs_gpio;
+       struct cs35l41_hw_cfg hw_cfg;
+       struct hda_codec *codec;
+
+       int irq;
+       int index;
+       int channel_index;
+       unsigned volatile long irq_errors;
+       const char *amp_name;
+       const char *acpi_subsystem_id;
+       int firmware_type;
+       int speaker_id;
+       struct mutex fw_mutex;
+       struct work_struct fw_load_work;
+
+       struct regmap_irq_chip_data *irq_data;
+       bool firmware_running;
+       bool request_fw_load;
+       bool fw_request_ongoing;
+       bool halo_initialized;
+       bool playback_started;
+       struct cs_dsp cs_dsp;
+       struct acpi_device *dacpi;
+       bool mute_override;
+       enum control_bus control_bus;
+       bool bypass_fw;
+       unsigned int tuning_gain;
+       struct cirrus_amp_cal_data cal_data;
+       bool cal_data_valid;
+
+};
+
+enum halo_state {
+       HALO_STATE_CODE_INIT_DOWNLOAD = 0,
+       HALO_STATE_CODE_START,
+       HALO_STATE_CODE_RUN
+};
+
+extern const struct dev_pm_ops cs35l41_hda_pm_ops;
+
+int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
+                     struct regmap *regmap, enum control_bus control_bus);
+void cs35l41_hda_remove(struct device *dev);
+int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id);
+int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id);
+
+#endif /*__CS35L41_HDA_H__*/
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l41_hda_i2c.c
new file mode 100644 (file)
index 0000000..e774954
--- /dev/null
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS35l41 HDA I2C driver
+//
+// Copyright 2021 Cirrus Logic, Inc.
+//
+// Author: Lucas Tanure <tanureal@opensource.cirrus.com>
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+
+#include "cs35l41_hda.h"
+
+static int cs35l41_hda_i2c_probe(struct i2c_client *clt)
+{
+       const char *device_name;
+
+       /*
+        * Compare against the device name so it works for SPI, normal ACPI
+        * and for ACPI by serial-multi-instantiate matching cases.
+        */
+       if (strstr(dev_name(&clt->dev), "CLSA0100"))
+               device_name = "CLSA0100";
+       else if (strstr(dev_name(&clt->dev), "CLSA0101"))
+               device_name = "CLSA0101";
+       else if (strstr(dev_name(&clt->dev), "CSC3551"))
+               device_name = "CSC3551";
+       else
+               return -ENODEV;
+
+       return cs35l41_hda_probe(&clt->dev, device_name, clt->addr, clt->irq,
+                                devm_regmap_init_i2c(clt, &cs35l41_regmap_i2c), I2C);
+}
+
+static void cs35l41_hda_i2c_remove(struct i2c_client *clt)
+{
+       cs35l41_hda_remove(&clt->dev);
+}
+
+static const struct i2c_device_id cs35l41_hda_i2c_id[] = {
+       { "cs35l41-hda" },
+       {}
+};
+
+static const struct acpi_device_id cs35l41_acpi_hda_match[] = {
+       {"CLSA0100", 0 },
+       {"CLSA0101", 0 },
+       {"CSC3551", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_hda_match);
+
+static struct i2c_driver cs35l41_i2c_driver = {
+       .driver = {
+               .name           = "cs35l41-hda",
+               .acpi_match_table = cs35l41_acpi_hda_match,
+               .pm             = &cs35l41_hda_pm_ops,
+       },
+       .id_table       = cs35l41_hda_i2c_id,
+       .probe          = cs35l41_hda_i2c_probe,
+       .remove         = cs35l41_hda_i2c_remove,
+};
+module_i2c_driver(cs35l41_i2c_driver);
+
+MODULE_DESCRIPTION("HDA CS35L41 driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41");
+MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_property.c b/sound/hda/codecs/side-codecs/cs35l41_hda_property.c
new file mode 100644 (file)
index 0000000..d8249d9
--- /dev/null
@@ -0,0 +1,578 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS35L41 ALSA HDA Property driver
+//
+// Copyright 2023 Cirrus Logic, Inc.
+//
+// Author: Stefan Binding <sbinding@opensource.cirrus.com>
+
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/string.h>
+#include "cs35l41_hda_property.h"
+#include <linux/spi/spi.h>
+
+#define MAX_AMPS 4
+
+struct cs35l41_config {
+       const char *ssid;
+       int num_amps;
+       enum {
+               INTERNAL,
+               EXTERNAL
+       } boost_type;
+       u8 channel[MAX_AMPS];
+       int reset_gpio_index; /* -1 if no reset gpio */
+       int spkid_gpio_index; /* -1 if no spkid gpio */
+       int cs_gpio_index; /* -1 if no cs gpio, or cs-gpios already exists, max num amps == 2 */
+       int boost_ind_nanohenry; /* Required if boost_type == Internal */
+       int boost_peak_milliamp; /* Required if boost_type == Internal */
+       int boost_cap_microfarad; /* Required if boost_type == Internal */
+};
+
+static const struct cs35l41_config cs35l41_config_table[] = {
+       { "10251826", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "1025182C", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "10251844", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "10280B27", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10280B28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10280BEB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
+       { "10280C4D", 4, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT }, 0, 1, -1, 1000, 4500, 24 },
+/*
+ * Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type.
+ * We can override the _DSD to correct the boost type here.
+ * Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists
+ * in the ACPI. The Reset GPIO is also valid, so we can use the Reset defined in _DSD.
+ */
+       { "103C89C6", 2, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, -1, -1, -1, 1000, 4500, 24 },
+       { "103C8A28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A29", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A2A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A2B", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A2C", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A2D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A2E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 },
+       { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE0", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE1", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE2", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE5", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE6", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE7", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE8", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8B3A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
+       { "103C8C4D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C4E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8CDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
+       { "103C8CDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 3900, 24 },
+       { "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431473", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
+       { "10431483", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
+       { "10431493", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "104314D3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "104314E3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431503", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431533", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431573", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10431663", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
+       { "10431683", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "104316A3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+       { "104316D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+       { "104316F3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+       { "104317F3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431863", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "104318D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "10431A83", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431B93", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10431C9F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10431CAF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10431CCF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10431CDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10431CEF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10431D1F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431DA2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+       { "10431E02", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+       { "10431E12", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "10431EE2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
+       { "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
+       { "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
+       { "10433A20", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10433A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10433A40", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10433A50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "10433A60", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
+       { "17AA3865", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "17AA3866", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "17AA386E", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+       { "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "17AA3877", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "17AA3878", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
+       { "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+       { "17AA38AB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+       { "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "17AA38B7", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
+       { "17AA38C7", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },
+       { "17AA38C8", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },
+       { "17AA38F9", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+       { "17AA38FA", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
+       {}
+};
+
+static int cs35l41_add_gpios(struct cs35l41_hda *cs35l41, struct device *physdev, int reset_gpio,
+                            int spkid_gpio, int cs_gpio_index, int num_amps)
+{
+       struct acpi_gpio_mapping *gpio_mapping = NULL;
+       struct acpi_gpio_params *reset_gpio_params = NULL;
+       struct acpi_gpio_params *spkid_gpio_params = NULL;
+       struct acpi_gpio_params *cs_gpio_params = NULL;
+       unsigned int num_entries = 0;
+       unsigned int reset_index, spkid_index, csgpio_index;
+       int i;
+
+       /*
+        * GPIO Mapping only needs to be done once, since it would be available for subsequent amps
+        */
+       if (cs35l41->dacpi->driver_gpios)
+               return 0;
+
+       if (reset_gpio >= 0) {
+               reset_index = num_entries;
+               num_entries++;
+       }
+
+       if (spkid_gpio >= 0) {
+               spkid_index = num_entries;
+               num_entries++;
+       }
+
+       if ((cs_gpio_index >= 0)  && (num_amps == 2)) {
+               csgpio_index = num_entries;
+               num_entries++;
+       }
+
+       if (!num_entries)
+               return 0;
+
+       /* must include termination entry */
+       num_entries++;
+
+       gpio_mapping = devm_kcalloc(physdev, num_entries, sizeof(struct acpi_gpio_mapping),
+                                   GFP_KERNEL);
+
+       if (!gpio_mapping)
+               goto err;
+
+       if (reset_gpio >= 0) {
+               gpio_mapping[reset_index].name = "reset-gpios";
+               reset_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),
+                                                GFP_KERNEL);
+               if (!reset_gpio_params)
+                       goto err;
+
+               for (i = 0; i < num_amps; i++)
+                       reset_gpio_params[i].crs_entry_index = reset_gpio;
+
+               gpio_mapping[reset_index].data = reset_gpio_params;
+               gpio_mapping[reset_index].size = num_amps;
+       }
+
+       if (spkid_gpio >= 0) {
+               gpio_mapping[spkid_index].name = "spk-id-gpios";
+               spkid_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),
+                                                GFP_KERNEL);
+               if (!spkid_gpio_params)
+                       goto err;
+
+               for (i = 0; i < num_amps; i++)
+                       spkid_gpio_params[i].crs_entry_index = spkid_gpio;
+
+               gpio_mapping[spkid_index].data = spkid_gpio_params;
+               gpio_mapping[spkid_index].size = num_amps;
+       }
+
+       if ((cs_gpio_index >= 0) && (num_amps == 2)) {
+               gpio_mapping[csgpio_index].name = "cs-gpios";
+               /* only one GPIO CS is supported without using _DSD, obtained using index 0 */
+               cs_gpio_params = devm_kzalloc(physdev, sizeof(struct acpi_gpio_params), GFP_KERNEL);
+               if (!cs_gpio_params)
+                       goto err;
+
+               cs_gpio_params->crs_entry_index = cs_gpio_index;
+
+               gpio_mapping[csgpio_index].data = cs_gpio_params;
+               gpio_mapping[csgpio_index].size = 1;
+       }
+
+       return devm_acpi_dev_add_driver_gpios(physdev, gpio_mapping);
+err:
+       devm_kfree(physdev, gpio_mapping);
+       devm_kfree(physdev, reset_gpio_params);
+       devm_kfree(physdev, spkid_gpio_params);
+       devm_kfree(physdev, cs_gpio_params);
+       return -ENOMEM;
+}
+
+static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                             const char *hid)
+{
+       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+       const struct cs35l41_config *cfg;
+       struct gpio_desc *cs_gpiod;
+       struct spi_device *spi;
+       bool dsd_found;
+       int ret;
+       int i;
+
+       for (cfg = cs35l41_config_table; cfg->ssid; cfg++) {
+               if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id))
+                       break;
+       }
+
+       if (!cfg->ssid)
+               return -ENOENT;
+
+       if (!cs35l41->dacpi || cs35l41->dacpi != ACPI_COMPANION(physdev)) {
+               dev_err(cs35l41->dev, "ACPI Device does not match, cannot override _DSD.\n");
+               return -ENODEV;
+       }
+
+       dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
+
+       dsd_found = acpi_dev_has_props(cs35l41->dacpi);
+
+       if (!dsd_found) {
+               ret = cs35l41_add_gpios(cs35l41, physdev, cfg->reset_gpio_index,
+                                                cfg->spkid_gpio_index, cfg->cs_gpio_index,
+                                                cfg->num_amps);
+               if (ret) {
+                       dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);
+                       return ret;
+               }
+       } else if (cfg->reset_gpio_index >= 0 || cfg->spkid_gpio_index >= 0) {
+               dev_warn(cs35l41->dev, "Cannot add Reset/Speaker ID/SPI CS GPIO Mapping, "
+                        "_DSD already exists.\n");
+       }
+
+       if (cs35l41->control_bus == SPI) {
+               cs35l41->index = id;
+
+               /*
+                * Manually set the Chip Select for the second amp <cs_gpio_index> in the node.
+                * This is only supported for systems with 2 amps, since we cannot expand the
+                * default number of chip selects without using cs-gpios
+                * The CS GPIO must be set high prior to communicating with the first amp (which
+                * uses a native chip select), to ensure the second amp does not clash with the
+                * first.
+                */
+               if (IS_ENABLED(CONFIG_SPI) && cfg->cs_gpio_index >= 0) {
+                       spi = to_spi_device(cs35l41->dev);
+
+                       if (cfg->num_amps != 2) {
+                               dev_warn(cs35l41->dev,
+                                        "Cannot update SPI CS, Number of Amps (%d) != 2\n",
+                                        cfg->num_amps);
+                       } else if (dsd_found) {
+                               dev_warn(cs35l41->dev,
+                                       "Cannot update SPI CS, _DSD already exists.\n");
+                       } else {
+                               /*
+                                * This is obtained using driver_gpios, since only one GPIO for CS
+                                * exists, this can be obtained using index 0.
+                                */
+                               cs_gpiod = gpiod_get_index(physdev, "cs", 0, GPIOD_OUT_LOW);
+                               if (IS_ERR(cs_gpiod)) {
+                                       dev_err(cs35l41->dev,
+                                               "Unable to get Chip Select GPIO descriptor\n");
+                                       return PTR_ERR(cs_gpiod);
+                               }
+                               if (id == 1) {
+                                       spi_set_csgpiod(spi, 0, cs_gpiod);
+                                       cs35l41->cs_gpio = cs_gpiod;
+                               } else {
+                                       gpiod_set_value_cansleep(cs_gpiod, true);
+                                       gpiod_put(cs_gpiod);
+                               }
+                               spi_setup(spi);
+                       }
+               }
+       } else {
+               if (cfg->num_amps > 2)
+                       /*
+                        * i2c addresses for 3/4 amps are used in order: 0x40, 0x41, 0x42, 0x43,
+                        * subtracting 0x40 would give zero-based index
+                        */
+                       cs35l41->index = id - 0x40;
+               else
+                       /* i2c addr 0x40 for first amp (always), 0x41/0x42 for 2nd amp */
+                       cs35l41->index = id == 0x40 ? 0 : 1;
+       }
+
+       cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
+                                                    cs35l41->index, GPIOD_OUT_LOW,
+                                                    "cs35l41-reset");
+       cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, cfg->num_amps, -1);
+
+       hw_cfg->spk_pos = cfg->channel[cs35l41->index];
+
+       cs35l41->channel_index = 0;
+       for (i = 0; i < cs35l41->index; i++)
+               if (cfg->channel[i] == hw_cfg->spk_pos)
+                       cs35l41->channel_index++;
+
+       if (cfg->boost_type == INTERNAL) {
+               hw_cfg->bst_type = CS35L41_INT_BOOST;
+               hw_cfg->bst_ind = cfg->boost_ind_nanohenry;
+               hw_cfg->bst_ipk = cfg->boost_peak_milliamp;
+               hw_cfg->bst_cap = cfg->boost_cap_microfarad;
+               hw_cfg->gpio1.func = CS35L41_NOT_USED;
+               hw_cfg->gpio1.valid = true;
+       } else {
+               hw_cfg->bst_type = CS35L41_EXT_BOOST;
+               hw_cfg->bst_ind = -1;
+               hw_cfg->bst_ipk = -1;
+               hw_cfg->bst_cap = -1;
+               hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
+               hw_cfg->gpio1.valid = true;
+       }
+
+       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+       hw_cfg->gpio2.valid = true;
+       hw_cfg->valid = true;
+
+       return 0;
+}
+
+/*
+ * Systems 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system - each speaker has
+ * its own speaker id.
+ */
+static int hp_i2c_int_2amp_dual_spkid(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                                     const char *hid)
+{
+       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+       /* If _DSD exists for this laptop, we cannot support it through here */
+       if (acpi_dev_has_props(cs35l41->dacpi))
+               return -ENOENT;
+
+       /* check I2C address to assign the index */
+       cs35l41->index = id == 0x40 ? 0 : 1;
+       cs35l41->channel_index = 0;
+       cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+       if (cs35l41->index == 0)
+               cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 1);
+       else
+               cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+       hw_cfg->spk_pos = cs35l41->index;
+       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+       hw_cfg->gpio2.valid = true;
+       hw_cfg->valid = true;
+
+       hw_cfg->bst_type = CS35L41_INT_BOOST;
+       hw_cfg->bst_ind = 1000;
+       hw_cfg->bst_ipk = 4100;
+       hw_cfg->bst_cap = 24;
+       hw_cfg->gpio1.func = CS35L41_NOT_USED;
+       hw_cfg->gpio1.valid = true;
+
+       return 0;
+}
+
+/*
+ * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
+ * And devices created by serial-multi-instantiate don't have their device struct
+ * pointing to the correct fwnode, so acpi_dev must be used here.
+ * And devm functions expect that the device requesting the resource has the correct
+ * fwnode.
+ */
+static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                                const char *hid)
+{
+       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
+
+       /* check I2C address to assign the index */
+       cs35l41->index = id == 0x40 ? 0 : 1;
+       cs35l41->channel_index = 0;
+       cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
+       cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
+       hw_cfg->spk_pos = cs35l41->index;
+       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
+       hw_cfg->gpio2.valid = true;
+       hw_cfg->valid = true;
+
+       if (strcmp(hid, "CLSA0100") == 0) {
+               hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
+       } else if (strcmp(hid, "CLSA0101") == 0) {
+               hw_cfg->bst_type = CS35L41_EXT_BOOST;
+               hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
+               hw_cfg->gpio1.valid = true;
+       }
+
+       return 0;
+}
+
+static int missing_speaker_id_gpio2(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                                   const char *hid)
+{
+       int ret;
+
+       ret = cs35l41_add_gpios(cs35l41, physdev, -1, 2, -1, 2);
+       if (ret) {
+               dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);
+               return ret;
+       }
+
+       return cs35l41_hda_parse_acpi(cs35l41, physdev, id);
+}
+
+struct cs35l41_prop_model {
+       const char *hid;
+       const char *ssid;
+       int (*add_prop)(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                       const char *hid);
+};
+
+static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
+       { "CLSA0100", NULL, lenovo_legion_no_acpi },
+       { "CLSA0101", NULL, lenovo_legion_no_acpi },
+       { "CSC3551", "10251826", generic_dsd_config },
+       { "CSC3551", "1025182C", generic_dsd_config },
+       { "CSC3551", "10251844", generic_dsd_config },
+       { "CSC3551", "10280B27", generic_dsd_config },
+       { "CSC3551", "10280B28", generic_dsd_config },
+       { "CSC3551", "10280BEB", generic_dsd_config },
+       { "CSC3551", "10280C4D", generic_dsd_config },
+       { "CSC3551", "103C89C6", generic_dsd_config },
+       { "CSC3551", "103C8A28", generic_dsd_config },
+       { "CSC3551", "103C8A29", generic_dsd_config },
+       { "CSC3551", "103C8A2A", generic_dsd_config },
+       { "CSC3551", "103C8A2B", generic_dsd_config },
+       { "CSC3551", "103C8A2C", generic_dsd_config },
+       { "CSC3551", "103C8A2D", generic_dsd_config },
+       { "CSC3551", "103C8A2E", generic_dsd_config },
+       { "CSC3551", "103C8A30", generic_dsd_config },
+       { "CSC3551", "103C8A31", generic_dsd_config },
+       { "CSC3551", "103C8A6E", generic_dsd_config },
+       { "CSC3551", "103C8BB3", generic_dsd_config },
+       { "CSC3551", "103C8BB4", generic_dsd_config },
+       { "CSC3551", "103C8BDD", generic_dsd_config },
+       { "CSC3551", "103C8BDE", generic_dsd_config },
+       { "CSC3551", "103C8BDF", generic_dsd_config },
+       { "CSC3551", "103C8BE0", generic_dsd_config },
+       { "CSC3551", "103C8BE1", generic_dsd_config },
+       { "CSC3551", "103C8BE2", generic_dsd_config },
+       { "CSC3551", "103C8BE3", generic_dsd_config },
+       { "CSC3551", "103C8BE5", generic_dsd_config },
+       { "CSC3551", "103C8BE6", generic_dsd_config },
+       { "CSC3551", "103C8BE7", generic_dsd_config },
+       { "CSC3551", "103C8BE8", generic_dsd_config },
+       { "CSC3551", "103C8BE9", generic_dsd_config },
+       { "CSC3551", "103C8B3A", generic_dsd_config },
+       { "CSC3551", "103C8C15", generic_dsd_config },
+       { "CSC3551", "103C8C16", generic_dsd_config },
+       { "CSC3551", "103C8C17", generic_dsd_config },
+       { "CSC3551", "103C8C4D", generic_dsd_config },
+       { "CSC3551", "103C8C4E", generic_dsd_config },
+       { "CSC3551", "103C8C4F", generic_dsd_config },
+       { "CSC3551", "103C8C50", generic_dsd_config },
+       { "CSC3551", "103C8C51", generic_dsd_config },
+       { "CSC3551", "103C8C66", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C67", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C68", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8C6A", hp_i2c_int_2amp_dual_spkid },
+       { "CSC3551", "103C8CDD", generic_dsd_config },
+       { "CSC3551", "103C8CDE", generic_dsd_config },
+       { "CSC3551", "104312AF", generic_dsd_config },
+       { "CSC3551", "10431433", generic_dsd_config },
+       { "CSC3551", "10431463", generic_dsd_config },
+       { "CSC3551", "10431473", generic_dsd_config },
+       { "CSC3551", "10431483", generic_dsd_config },
+       { "CSC3551", "10431493", generic_dsd_config },
+       { "CSC3551", "104314D3", generic_dsd_config },
+       { "CSC3551", "104314E3", generic_dsd_config },
+       { "CSC3551", "10431503", generic_dsd_config },
+       { "CSC3551", "10431533", generic_dsd_config },
+       { "CSC3551", "10431573", generic_dsd_config },
+       { "CSC3551", "10431663", generic_dsd_config },
+       { "CSC3551", "10431683", generic_dsd_config },
+       { "CSC3551", "104316A3", generic_dsd_config },
+       { "CSC3551", "104316D3", generic_dsd_config },
+       { "CSC3551", "104316F3", generic_dsd_config },
+       { "CSC3551", "104317F3", generic_dsd_config },
+       { "CSC3551", "10431863", generic_dsd_config },
+       { "CSC3551", "104318D3", generic_dsd_config },
+       { "CSC3551", "10431A63", missing_speaker_id_gpio2 },
+       { "CSC3551", "10431A83", generic_dsd_config },
+       { "CSC3551", "10431B93", generic_dsd_config },
+       { "CSC3551", "10431C9F", generic_dsd_config },
+       { "CSC3551", "10431CAF", generic_dsd_config },
+       { "CSC3551", "10431CCF", generic_dsd_config },
+       { "CSC3551", "10431CDF", generic_dsd_config },
+       { "CSC3551", "10431CEF", generic_dsd_config },
+       { "CSC3551", "10431D1F", generic_dsd_config },
+       { "CSC3551", "10431DA2", generic_dsd_config },
+       { "CSC3551", "10431E02", generic_dsd_config },
+       { "CSC3551", "10431E12", generic_dsd_config },
+       { "CSC3551", "10431EE2", generic_dsd_config },
+       { "CSC3551", "10431F12", generic_dsd_config },
+       { "CSC3551", "10431F1F", generic_dsd_config },
+       { "CSC3551", "10431F62", generic_dsd_config },
+       { "CSC3551", "10433A20", generic_dsd_config },
+       { "CSC3551", "10433A30", generic_dsd_config },
+       { "CSC3551", "10433A40", generic_dsd_config },
+       { "CSC3551", "10433A50", generic_dsd_config },
+       { "CSC3551", "10433A60", generic_dsd_config },
+       { "CSC3551", "17AA3865", generic_dsd_config },
+       { "CSC3551", "17AA3866", generic_dsd_config },
+       { "CSC3551", "17AA386E", generic_dsd_config },
+       { "CSC3551", "17AA386F", generic_dsd_config },
+       { "CSC3551", "17AA3877", generic_dsd_config },
+       { "CSC3551", "17AA3878", generic_dsd_config },
+       { "CSC3551", "17AA38A9", generic_dsd_config },
+       { "CSC3551", "17AA38AB", generic_dsd_config },
+       { "CSC3551", "17AA38B4", generic_dsd_config },
+       { "CSC3551", "17AA38B5", generic_dsd_config },
+       { "CSC3551", "17AA38B6", generic_dsd_config },
+       { "CSC3551", "17AA38B7", generic_dsd_config },
+       { "CSC3551", "17AA38C7", generic_dsd_config },
+       { "CSC3551", "17AA38C8", generic_dsd_config },
+       { "CSC3551", "17AA38F9", generic_dsd_config },
+       { "CSC3551", "17AA38FA", generic_dsd_config },
+       {}
+};
+
+int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                              const char *hid)
+{
+       const struct cs35l41_prop_model *model;
+
+       for (model = cs35l41_prop_model_table; model->hid; model++) {
+               if (!strcmp(model->hid, hid) &&
+                   (!model->ssid ||
+                    (cs35l41->acpi_subsystem_id &&
+                     !strcasecmp(model->ssid, cs35l41->acpi_subsystem_id))))
+                       return model->add_prop(cs35l41, physdev, id, hid);
+       }
+
+       return -ENOENT;
+}
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_property.h b/sound/hda/codecs/side-codecs/cs35l41_hda_property.h
new file mode 100644 (file)
index 0000000..fd83404
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0
+ *
+ * CS35L41 ALSA HDA Property driver
+ *
+ * Copyright 2023 Cirrus Logic, Inc.
+ *
+ * Author: Stefan Binding <sbinding@opensource.cirrus.com>
+ */
+
+#ifndef CS35L41_HDA_PROP_H
+#define CS35L41_HDA_PROP_H
+
+#include <linux/device.h>
+#include "cs35l41_hda.h"
+
+int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
+                              const char *hid);
+#endif /* CS35L41_HDA_PROP_H */
diff --git a/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l41_hda_spi.c
new file mode 100644 (file)
index 0000000..2acbaf8
--- /dev/null
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// CS35l41 HDA SPI driver
+//
+// Copyright 2021 Cirrus Logic, Inc.
+//
+// Author: Lucas Tanure <tanureal@opensource.cirrus.com>
+
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+
+#include "cs35l41_hda.h"
+
+static int cs35l41_hda_spi_probe(struct spi_device *spi)
+{
+       const char *device_name;
+
+       /*
+        * Compare against the device name so it works for SPI, normal ACPI
+        * and for ACPI by serial-multi-instantiate matching cases.
+        */
+       if (strstr(dev_name(&spi->dev), "CSC3551"))
+               device_name = "CSC3551";
+       else
+               return -ENODEV;
+
+       return cs35l41_hda_probe(&spi->dev, device_name, spi_get_chipselect(spi, 0), spi->irq,
+                                devm_regmap_init_spi(spi, &cs35l41_regmap_spi), SPI);
+}
+
+static void cs35l41_hda_spi_remove(struct spi_device *spi)
+{
+       cs35l41_hda_remove(&spi->dev);
+}
+
+static const struct spi_device_id cs35l41_hda_spi_id[] = {
+       { "cs35l41-hda", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(spi, cs35l41_hda_spi_id);
+
+static const struct acpi_device_id cs35l41_acpi_hda_match[] = {
+       { "CSC3551", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_hda_match);
+
+static struct spi_driver cs35l41_spi_driver = {
+       .driver = {
+               .name           = "cs35l41-hda",
+               .acpi_match_table = cs35l41_acpi_hda_match,
+               .pm             = &cs35l41_hda_pm_ops,
+       },
+       .id_table       = cs35l41_hda_spi_id,
+       .probe          = cs35l41_hda_spi_probe,
+       .remove         = cs35l41_hda_spi_remove,
+};
+module_spi_driver(cs35l41_spi_driver);
+
+MODULE_DESCRIPTION("HDA CS35L41 driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41");
+MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.c b/sound/hda/codecs/side-codecs/cs35l56_hda.c
new file mode 100644 (file)
index 0000000..8d43119
--- /dev/null
@@ -0,0 +1,1127 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// HDA audio driver for Cirrus Logic CS35L56 smart amp
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+//
+
+#include <linux/acpi.h>
+#include <linux/debugfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/cs-amp-lib.h>
+#include <sound/hda_codec.h>
+#include <sound/tlv.h>
+#include "cirrus_scodec.h"
+#include "cs35l56_hda.h"
+#include "hda_component.h"
+#include "../generic.h"
+
+ /*
+  * The cs35l56_hda_dai_config[] reg sequence configures the device as
+  *  ASP1_BCLK_FREQ = 3.072 MHz
+  *  ASP1_RX_WIDTH = 32 cycles per slot, ASP1_TX_WIDTH = 32 cycles per slot, ASP1_FMT = I2S
+  *  ASP1_DOUT_HIZ_CONTROL = Hi-Z during unused timeslots
+  *  ASP1_RX_WL = 24 bits per sample
+  *  ASP1_TX_WL = 24 bits per sample
+  *  ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled
+  *
+  * Override any Windows-specific mixer settings applied by the firmware.
+  */
+static const struct reg_sequence cs35l56_hda_dai_config[] = {
+       { CS35L56_ASP1_CONTROL1,        0x00000021 },
+       { CS35L56_ASP1_CONTROL2,        0x20200200 },
+       { CS35L56_ASP1_CONTROL3,        0x00000003 },
+       { CS35L56_ASP1_FRAME_CONTROL1,  0x03020100 },
+       { CS35L56_ASP1_FRAME_CONTROL5,  0x00020100 },
+       { CS35L56_ASP1_DATA_CONTROL5,   0x00000018 },
+       { CS35L56_ASP1_DATA_CONTROL1,   0x00000018 },
+       { CS35L56_ASP1_ENABLES1,        0x00000000 },
+       { CS35L56_ASP1TX1_INPUT,        0x00000018 },
+       { CS35L56_ASP1TX2_INPUT,        0x00000019 },
+       { CS35L56_ASP1TX3_INPUT,        0x00000020 },
+       { CS35L56_ASP1TX4_INPUT,        0x00000028 },
+
+};
+
+static void cs35l56_hda_wait_dsp_ready(struct cs35l56_hda *cs35l56)
+{
+       /* Wait for patching to complete */
+       flush_work(&cs35l56->dsp_work);
+}
+
+static void cs35l56_hda_play(struct cs35l56_hda *cs35l56)
+{
+       unsigned int val;
+       int ret;
+
+       cs35l56_hda_wait_dsp_ready(cs35l56);
+
+       pm_runtime_get_sync(cs35l56->base.dev);
+       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY);
+       if (ret == 0) {
+               /* Wait for firmware to enter PS0 power state */
+               ret = regmap_read_poll_timeout(cs35l56->base.regmap,
+                                              cs35l56->base.fw_reg->transducer_actual_ps,
+                                              val, (val == CS35L56_PS0),
+                                              CS35L56_PS0_POLL_US,
+                                              CS35L56_PS0_TIMEOUT_US);
+               if (ret)
+                       dev_warn(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
+       }
+       regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
+                       BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
+                       cs35l56->asp_tx_mask);
+       cs35l56->playing = true;
+}
+
+static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56)
+{
+       cs35l56->playing = false;
+       cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
+       regmap_clear_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
+                         BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
+                         BIT(CS35L56_ASP_TX1_EN_SHIFT) | BIT(CS35L56_ASP_TX2_EN_SHIFT) |
+                         BIT(CS35L56_ASP_TX3_EN_SHIFT) | BIT(CS35L56_ASP_TX4_EN_SHIFT));
+
+       pm_runtime_put_autosuspend(cs35l56->base.dev);
+}
+
+static void cs35l56_hda_playback_hook(struct device *dev, int action)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       dev_dbg(cs35l56->base.dev, "%s()%d: action: %d\n", __func__, __LINE__, action);
+
+       switch (action) {
+       case HDA_GEN_PCM_ACT_PREPARE:
+               if (cs35l56->playing)
+                       break;
+
+               /* If we're suspended: flag that resume should start playback */
+               if (cs35l56->suspended) {
+                       cs35l56->playing = true;
+                       break;
+               }
+
+               cs35l56_hda_play(cs35l56);
+               break;
+       case HDA_GEN_PCM_ACT_CLEANUP:
+               if (!cs35l56->playing)
+                       break;
+
+               cs35l56_hda_pause(cs35l56);
+               break;
+       default:
+               break;
+       }
+}
+
+static int cs35l56_hda_runtime_suspend(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       if (cs35l56->cs_dsp.booted)
+               cs_dsp_stop(&cs35l56->cs_dsp);
+
+       return cs35l56_runtime_suspend_common(&cs35l56->base);
+}
+
+static int cs35l56_hda_runtime_resume(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+       int ret;
+
+       ret = cs35l56_runtime_resume_common(&cs35l56->base, false);
+       if (ret < 0)
+               return ret;
+
+       if (cs35l56->cs_dsp.booted) {
+               ret = cs_dsp_run(&cs35l56->cs_dsp);
+               if (ret) {
+                       dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
+                       goto err;
+               }
+       }
+
+       return 0;
+
+err:
+       cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
+       regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
+                    CS35L56_MBOX_CMD_HIBERNATE_NOW);
+
+       regcache_cache_only(cs35l56->base.regmap, true);
+
+       return ret;
+}
+
+static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = CS35L56_NUM_INPUT_SRC;
+       if (uinfo->value.enumerated.item >= CS35L56_NUM_INPUT_SRC)
+               uinfo->value.enumerated.item = CS35L56_NUM_INPUT_SRC - 1;
+       strscpy(uinfo->value.enumerated.name, cs35l56_tx_input_texts[uinfo->value.enumerated.item],
+               sizeof(uinfo->value.enumerated.name));
+
+       return 0;
+}
+
+static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+       unsigned int reg_val;
+       int i;
+
+       cs35l56_hda_wait_dsp_ready(cs35l56);
+
+       regmap_read(cs35l56->base.regmap, kcontrol->private_value, &reg_val);
+       reg_val &= CS35L56_ASP_TXn_SRC_MASK;
+
+       for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {
+               if (cs35l56_tx_input_values[i] == reg_val) {
+                       ucontrol->value.enumerated.item[0] = i;
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+       unsigned int item = ucontrol->value.enumerated.item[0];
+       bool changed;
+
+       if (item >= CS35L56_NUM_INPUT_SRC)
+               return -EINVAL;
+
+       cs35l56_hda_wait_dsp_ready(cs35l56);
+
+       regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
+                                CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
+                                &changed);
+
+       return changed;
+}
+
+static int cs35l56_hda_posture_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = CS35L56_MAIN_POSTURE_MIN;
+       uinfo->value.integer.max = CS35L56_MAIN_POSTURE_MAX;
+       return 0;
+}
+
+static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+       unsigned int pos;
+       int ret;
+
+       cs35l56_hda_wait_dsp_ready(cs35l56);
+
+       ret = regmap_read(cs35l56->base.regmap,
+                         cs35l56->base.fw_reg->posture_number, &pos);
+       if (ret)
+               return ret;
+
+       ucontrol->value.integer.value[0] = pos;
+
+       return 0;
+}
+
+static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+       unsigned long pos = ucontrol->value.integer.value[0];
+       bool changed;
+       int ret;
+
+       if ((pos < CS35L56_MAIN_POSTURE_MIN) ||
+           (pos > CS35L56_MAIN_POSTURE_MAX))
+               return -EINVAL;
+
+       cs35l56_hda_wait_dsp_ready(cs35l56);
+
+       ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->posture_number,
+                                      CS35L56_MAIN_POSTURE_MASK, pos, &changed);
+       if (ret)
+               return ret;
+
+       return changed;
+}
+
+static const struct {
+       const char *name;
+       unsigned int reg;
+} cs35l56_hda_mixer_controls[] = {
+       { "ASP1 TX1 Source", CS35L56_ASP1TX1_INPUT },
+       { "ASP1 TX2 Source", CS35L56_ASP1TX2_INPUT },
+       { "ASP1 TX3 Source", CS35L56_ASP1TX3_INPUT },
+       { "ASP1 TX4 Source", CS35L56_ASP1TX4_INPUT },
+};
+
+static const DECLARE_TLV_DB_SCALE(cs35l56_hda_vol_tlv, -10000, 25, 0);
+
+static int cs35l56_hda_vol_info(struct snd_kcontrol *kcontrol,
+                               struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.step = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
+                                  CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
+
+       return 0;
+}
+
+static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+       unsigned int raw_vol;
+       int vol;
+       int ret;
+
+       cs35l56_hda_wait_dsp_ready(cs35l56);
+
+       ret = regmap_read(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume, &raw_vol);
+
+       if (ret)
+               return ret;
+
+       vol = (s16)(raw_vol & 0xFFFF);
+       vol >>= CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
+
+       if (vol & BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT))
+               vol |= ~((int)(BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT) - 1));
+
+       ucontrol->value.integer.value[0] = vol - CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
+
+       return 0;
+}
+
+static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+{
+       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
+       long vol = ucontrol->value.integer.value[0];
+       unsigned int raw_vol;
+       bool changed;
+       int ret;
+
+       if ((vol < 0) || (vol > (CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
+                                CS35L56_MAIN_RENDER_USER_VOLUME_MIN)))
+               return -EINVAL;
+
+       raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) <<
+                 CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
+
+       cs35l56_hda_wait_dsp_ready(cs35l56);
+
+       ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume,
+                                      CS35L56_MAIN_RENDER_USER_VOLUME_MASK, raw_vol, &changed);
+       if (ret)
+               return ret;
+
+       return changed;
+}
+
+static void cs35l56_hda_create_controls(struct cs35l56_hda *cs35l56)
+{
+       struct snd_kcontrol_new ctl_template = {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = cs35l56_hda_posture_info,
+               .get = cs35l56_hda_posture_get,
+               .put = cs35l56_hda_posture_put,
+       };
+       char name[64];
+       int i;
+
+       snprintf(name, sizeof(name), "%s Posture Number", cs35l56->amp_name);
+       ctl_template.name = name;
+       cs35l56->posture_ctl = snd_ctl_new1(&ctl_template, cs35l56);
+       if (snd_ctl_add(cs35l56->codec->card, cs35l56->posture_ctl))
+               dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
+
+       /* Mixer controls */
+       ctl_template.info = cs35l56_hda_mixer_info;
+       ctl_template.get = cs35l56_hda_mixer_get;
+       ctl_template.put = cs35l56_hda_mixer_put;
+
+       BUILD_BUG_ON(ARRAY_SIZE(cs35l56->mixer_ctl) != ARRAY_SIZE(cs35l56_hda_mixer_controls));
+
+       for (i = 0; i < ARRAY_SIZE(cs35l56_hda_mixer_controls); ++i) {
+               snprintf(name, sizeof(name), "%s %s", cs35l56->amp_name,
+                        cs35l56_hda_mixer_controls[i].name);
+               ctl_template.private_value = cs35l56_hda_mixer_controls[i].reg;
+               cs35l56->mixer_ctl[i] = snd_ctl_new1(&ctl_template, cs35l56);
+               if (snd_ctl_add(cs35l56->codec->card, cs35l56->mixer_ctl[i])) {
+                       dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n",
+                               ctl_template.name);
+               }
+       }
+
+       ctl_template.info = cs35l56_hda_vol_info;
+       ctl_template.get = cs35l56_hda_vol_get;
+       ctl_template.put = cs35l56_hda_vol_put;
+       ctl_template.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ);
+       ctl_template.tlv.p = cs35l56_hda_vol_tlv;
+       snprintf(name, sizeof(name), "%s Speaker Playback Volume", cs35l56->amp_name);
+       ctl_template.name = name;
+       cs35l56->volume_ctl = snd_ctl_new1(&ctl_template, cs35l56);
+       if (snd_ctl_add(cs35l56->codec->card, cs35l56->volume_ctl))
+               dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
+}
+
+static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56)
+{
+       int i;
+
+       for (i = ARRAY_SIZE(cs35l56->mixer_ctl) - 1; i >= 0; i--)
+               snd_ctl_remove(cs35l56->codec->card, cs35l56->mixer_ctl[i]);
+
+       snd_ctl_remove(cs35l56->codec->card, cs35l56->posture_ctl);
+       snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl);
+}
+
+static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {
+       /* cs_dsp requires the client to provide this even if it is empty */
+};
+
+static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
+                                            const struct firmware **firmware, char **filename,
+                                            const char *base_name, const char *system_name,
+                                            const char *amp_name,
+                                            const char *filetype)
+{
+       char *s, c;
+       int ret = 0;
+
+       if (system_name && amp_name)
+               *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", base_name,
+                                     system_name, amp_name, filetype);
+       else if (system_name)
+               *filename = kasprintf(GFP_KERNEL, "%s-%s.%s", base_name,
+                                     system_name, filetype);
+       else
+               *filename = kasprintf(GFP_KERNEL, "%s.%s", base_name, filetype);
+
+       if (!*filename)
+               return -ENOMEM;
+
+       /*
+        * Make sure that filename is lower-case and any non alpha-numeric
+        * characters except full stop and forward slash are replaced with
+        * hyphens.
+        */
+       s = *filename;
+       while (*s) {
+               c = *s;
+               if (isalnum(c))
+                       *s = tolower(c);
+               else if (c != '.' && c != '/')
+                       *s = '-';
+               s++;
+       }
+
+       ret = firmware_request_nowarn(firmware, *filename, cs35l56->base.dev);
+       if (ret) {
+               dev_dbg(cs35l56->base.dev, "Failed to request '%s'\n", *filename);
+               kfree(*filename);
+               *filename = NULL;
+               return ret;
+       }
+
+       dev_dbg(cs35l56->base.dev, "Found '%s'\n", *filename);
+
+       return 0;
+}
+
+static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
+                                              unsigned int preloaded_fw_ver,
+                                              const struct firmware **wmfw_firmware,
+                                              char **wmfw_filename,
+                                              const struct firmware **coeff_firmware,
+                                              char **coeff_filename)
+{
+       const char *system_name = cs35l56->system_name;
+       const char *amp_name = cs35l56->amp_name;
+       char base_name[37];
+       int ret;
+
+       if (preloaded_fw_ver) {
+               snprintf(base_name, sizeof(base_name),
+                        "cirrus/cs35l%02x-%02x%s-%06x-dsp1-misc",
+                        cs35l56->base.type,
+                        cs35l56->base.rev,
+                        cs35l56->base.secured ? "-s" : "",
+                        preloaded_fw_ver & 0xffffff);
+       } else {
+               snprintf(base_name, sizeof(base_name),
+                        "cirrus/cs35l%02x-%02x%s-dsp1-misc",
+                        cs35l56->base.type,
+                        cs35l56->base.rev,
+                        cs35l56->base.secured ? "-s" : "");
+       }
+
+       if (system_name && amp_name) {
+               if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+                                                      base_name, system_name, amp_name, "wmfw")) {
+                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                         base_name, system_name, amp_name, "bin");
+                       return;
+               }
+       }
+
+       if (system_name) {
+               if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+                                                      base_name, system_name, NULL, "wmfw")) {
+                       if (amp_name)
+                               cs35l56_hda_request_firmware_file(cs35l56,
+                                                                 coeff_firmware, coeff_filename,
+                                                                 base_name, system_name,
+                                                                 amp_name, "bin");
+                       if (!*coeff_firmware)
+                               cs35l56_hda_request_firmware_file(cs35l56,
+                                                                 coeff_firmware, coeff_filename,
+                                                                 base_name, system_name,
+                                                                 NULL, "bin");
+                       return;
+               }
+
+               /*
+                * Check for system-specific bin files without wmfw before
+                * falling back to generic firmware
+                */
+               if (amp_name)
+                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                         base_name, system_name, amp_name, "bin");
+               if (!*coeff_firmware)
+                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                         base_name, system_name, NULL, "bin");
+
+               if (*coeff_firmware)
+                       return;
+       }
+
+       ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
+                                               base_name, NULL, NULL, "wmfw");
+       if (!ret) {
+               cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                 base_name, NULL, NULL, "bin");
+               return;
+       }
+
+       if (!*coeff_firmware)
+               cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
+                                                 base_name, NULL, NULL, "bin");
+}
+
+static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
+                                              char *wmfw_filename,
+                                              const struct firmware *coeff_firmware,
+                                              char *coeff_filename)
+{
+       release_firmware(wmfw_firmware);
+       kfree(wmfw_filename);
+
+       release_firmware(coeff_firmware);
+       kfree(coeff_filename);
+}
+
+static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
+{
+       int ret;
+
+       if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)
+               return;
+
+       ret = cs_amp_write_cal_coeffs(&cs35l56->cs_dsp,
+                                     &cs35l56_calibration_controls,
+                                     &cs35l56->base.cal_data);
+       if (ret < 0)
+               dev_warn(cs35l56->base.dev, "Failed to write calibration: %d\n", ret);
+       else
+               dev_info(cs35l56->base.dev, "Calibration applied\n");
+}
+
+static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
+{
+       const struct firmware *coeff_firmware = NULL;
+       const struct firmware *wmfw_firmware = NULL;
+       char *coeff_filename = NULL;
+       char *wmfw_filename = NULL;
+       unsigned int preloaded_fw_ver;
+       bool firmware_missing;
+       int ret;
+
+       /*
+        * Prepare for a new DSP power-up. If the DSP has had firmware
+        * downloaded previously then it needs to be powered down so that it
+        * can be updated.
+        */
+       if (cs35l56->base.fw_patched)
+               cs_dsp_power_down(&cs35l56->cs_dsp);
+
+       cs35l56->base.fw_patched = false;
+
+       ret = pm_runtime_resume_and_get(cs35l56->base.dev);
+       if (ret < 0) {
+               dev_err(cs35l56->base.dev, "Failed to resume and get %d\n", ret);
+               return;
+       }
+
+       /*
+        * The firmware can only be upgraded if it is currently running
+        * from the built-in ROM. If not, the wmfw/bin must be for the
+        * version of firmware that is running on the chip.
+        */
+       ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &preloaded_fw_ver);
+       if (ret)
+               goto err_pm_put;
+
+       if (firmware_missing)
+               preloaded_fw_ver = 0;
+
+       cs35l56_hda_request_firmware_files(cs35l56, preloaded_fw_ver,
+                                          &wmfw_firmware, &wmfw_filename,
+                                          &coeff_firmware, &coeff_filename);
+
+       /*
+        * If the BIOS didn't patch the firmware a bin file is mandatory to
+        * enable the ASP·
+        */
+       if (!coeff_firmware && firmware_missing) {
+               dev_err(cs35l56->base.dev, ".bin file required but not found\n");
+               goto err_fw_release;
+       }
+
+       mutex_lock(&cs35l56->base.irq_lock);
+
+       /*
+        * If the firmware hasn't been patched it must be shutdown before
+        * doing a full patch and reset afterwards. If it is already
+        * running a patched version the firmware files only contain
+        * tunings and we can use the lower cost reinit sequence instead.
+        */
+       if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
+               ret = cs35l56_firmware_shutdown(&cs35l56->base);
+               if (ret)
+                       goto err;
+       }
+
+       ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,
+                             coeff_firmware, coeff_filename, "misc");
+       if (ret) {
+               dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);
+               goto err;
+       }
+
+       if (wmfw_filename)
+               dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename);
+
+       if (coeff_filename)
+               dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);
+
+       /* If we downloaded firmware, reset the device and wait for it to boot */
+       if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
+               cs35l56_system_reset(&cs35l56->base, false);
+               regcache_mark_dirty(cs35l56->base.regmap);
+               ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
+               if (ret)
+                       goto err_powered_up;
+
+               regcache_cache_only(cs35l56->base.regmap, false);
+       }
+
+       /* Disable auto-hibernate so that runtime_pm has control */
+       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+       if (ret)
+               goto err_powered_up;
+
+       regcache_sync(cs35l56->base.regmap);
+
+       regmap_clear_bits(cs35l56->base.regmap,
+                         cs35l56->base.fw_reg->prot_sts,
+                         CS35L56_FIRMWARE_MISSING);
+       cs35l56->base.fw_patched = true;
+
+       ret = cs_dsp_run(&cs35l56->cs_dsp);
+       if (ret)
+               dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
+
+       cs35l56_hda_apply_calibration(cs35l56);
+       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
+       if (ret)
+               cs_dsp_stop(&cs35l56->cs_dsp);
+
+       cs35l56_log_tuning(&cs35l56->base, &cs35l56->cs_dsp);
+
+err_powered_up:
+       if (!cs35l56->base.fw_patched)
+               cs_dsp_power_down(&cs35l56->cs_dsp);
+err:
+       mutex_unlock(&cs35l56->base.irq_lock);
+err_fw_release:
+       cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,
+                                          coeff_firmware, coeff_filename);
+err_pm_put:
+       pm_runtime_put(cs35l56->base.dev);
+}
+
+static void cs35l56_hda_dsp_work(struct work_struct *work)
+{
+       struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, dsp_work);
+
+       cs35l56_hda_fw_load(cs35l56);
+}
+
+static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+       struct hda_component_parent *parent = master_data;
+       struct hda_component *comp;
+
+       comp = hda_component_from_index(parent, cs35l56->index);
+       if (!comp)
+               return -EINVAL;
+
+       if (comp->dev)
+               return -EBUSY;
+
+       comp->dev = dev;
+       cs35l56->codec = parent->codec;
+       strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+       comp->playback_hook = cs35l56_hda_playback_hook;
+
+       queue_work(system_long_wq, &cs35l56->dsp_work);
+
+       cs35l56_hda_create_controls(cs35l56);
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+       cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root);
+       cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);
+#endif
+
+       dev_dbg(cs35l56->base.dev, "Bound\n");
+
+       return 0;
+}
+
+static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+       struct hda_component_parent *parent = master_data;
+       struct hda_component *comp;
+
+       cancel_work_sync(&cs35l56->dsp_work);
+
+       cs35l56_hda_remove_controls(cs35l56);
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+       cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp);
+       debugfs_remove_recursive(cs35l56->debugfs_root);
+#endif
+
+       if (cs35l56->base.fw_patched)
+               cs_dsp_power_down(&cs35l56->cs_dsp);
+
+       comp = hda_component_from_index(parent, cs35l56->index);
+       if (comp && (comp->dev == dev))
+               memset(comp, 0, sizeof(*comp));
+
+       cs35l56->codec = NULL;
+
+       dev_dbg(cs35l56->base.dev, "Unbound\n");
+}
+
+static const struct component_ops cs35l56_hda_comp_ops = {
+       .bind = cs35l56_hda_bind,
+       .unbind = cs35l56_hda_unbind,
+};
+
+static int cs35l56_hda_system_suspend(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       cs35l56_hda_wait_dsp_ready(cs35l56);
+
+       if (cs35l56->playing)
+               cs35l56_hda_pause(cs35l56);
+
+       cs35l56->suspended = true;
+
+       /*
+        * The interrupt line is normally shared, but after we start suspending
+        * we can't check if our device is the source of an interrupt, and can't
+        * clear it. Prevent this race by temporarily disabling the parent irq
+        * until we reach _no_irq.
+        */
+       if (cs35l56->base.irq)
+               disable_irq(cs35l56->base.irq);
+
+       return pm_runtime_force_suspend(dev);
+}
+
+static int cs35l56_hda_system_suspend_late(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       /*
+        * RESET is usually shared by all amps so it must not be asserted until
+        * all driver instances have done their suspend() stage.
+        */
+       if (cs35l56->base.reset_gpio) {
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+               cs35l56_wait_min_reset_pulse();
+       }
+
+       return 0;
+}
+
+static int cs35l56_hda_system_suspend_no_irq(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
+       if (cs35l56->base.irq)
+               enable_irq(cs35l56->base.irq);
+
+       return 0;
+}
+
+static int cs35l56_hda_system_resume_no_irq(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       /*
+        * WAKE interrupts unmask if the CS35L56 hibernates, which can cause
+        * spurious interrupts, and the interrupt line is normally shared.
+        * We can't check if our device is the source of an interrupt, and can't
+        * clear it, until it has fully resumed. Prevent this race by temporarily
+        * disabling the parent irq until we complete resume().
+        */
+       if (cs35l56->base.irq)
+               disable_irq(cs35l56->base.irq);
+
+       return 0;
+}
+
+static int cs35l56_hda_system_resume_early(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       /* Ensure a spec-compliant RESET pulse. */
+       if (cs35l56->base.reset_gpio) {
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+               cs35l56_wait_min_reset_pulse();
+
+               /* Release shared RESET before drivers start resume(). */
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
+               cs35l56_wait_control_port_ready();
+       }
+
+       return 0;
+}
+
+static int cs35l56_hda_system_resume(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+       int ret;
+
+       /* Undo pm_runtime_force_suspend() before re-enabling the irq */
+       ret = pm_runtime_force_resume(dev);
+       if (cs35l56->base.irq)
+               enable_irq(cs35l56->base.irq);
+
+       if (ret)
+               return ret;
+
+       cs35l56->suspended = false;
+
+       if (!cs35l56->codec)
+               return 0;
+
+       ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
+       dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
+       if (ret > 0)
+               queue_work(system_long_wq, &cs35l56->dsp_work);
+
+       if (cs35l56->playing)
+               cs35l56_hda_play(cs35l56);
+
+       return 0;
+}
+
+static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
+{
+       u32 values[HDA_MAX_COMPONENTS];
+       char hid_string[8];
+       struct acpi_device *adev;
+       const char *property, *sub;
+       size_t nval;
+       int i, ret;
+
+       /*
+        * ACPI_COMPANION isn't available when this driver was instantiated by
+        * the serial-multi-instantiate driver, so lookup the node by HID
+        */
+       if (!ACPI_COMPANION(cs35l56->base.dev)) {
+               snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid);
+               adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1);
+               if (!adev) {
+                       dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",
+                               dev_name(cs35l56->base.dev));
+                       return -ENODEV;
+               }
+               ACPI_COMPANION_SET(cs35l56->base.dev, adev);
+       }
+
+       property = "cirrus,dev-index";
+       ret = device_property_count_u32(cs35l56->base.dev, property);
+       if (ret <= 0)
+               goto err;
+
+       if (ret > ARRAY_SIZE(values)) {
+               ret = -EINVAL;
+               goto err;
+       }
+       nval = ret;
+
+       ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
+       if (ret)
+               goto err;
+
+       cs35l56->index = -1;
+       for (i = 0; i < nval; i++) {
+               if (values[i] == id) {
+                       cs35l56->index = i;
+                       break;
+               }
+       }
+       /*
+        * It's not an error for the ID to be missing: for I2C there can be
+        * an alias address that is not a real device. So reject silently.
+        */
+       if (cs35l56->index == -1) {
+               dev_dbg(cs35l56->base.dev, "No index found in %s\n", property);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
+
+       if (IS_ERR(sub)) {
+               dev_info(cs35l56->base.dev,
+                        "Read ACPI _SUB failed(%ld): fallback to generic firmware\n",
+                        PTR_ERR(sub));
+       } else {
+               ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);
+               if (ret == -ENOENT) {
+                       cs35l56->system_name = sub;
+               } else if (ret >= 0) {
+                       cs35l56->system_name = kasprintf(GFP_KERNEL, "%s-spkid%d", sub, ret);
+                       kfree(sub);
+                       if (!cs35l56->system_name)
+                               return -ENOMEM;
+               } else {
+                       return ret;
+               }
+       }
+
+       cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev,
+                                                                "reset",
+                                                                cs35l56->index,
+                                                                GPIOD_OUT_LOW);
+       if (IS_ERR(cs35l56->base.reset_gpio)) {
+               ret = PTR_ERR(cs35l56->base.reset_gpio);
+
+               /*
+                * If RESET is shared the first amp to probe will grab the reset
+                * line and reset all the amps
+                */
+               if (ret != -EBUSY)
+                       return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");
+
+               dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
+               cs35l56->base.reset_gpio = NULL;
+       }
+
+       return 0;
+
+err:
+       if (ret != -ENODEV)
+               dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret);
+
+       return ret;
+}
+
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
+{
+       int ret;
+
+       mutex_init(&cs35l56->base.irq_lock);
+       dev_set_drvdata(cs35l56->base.dev, cs35l56);
+
+       INIT_WORK(&cs35l56->dsp_work, cs35l56_hda_dsp_work);
+
+       ret = cs35l56_hda_read_acpi(cs35l56, hid, id);
+       if (ret)
+               goto err;
+
+       cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d",
+                                          cs35l56->index + 1);
+       if (!cs35l56->amp_name) {
+               ret = -ENOMEM;
+               goto err;
+       }
+
+       cs35l56->base.cal_index = -1;
+
+       cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);
+       cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;
+
+       if (cs35l56->base.reset_gpio) {
+               dev_dbg(cs35l56->base.dev, "Hard reset\n");
+
+               /*
+                * The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the
+                * ACPI defines a different default state. So explicitly set low.
+                */
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+               cs35l56_wait_min_reset_pulse();
+               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
+       }
+
+       ret = cs35l56_hw_init(&cs35l56->base);
+       if (ret < 0)
+               goto err;
+
+       /* Reset the device and wait for it to boot */
+       cs35l56_system_reset(&cs35l56->base, false);
+       ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
+       if (ret)
+               goto err;
+
+       regcache_cache_only(cs35l56->base.regmap, false);
+
+       ret = cs35l56_set_patch(&cs35l56->base);
+       if (ret)
+               goto err;
+
+       regcache_mark_dirty(cs35l56->base.regmap);
+       regcache_sync(cs35l56->base.regmap);
+
+       /* Disable auto-hibernate so that runtime_pm has control */
+       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
+       if (ret)
+               goto err;
+
+       ret = cs35l56_get_calibration(&cs35l56->base);
+       if (ret)
+               goto err;
+
+       ret = cs_dsp_halo_init(&cs35l56->cs_dsp);
+       if (ret) {
+               dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n");
+               goto err;
+       }
+
+       dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
+                cs35l56->system_name, cs35l56->amp_name);
+
+       regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,
+                              ARRAY_SIZE(cs35l56_hda_dai_config));
+
+       /*
+        * By default only enable one ASP1TXn, where n=amplifier index,
+        * This prevents multiple amps trying to drive the same slot.
+        */
+       cs35l56->asp_tx_mask = BIT(cs35l56->index);
+
+       pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000);
+       pm_runtime_use_autosuspend(cs35l56->base.dev);
+       pm_runtime_set_active(cs35l56->base.dev);
+       pm_runtime_mark_last_busy(cs35l56->base.dev);
+       pm_runtime_enable(cs35l56->base.dev);
+
+       cs35l56->base.init_done = true;
+
+       ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);
+       if (ret) {
+               dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);
+               goto pm_err;
+       }
+
+       return 0;
+
+pm_err:
+       pm_runtime_disable(cs35l56->base.dev);
+       cs_dsp_remove(&cs35l56->cs_dsp);
+err:
+       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, "SND_HDA_SCODEC_CS35L56");
+
+void cs35l56_hda_remove(struct device *dev)
+{
+       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
+
+       component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops);
+
+       pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
+       pm_runtime_get_sync(cs35l56->base.dev);
+       pm_runtime_disable(cs35l56->base.dev);
+
+       cs_dsp_remove(&cs35l56->cs_dsp);
+
+       kfree(cs35l56->system_name);
+       pm_runtime_put_noidle(cs35l56->base.dev);
+
+       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
+}
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, "SND_HDA_SCODEC_CS35L56");
+
+const struct dev_pm_ops cs35l56_hda_pm_ops = {
+       RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume)
+       LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late,
+                                cs35l56_hda_system_resume_early)
+       NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq,
+                                 cs35l56_hda_system_resume_no_irq)
+};
+EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, "SND_HDA_SCODEC_CS35L56");
+
+MODULE_DESCRIPTION("CS35L56 HDA Driver");
+MODULE_IMPORT_NS("FW_CS_DSP");
+MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
+MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("cirrus/cs35l54-*.wmfw");
+MODULE_FIRMWARE("cirrus/cs35l54-*.bin");
+MODULE_FIRMWARE("cirrus/cs35l56-*.wmfw");
+MODULE_FIRMWARE("cirrus/cs35l56-*.bin");
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda.h b/sound/hda/codecs/side-codecs/cs35l56_hda.h
new file mode 100644 (file)
index 0000000..38d94fb
--- /dev/null
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * HDA audio driver for Cirrus Logic CS35L56 smart amp
+ *
+ * Copyright (C) 2023 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __CS35L56_HDA_H__
+#define __CS35L56_HDA_H__
+
+#include <linux/device.h>
+#include <linux/gpio/consumer.h>
+#include <linux/firmware/cirrus/cs_dsp.h>
+#include <linux/firmware/cirrus/wmfw.h>
+#include <linux/regulator/consumer.h>
+#include <linux/workqueue.h>
+#include <sound/cs35l56.h>
+
+struct dentry;
+
+struct cs35l56_hda {
+       struct cs35l56_base base;
+       struct hda_codec *codec;
+       struct work_struct dsp_work;
+
+       int index;
+       const char *system_name;
+       const char *amp_name;
+
+       struct cs_dsp cs_dsp;
+       bool playing;
+       bool suspended;
+       u8 asp_tx_mask;
+
+       struct snd_kcontrol *posture_ctl;
+       struct snd_kcontrol *volume_ctl;
+       struct snd_kcontrol *mixer_ctl[4];
+
+#if IS_ENABLED(CONFIG_SND_DEBUG)
+       struct dentry *debugfs_root;
+#endif
+};
+
+extern const struct dev_pm_ops cs35l56_hda_pm_ops;
+
+int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id);
+void cs35l56_hda_remove(struct device *dev);
+
+#endif /*__CS35L56_HDA_H__*/
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c b/sound/hda/codecs/side-codecs/cs35l56_hda_i2c.c
new file mode 100644 (file)
index 0000000..d10209e
--- /dev/null
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// CS35L56 HDA audio driver I2C binding
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+
+#include "cs35l56_hda.h"
+
+static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
+{
+       const struct i2c_device_id *id = i2c_client_get_device_id(clt);
+       struct cs35l56_hda *cs35l56;
+       int ret;
+
+       cs35l56 = devm_kzalloc(&clt->dev, sizeof(*cs35l56), GFP_KERNEL);
+       if (!cs35l56)
+               return -ENOMEM;
+
+       cs35l56->base.dev = &clt->dev;
+
+#ifdef CS35L56_WAKE_HOLD_TIME_US
+       cs35l56->base.can_hibernate = true;
+#endif
+
+       cs35l56->base.fw_reg = &cs35l56_fw_reg;
+
+       cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c);
+       if (IS_ERR(cs35l56->base.regmap)) {
+               ret = PTR_ERR(cs35l56->base.regmap);
+               dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, clt->addr);
+       if (ret)
+               return ret;
+       ret = cs35l56_irq_request(&cs35l56->base, clt->irq);
+       if (ret < 0)
+               cs35l56_hda_remove(cs35l56->base.dev);
+
+       return ret;
+}
+
+static void cs35l56_hda_i2c_remove(struct i2c_client *clt)
+{
+       cs35l56_hda_remove(&clt->dev);
+}
+
+static const struct i2c_device_id cs35l56_hda_i2c_id[] = {
+       { "cs35l54-hda", 0x3554 },
+       { "cs35l56-hda", 0x3556 },
+       { "cs35l57-hda", 0x3557 },
+       {}
+};
+
+static const struct acpi_device_id cs35l56_acpi_hda_match[] = {
+       { "CSC3554", 0 },
+       { "CSC3556", 0 },
+       { "CSC3557", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, cs35l56_acpi_hda_match);
+
+static struct i2c_driver cs35l56_hda_i2c_driver = {
+       .driver = {
+               .name             = "cs35l56-hda",
+               .acpi_match_table = cs35l56_acpi_hda_match,
+               .pm               = &cs35l56_hda_pm_ops,
+       },
+       .id_table       = cs35l56_hda_i2c_id,
+       .probe          = cs35l56_hda_i2c_probe,
+       .remove         = cs35l56_hda_i2c_remove,
+};
+module_i2c_driver(cs35l56_hda_i2c_driver);
+
+MODULE_DESCRIPTION("HDA CS35L56 I2C driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/cs35l56_hda_spi.c b/sound/hda/codecs/side-codecs/cs35l56_hda_spi.c
new file mode 100644 (file)
index 0000000..f57533d
--- /dev/null
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0-only
+//
+// CS35L56 HDA audio driver SPI binding
+//
+// Copyright (C) 2023 Cirrus Logic, Inc. and
+//                    Cirrus Logic International Semiconductor Ltd.
+
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+
+#include "cs35l56_hda.h"
+
+static int cs35l56_hda_spi_probe(struct spi_device *spi)
+{
+       const struct spi_device_id *id = spi_get_device_id(spi);
+       struct cs35l56_hda *cs35l56;
+       int ret;
+
+       cs35l56 = devm_kzalloc(&spi->dev, sizeof(*cs35l56), GFP_KERNEL);
+       if (!cs35l56)
+               return -ENOMEM;
+
+       cs35l56->base.dev = &spi->dev;
+       ret = cs35l56_init_config_for_spi(&cs35l56->base, spi);
+       if (ret)
+               return ret;
+
+#ifdef CS35L56_WAKE_HOLD_TIME_US
+       cs35l56->base.can_hibernate = true;
+#endif
+
+       cs35l56->base.fw_reg = &cs35l56_fw_reg;
+
+       cs35l56->base.regmap = devm_regmap_init_spi(spi, &cs35l56_regmap_spi);
+       if (IS_ERR(cs35l56->base.regmap)) {
+               ret = PTR_ERR(cs35l56->base.regmap);
+               dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, spi_get_chipselect(spi, 0));
+       if (ret)
+               return ret;
+       ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
+       if (ret < 0)
+               cs35l56_hda_remove(cs35l56->base.dev);
+
+       return ret;
+}
+
+static void cs35l56_hda_spi_remove(struct spi_device *spi)
+{
+       cs35l56_hda_remove(&spi->dev);
+}
+
+static const struct spi_device_id cs35l56_hda_spi_id[] = {
+       { "cs35l54-hda", 0x3554 },
+       { "cs35l56-hda", 0x3556 },
+       { "cs35l57-hda", 0x3557 },
+       {}
+};
+
+static const struct acpi_device_id cs35l56_acpi_hda_match[] = {
+       { "CSC3554", 0 },
+       { "CSC3556", 0 },
+       { "CSC3557", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, cs35l56_acpi_hda_match);
+
+static struct spi_driver cs35l56_hda_spi_driver = {
+       .driver = {
+               .name             = "cs35l56-hda",
+               .acpi_match_table = cs35l56_acpi_hda_match,
+               .pm               = &cs35l56_hda_pm_ops,
+       },
+       .id_table       = cs35l56_hda_spi_id,
+       .probe          = cs35l56_hda_spi_probe,
+       .remove         = cs35l56_hda_spi_remove,
+};
+module_spi_driver(cs35l56_hda_spi_driver);
+
+MODULE_DESCRIPTION("HDA CS35L56 SPI driver");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56");
+MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/hda_component.c b/sound/hda/codecs/side-codecs/hda_component.c
new file mode 100644 (file)
index 0000000..71860e2
--- /dev/null
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HD audio Component Binding Interface
+ *
+ * Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
+ *                     Cirrus Logic International Semiconductor Ltd.
+ */
+
+#include <linux/acpi.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <sound/hda_codec.h>
+#include "hda_component.h"
+#include "hda_local.h"
+
+#ifdef CONFIG_ACPI
+void hda_component_acpi_device_notify(struct hda_component_parent *parent,
+                                     acpi_handle handle, u32 event, void *data)
+{
+       struct hda_component *comp;
+       int i;
+
+       mutex_lock(&parent->mutex);
+       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+               comp = hda_component_from_index(parent, i);
+               if (comp->dev && comp->acpi_notify)
+                       comp->acpi_notify(acpi_device_handle(comp->adev), event, comp->dev);
+       }
+       mutex_unlock(&parent->mutex);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, "SND_HDA_SCODEC_COMPONENT");
+
+int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+                                                 struct hda_component_parent *parent,
+                                                 acpi_notify_handler handler, void *data)
+{
+       bool support_notifications = false;
+       struct acpi_device *adev;
+       struct hda_component *comp;
+       int ret;
+       int i;
+
+       adev = parent->comps[0].adev;
+       if (!acpi_device_handle(adev))
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+               comp = hda_component_from_index(parent, i);
+               support_notifications = support_notifications ||
+                       comp->acpi_notifications_supported;
+       }
+
+       if (support_notifications) {
+               ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
+                                                 handler, data);
+               if (ret < 0) {
+                       codec_warn(cdc, "Failed to install notify handler: %d\n", ret);
+                       return 0;
+               }
+
+               codec_dbg(cdc, "Notify handler installed\n");
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT");
+
+void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+                                                    struct hda_component_parent *parent,
+                                                    acpi_notify_handler handler)
+{
+       struct acpi_device *adev;
+       int ret;
+
+       adev = parent->comps[0].adev;
+       if (!acpi_device_handle(adev))
+               return;
+
+       ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, handler);
+       if (ret < 0)
+               codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT");
+#endif /* ifdef CONFIG_ACPI */
+
+void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action)
+{
+       struct hda_component *comp;
+       int i;
+
+       mutex_lock(&parent->mutex);
+       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+               comp = hda_component_from_index(parent, i);
+               if (comp->dev && comp->pre_playback_hook)
+                       comp->pre_playback_hook(comp->dev, action);
+       }
+       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+               comp = hda_component_from_index(parent, i);
+               if (comp->dev && comp->playback_hook)
+                       comp->playback_hook(comp->dev, action);
+       }
+       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
+               comp = hda_component_from_index(parent, i);
+               if (comp->dev && comp->post_playback_hook)
+                       comp->post_playback_hook(comp->dev, action);
+       }
+       mutex_unlock(&parent->mutex);
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, "SND_HDA_SCODEC_COMPONENT");
+
+struct hda_scodec_match {
+       const char *bus;
+       const char *hid;
+       const char *match_str;
+       int index;
+};
+
+/* match the device name in a slightly relaxed manner */
+static int hda_comp_match_dev_name(struct device *dev, void *data)
+{
+       struct hda_scodec_match *p = data;
+       const char *d = dev_name(dev);
+       int n = strlen(p->bus);
+       char tmp[32];
+
+       /* check the bus name */
+       if (strncmp(d, p->bus, n))
+               return 0;
+       /* skip the bus number */
+       if (isdigit(d[n]))
+               n++;
+       /* the rest must be exact matching */
+       snprintf(tmp, sizeof(tmp), p->match_str, p->hid, p->index);
+       return !strcmp(d + n, tmp);
+}
+
+int hda_component_manager_bind(struct hda_codec *cdc,
+                              struct hda_component_parent *parent)
+{
+       int ret;
+
+       /* Init shared and component specific data */
+       memset(parent->comps, 0, sizeof(parent->comps));
+
+       mutex_lock(&parent->mutex);
+       ret = component_bind_all(hda_codec_dev(cdc), parent);
+       mutex_unlock(&parent->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, "SND_HDA_SCODEC_COMPONENT");
+
+int hda_component_manager_init(struct hda_codec *cdc,
+                              struct hda_component_parent *parent, int count,
+                              const char *bus, const char *hid,
+                              const char *match_str,
+                              const struct component_master_ops *ops)
+{
+       struct device *dev = hda_codec_dev(cdc);
+       struct component_match *match = NULL;
+       struct hda_scodec_match *sm;
+       int ret, i;
+
+       if (parent->codec) {
+               codec_err(cdc, "Component binding already created (SSID: %x)\n",
+                         cdc->core.subsystem_id);
+               return -EINVAL;
+       }
+       parent->codec = cdc;
+
+       mutex_init(&parent->mutex);
+
+       for (i = 0; i < count; i++) {
+               sm = devm_kmalloc(dev, sizeof(*sm), GFP_KERNEL);
+               if (!sm)
+                       return -ENOMEM;
+
+               sm->bus = bus;
+               sm->hid = hid;
+               sm->match_str = match_str;
+               sm->index = i;
+               component_match_add(dev, &match, hda_comp_match_dev_name, sm);
+       }
+
+       ret = component_master_add_with_match(dev, ops, match);
+       if (ret)
+               codec_err(cdc, "Fail to register component aggregator %d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, "SND_HDA_SCODEC_COMPONENT");
+
+void hda_component_manager_free(struct hda_component_parent *parent,
+                               const struct component_master_ops *ops)
+{
+       struct device *dev;
+
+       if (!parent->codec)
+               return;
+
+       dev = hda_codec_dev(parent->codec);
+
+       component_master_del(dev, ops);
+
+       parent->codec = NULL;
+}
+EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, "SND_HDA_SCODEC_COMPONENT");
+
+MODULE_DESCRIPTION("HD Audio component binding library");
+MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
+MODULE_LICENSE("GPL");
diff --git a/sound/hda/codecs/side-codecs/hda_component.h b/sound/hda/codecs/side-codecs/hda_component.h
new file mode 100644 (file)
index 0000000..7ee3715
--- /dev/null
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * HD audio Component Binding Interface
+ *
+ * Copyright (C) 2021 Cirrus Logic, Inc. and
+ *                    Cirrus Logic International Semiconductor Ltd.
+ */
+
+#ifndef __HDA_COMPONENT_H__
+#define __HDA_COMPONENT_H__
+
+#include <linux/acpi.h>
+#include <linux/component.h>
+#include <linux/mutex.h>
+#include <sound/hda_codec.h>
+
+#define HDA_MAX_COMPONENTS     4
+#define HDA_MAX_NAME_SIZE      50
+
+struct hda_component {
+       struct device *dev;
+       char name[HDA_MAX_NAME_SIZE];
+       struct acpi_device *adev;
+       bool acpi_notifications_supported;
+       void (*acpi_notify)(acpi_handle handle, u32 event, struct device *dev);
+       void (*pre_playback_hook)(struct device *dev, int action);
+       void (*playback_hook)(struct device *dev, int action);
+       void (*post_playback_hook)(struct device *dev, int action);
+};
+
+struct hda_component_parent {
+       struct mutex mutex;
+       struct hda_codec *codec;
+       struct hda_component comps[HDA_MAX_COMPONENTS];
+};
+
+#ifdef CONFIG_ACPI
+void hda_component_acpi_device_notify(struct hda_component_parent *parent,
+                                     acpi_handle handle, u32 event, void *data);
+int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+                                                 struct hda_component_parent *parent,
+                                                 acpi_notify_handler handler, void *data);
+void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+                                                    struct hda_component_parent *parent,
+                                                    acpi_notify_handler handler);
+#else
+static inline void hda_component_acpi_device_notify(struct hda_component_parent *parent,
+                                                   acpi_handle handle,
+                                                   u32 event,
+                                                   void *data)
+{
+}
+
+static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
+                                                               struct hda_component_parent *parent,
+                                                               acpi_notify_handler handler,
+                                                               void *data)
+
+{
+       return 0;
+}
+
+static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
+                                                                  struct hda_component_parent *parent,
+                                                                  acpi_notify_handler handler)
+{
+}
+#endif /* ifdef CONFIG_ACPI */
+
+void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action);
+
+int hda_component_manager_init(struct hda_codec *cdc,
+                              struct hda_component_parent *parent, int count,
+                              const char *bus, const char *hid,
+                              const char *match_str,
+                              const struct component_master_ops *ops);
+
+void hda_component_manager_free(struct hda_component_parent *parent,
+                               const struct component_master_ops *ops);
+
+int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent);
+
+static inline struct hda_component *hda_component_from_index(struct hda_component_parent *parent,
+                                                            int index)
+{
+       if (!parent)
+               return NULL;
+
+       if (index < 0 || index >= ARRAY_SIZE(parent->comps))
+               return NULL;
+
+       return &parent->comps[index];
+}
+
+static inline void hda_component_manager_unbind(struct hda_codec *cdc,
+                                               struct hda_component_parent *parent)
+{
+       mutex_lock(&parent->mutex);
+       component_unbind_all(hda_codec_dev(cdc), parent);
+       mutex_unlock(&parent->mutex);
+}
+
+#endif /* ifndef __HDA_COMPONENT_H__ */
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda.c b/sound/hda/codecs/side-codecs/tas2781_hda.c
new file mode 100644 (file)
index 0000000..34217ce
--- /dev/null
@@ -0,0 +1,379 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2781 HDA Shared Lib for I2C&SPI driver
+//
+// Copyright 2025 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+
+#include <linux/component.h>
+#include <linux/crc8.h>
+#include <linux/crc32.h>
+#include <linux/efi.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+
+#include "tas2781_hda.h"
+
+const efi_guid_t tasdev_fct_efi_guid[] = {
+       /* DELL */
+       EFI_GUID(0xcc92382d, 0x6337, 0x41cb, 0xa8, 0x8b, 0x8e, 0xce, 0x74,
+               0x91, 0xea, 0x9f),
+       /* HP */
+       EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a,
+               0xa3, 0x5d, 0xb3),
+       /* LENOVO & OTHERS */
+       EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, 0x43, 0xa3, 0xf4,
+               0x31, 0x0a, 0x92),
+};
+EXPORT_SYMBOL_NS_GPL(tasdev_fct_efi_guid, "SND_HDA_SCODEC_TAS2781");
+
+static void tas2781_apply_calib(struct tasdevice_priv *p)
+{
+       struct calidata *cali_data = &p->cali_data;
+       struct cali_reg *r = &cali_data->cali_reg_array;
+       unsigned char *data = cali_data->data;
+       unsigned int *tmp_val = (unsigned int *)data;
+       unsigned int cali_reg[TASDEV_CALIB_N] = {
+               TASDEVICE_REG(0, 0x17, 0x74),
+               TASDEVICE_REG(0, 0x18, 0x0c),
+               TASDEVICE_REG(0, 0x18, 0x14),
+               TASDEVICE_REG(0, 0x13, 0x70),
+               TASDEVICE_REG(0, 0x18, 0x7c),
+       };
+       unsigned int crc, oft, node_num;
+       unsigned char *buf;
+       int i, j, k, l;
+
+       if (tmp_val[0] == 2781) {
+               /*
+                * New features were added in calibrated Data V3:
+                *     1. Added calibration registers address define in
+                *          a node, marked as Device id == 0x80.
+                * New features were added in calibrated Data V2:
+                *     1. Added some the fields to store the link_id and
+                *          uniqie_id for multi-link solutions
+                *     2. Support flexible number of devices instead of
+                *          fixed one in V1.
+                * Layout of calibrated data V2 in UEFI(total 256 bytes):
+                *     ChipID (2781, 4 bytes)
+                *     Data-Group-Sum (4 bytes)
+                *     TimeStamp of Calibration (4 bytes)
+                *     for (i = 0; i < Data-Group-Sum; i++) {
+                *          if (Data type != 0x80) (4 bytes)
+                *               Calibrated Data of Device #i (20 bytes)
+                *          else
+                *               Calibration registers address (5*4 = 20 bytes)
+                *               # V2: No reg addr in data grp section.
+                *               # V3: Normally the last grp is the reg addr.
+                *     }
+                *     CRC (4 bytes)
+                *     Reserved (the rest)
+                */
+               crc = crc32(~0, data, (3 + tmp_val[1] * 6) * 4) ^ ~0;
+
+               if (crc != tmp_val[3 + tmp_val[1] * 6]) {
+                       cali_data->total_sz = 0;
+                       dev_err(p->dev, "%s: CRC error\n", __func__);
+                       return;
+               }
+               node_num = tmp_val[1];
+
+               for (j = 0, k = 0; j < node_num; j++) {
+                       oft = j * 6 + 3;
+                       if (tmp_val[oft] == TASDEV_UEFI_CALI_REG_ADDR_FLG) {
+                               for (i = 0; i < TASDEV_CALIB_N; i++) {
+                                       buf = &data[(oft + i + 1) * 4];
+                                       cali_reg[i] = TASDEVICE_REG(buf[1],
+                                               buf[2], buf[3]);
+                               }
+                       } else {
+                               l = j * (cali_data->cali_dat_sz_per_dev + 1);
+                               if (k >= p->ndev || l > oft * 4) {
+                                       dev_err(p->dev, "%s: dev sum error\n",
+                                               __func__);
+                                       cali_data->total_sz = 0;
+                                       return;
+                               }
+
+                               data[l] = k;
+                               oft++;
+                               for (i = 0; i < TASDEV_CALIB_N * 4; i++)
+                                       data[l + i + 1] = data[4 * oft + i];
+                               k++;
+                       }
+               }
+       } else {
+               /*
+                * Calibration data is in V1 format.
+                * struct cali_data {
+                *     char cali_data[20];
+                * }
+                *
+                * struct {
+                *     struct cali_data cali_data[4];
+                *     int  TimeStamp of Calibration (4 bytes)
+                *     int CRC (4 bytes)
+                * } ueft;
+                */
+               crc = crc32(~0, data, 84) ^ ~0;
+               if (crc != tmp_val[21]) {
+                       cali_data->total_sz = 0;
+                       dev_err(p->dev, "%s: V1 CRC error\n", __func__);
+                       return;
+               }
+
+               for (j = p->ndev - 1; j >= 0; j--) {
+                       l = j * (cali_data->cali_dat_sz_per_dev + 1);
+                       for (i = TASDEV_CALIB_N * 4; i > 0 ; i--)
+                               data[l + i] = data[p->index * 5 + i];
+                       data[l+i] = j;
+               }
+       }
+
+       if (p->dspbin_typ == TASDEV_BASIC) {
+               r->r0_reg = cali_reg[0];
+               r->invr0_reg = cali_reg[1];
+               r->r0_low_reg = cali_reg[2];
+               r->pow_reg = cali_reg[3];
+               r->tlimit_reg = cali_reg[4];
+       }
+
+       p->is_user_space_calidata = true;
+       cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
+}
+
+/*
+ * Update the calibration data, including speaker impedance, f0, etc,
+ * into algo. Calibrate data is done by manufacturer in the factory.
+ * The data is used by Algo for calculating the speaker temperature,
+ * speaker membrane excursion and f0 in real time during playback.
+ * Calibration data format in EFI is V2, since 2024.
+ */
+int tas2781_save_calibration(struct tas2781_hda *hda)
+{
+       /*
+        * GUID was used for data access in BIOS, it was provided by board
+        * manufactory.
+        */
+       efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
+       static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME;
+       struct tasdevice_priv *p = hda->priv;
+       struct calidata *cali_data = &p->cali_data;
+       unsigned long total_sz = 0;
+       unsigned int attr, size;
+       unsigned char *data;
+       efi_status_t status;
+
+       if (hda->catlog_id < LENOVO)
+               efi_guid = tasdev_fct_efi_guid[hda->catlog_id];
+
+       cali_data->cali_dat_sz_per_dev = 20;
+       size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
+       /* Get real size of UEFI variable */
+       status = efi.get_variable(efi_name, &efi_guid, &attr, &total_sz, NULL);
+       cali_data->total_sz = total_sz > size ? total_sz : size;
+       if (status == EFI_BUFFER_TOO_SMALL) {
+               /* Allocate data buffer of data_size bytes */
+               data = p->cali_data.data = devm_kzalloc(p->dev,
+                       p->cali_data.total_sz, GFP_KERNEL);
+               if (!data) {
+                       p->cali_data.total_sz = 0;
+                       return -ENOMEM;
+               }
+               /* Get variable contents into buffer */
+               status = efi.get_variable(efi_name, &efi_guid, &attr,
+                       &p->cali_data.total_sz, data);
+       }
+       if (status != EFI_SUCCESS) {
+               p->cali_data.total_sz = 0;
+               return status;
+       }
+
+       tas2781_apply_calib(p);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781");
+
+void tas2781_hda_remove(struct device *dev,
+       const struct component_ops *ops)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+       component_del(tas_hda->dev, ops);
+
+       pm_runtime_get_sync(tas_hda->dev);
+       pm_runtime_disable(tas_hda->dev);
+
+       pm_runtime_put_noidle(tas_hda->dev);
+
+       tasdevice_remove(tas_hda->priv);
+}
+EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_info_config(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct tasdevice_fw *tas_fw = tas_priv->fmw;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = tas_fw->nr_configurations - 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+               kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       int profile_id = ucontrol->value.integer.value[0];
+       int max = tas_priv->rcabin.ncfgs - 1;
+       int val, ret = 0;
+
+       val = clamp(profile_id, 0, max);
+
+       guard(mutex)(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+               kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
+
+       if (tas_priv->rcabin.profile_cfg_id != val) {
+               tas_priv->rcabin.profile_cfg_id = val;
+               ret = 1;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_program_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = tas_priv->cur_prog;
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+               kcontrol->id.name, tas_priv->cur_prog);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_program_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct tasdevice_fw *tas_fw = tas_priv->fmw;
+       int nr_program = ucontrol->value.integer.value[0];
+       int max = tas_fw->nr_programs - 1;
+       int val, ret = 0;
+
+       val = clamp(nr_program, 0, max);
+
+       guard(mutex)(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+               kcontrol->id.name, tas_priv->cur_prog, val);
+
+       if (tas_priv->cur_prog != val) {
+               tas_priv->cur_prog = val;
+               ret = 1;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_config_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = tas_priv->cur_conf;
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+               kcontrol->id.name, tas_priv->cur_conf);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_config_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct tasdevice_fw *tas_fw = tas_priv->fmw;
+       int nr_config = ucontrol->value.integer.value[0];
+       int max = tas_fw->nr_configurations - 1;
+       int val, ret = 0;
+
+       val = clamp(nr_config, 0, max);
+
+       guard(mutex)(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+               kcontrol->id.name, tas_priv->cur_conf, val);
+
+       if (tas_priv->cur_conf != val) {
+               tas_priv->cur_conf = val;
+               ret = 1;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
+
+MODULE_DESCRIPTION("TAS2781 HDA Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda.h b/sound/hda/codecs/side-codecs/tas2781_hda.h
new file mode 100644 (file)
index 0000000..575a701
--- /dev/null
@@ -0,0 +1,90 @@
+/* SPDX-License-Identifier: GPL-2.0-only
+ *
+ * HDA audio driver for Texas Instruments TAS2781 smart amp
+ *
+ * Copyright (C) 2025 Texas Instruments, Inc.
+ */
+#ifndef __TAS2781_HDA_H__
+#define __TAS2781_HDA_H__
+
+#include <sound/asound.h>
+
+/* Flag of calibration registers address. */
+#define TASDEV_UEFI_CALI_REG_ADDR_FLG  BIT(7)
+#define TASDEVICE_CALIBRATION_DATA_NAME        L"CALI_DATA"
+#define TASDEV_CALIB_N                 5
+
+/*
+ * No standard control callbacks for SNDRV_CTL_ELEM_IFACE_CARD
+ * Define two controls, one is Volume control callbacks, the other is
+ * flag setting control callbacks.
+ */
+
+/* Volume control callbacks for tas2781 */
+#define ACARD_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \
+       xhandler_get, xhandler_put, tlv_array) { \
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = (xname), \
+       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+               SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+       .tlv.p = (tlv_array), \
+       .info = snd_soc_info_volsw, \
+       .get = xhandler_get, .put = xhandler_put, \
+       .private_value = (unsigned long)&(struct soc_mixer_control) { \
+               .reg = xreg, .rreg = xreg, \
+               .shift = xshift, .rshift = xshift,\
+               .min = xmin, .max = xmax, .invert = xinvert, \
+       } \
+}
+
+/* Flag control callbacks for tas2781 */
+#define ACARD_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) { \
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
+       .name = xname, \
+       .info = snd_ctl_boolean_mono_info, \
+       .get = xhandler_get, \
+       .put = xhandler_put, \
+       .private_value = xdata, \
+}
+
+enum device_catlog_id {
+       DELL = 0,
+       HP,
+       LENOVO,
+       OTHERS
+};
+
+struct tas2781_hda {
+       struct device *dev;
+       struct tasdevice_priv *priv;
+       struct snd_kcontrol *dsp_prog_ctl;
+       struct snd_kcontrol *dsp_conf_ctl;
+       struct snd_kcontrol *prof_ctl;
+       enum device_catlog_id catlog_id;
+       void *hda_priv;
+};
+
+extern const efi_guid_t tasdev_fct_efi_guid[];
+
+int tas2781_save_calibration(struct tas2781_hda *p);
+void tas2781_hda_remove(struct device *dev,
+       const struct component_ops *ops);
+int tasdevice_info_profile(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_info *uctl);
+int tasdevice_info_programs(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_info *uctl);
+int tasdevice_info_config(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_info *uctl);
+int tasdevice_set_profile_id(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_get_profile_id(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_program_get(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_program_put(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_config_put(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_config_get(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+
+#endif
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c b/sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
new file mode 100644 (file)
index 0000000..bacc3f6
--- /dev/null
@@ -0,0 +1,751 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2781 HDA I2C driver
+//
+// Copyright 2023 - 2025 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+// Current maintainer: Baojun Xu <baojun.xu@ti.com>
+
+#include <linux/unaligned.h>
+#include <linux/acpi.h>
+#include <linux/crc8.h>
+#include <linux/crc32.h>
+#include <linux/efi.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/pci_ids.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <sound/hda_codec.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+#include <sound/tas2781-comlib-i2c.h>
+#include <sound/tlv.h>
+#include <sound/tas2781-tlv.h>
+
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_component.h"
+#include "hda_jack.h"
+#include "../generic.h"
+#include "tas2781_hda.h"
+
+#define TAS2563_CAL_VAR_NAME_MAX       16
+#define TAS2563_CAL_ARRAY_SIZE         80
+#define TAS2563_CAL_DATA_SIZE          4
+#define TAS2563_MAX_CHANNELS           4
+#define TAS2563_CAL_CH_SIZE            20
+
+#define TAS2563_CAL_R0_LOW             TASDEVICE_REG(0, 0x0f, 0x48)
+#define TAS2563_CAL_POWER              TASDEVICE_REG(0, 0x0d, 0x3c)
+#define TAS2563_CAL_INVR0              TASDEVICE_REG(0, 0x0f, 0x40)
+#define TAS2563_CAL_TLIM               TASDEVICE_REG(0, 0x10, 0x14)
+#define TAS2563_CAL_R0                 TASDEVICE_REG(0, 0x0f, 0x34)
+
+struct tas2781_hda_i2c_priv {
+       struct snd_kcontrol *snd_ctls[2];
+       int (*save_calibration)(struct tas2781_hda *h);
+};
+
+static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
+{
+       struct tasdevice_priv *tas_priv = data;
+       struct acpi_resource_i2c_serialbus *sb;
+
+       if (i2c_acpi_get_i2c_resource(ares, &sb)) {
+               if (tas_priv->ndev < TASDEVICE_MAX_CHANNELS &&
+                       sb->slave_address != tas_priv->global_addr) {
+                       tas_priv->tasdevice[tas_priv->ndev].dev_addr =
+                               (unsigned int)sb->slave_address;
+                       tas_priv->ndev++;
+               }
+       }
+       return 1;
+}
+
+static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false };
+
+static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
+       { "speakerid-gpios", &speakerid_gpios, 1 },
+       { }
+};
+
+static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
+{
+       struct acpi_device *adev;
+       struct device *physdev;
+       LIST_HEAD(resources);
+       const char *sub;
+       uint32_t subid;
+       int ret;
+
+       adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
+       if (!adev) {
+               dev_err(p->dev,
+                       "Failed to find an ACPI device for %s\n", hid);
+               return -ENODEV;
+       }
+
+       physdev = get_device(acpi_get_first_physical_node(adev));
+       ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
+       if (ret < 0) {
+               dev_err(p->dev, "Failed to get ACPI resource.\n");
+               goto err;
+       }
+       sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
+       if (IS_ERR(sub)) {
+               /* No subsys id in older tas2563 projects. */
+               if (!strncmp(hid, "INT8866", sizeof("INT8866")))
+                       goto end_2563;
+               dev_err(p->dev, "Failed to get SUBSYS ID.\n");
+               ret = PTR_ERR(sub);
+               goto err;
+       }
+       /* Speaker id was needed for ASUS projects. */
+       ret = kstrtou32(sub, 16, &subid);
+       if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
+               ret = devm_acpi_dev_add_driver_gpios(p->dev,
+                       tas2781_speaker_id_gpios);
+               if (ret < 0)
+                       dev_err(p->dev, "Failed to add driver gpio %d.\n",
+                               ret);
+               p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);
+               if (IS_ERR(p->speaker_id)) {
+                       dev_err(p->dev, "Failed to get Speaker id.\n");
+                       ret = PTR_ERR(p->speaker_id);
+                       goto err;
+               }
+       } else {
+               p->speaker_id = NULL;
+       }
+
+end_2563:
+       acpi_dev_free_resource_list(&resources);
+       strscpy(p->dev_name, hid, sizeof(p->dev_name));
+       put_device(physdev);
+       acpi_dev_put(adev);
+
+       return 0;
+
+err:
+       dev_err(p->dev, "read acpi error, ret: %d\n", ret);
+       put_device(physdev);
+       acpi_dev_put(adev);
+
+       return ret;
+}
+
+static void tas2781_hda_playback_hook(struct device *dev, int action)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+       dev_dbg(tas_hda->dev, "%s: action = %d\n", __func__, action);
+       switch (action) {
+       case HDA_GEN_PCM_ACT_OPEN:
+               pm_runtime_get_sync(dev);
+               mutex_lock(&tas_hda->priv->codec_lock);
+               tasdevice_tuning_switch(tas_hda->priv, 0);
+               tas_hda->priv->playback_started = true;
+               mutex_unlock(&tas_hda->priv->codec_lock);
+               break;
+       case HDA_GEN_PCM_ACT_CLOSE:
+               mutex_lock(&tas_hda->priv->codec_lock);
+               tasdevice_tuning_switch(tas_hda->priv, 1);
+               tas_hda->priv->playback_started = false;
+               mutex_unlock(&tas_hda->priv->codec_lock);
+
+               pm_runtime_put_autosuspend(dev);
+               break;
+       default:
+               break;
+       }
+}
+
+static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int ret;
+
+       mutex_lock(&tas_priv->codec_lock);
+
+       ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n",
+               __func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
+
+       mutex_unlock(&tas_priv->codec_lock);
+
+       return ret;
+}
+
+static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+       int ret;
+
+       mutex_lock(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n",
+               __func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
+
+       /* The check of the given value is in tasdevice_amp_putvol. */
+       ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc);
+
+       mutex_unlock(&tas_priv->codec_lock);
+
+       return ret;
+}
+
+static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       mutex_lock(&tas_priv->codec_lock);
+
+       ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
+               __func__, kcontrol->id.name, tas_priv->force_fwload_status);
+
+       mutex_unlock(&tas_priv->codec_lock);
+
+       return 0;
+}
+
+static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       bool change, val = (bool)ucontrol->value.integer.value[0];
+
+       mutex_lock(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
+               __func__, kcontrol->id.name,
+               tas_priv->force_fwload_status, val);
+
+       if (tas_priv->force_fwload_status == val)
+               change = false;
+       else {
+               change = true;
+               tas_priv->force_fwload_status = val;
+       }
+
+       mutex_unlock(&tas_priv->codec_lock);
+
+       return change;
+}
+
+static const struct snd_kcontrol_new tas2781_snd_controls[] = {
+       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
+               1, 0, 20, 0, tas2781_amp_getvol,
+               tas2781_amp_putvol, amp_vol_tlv),
+       ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+               tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
+static const struct snd_kcontrol_new tas2781_prof_ctrl = {
+       .name = "Speaker Profile Id",
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .info = tasdevice_info_profile,
+       .get = tasdevice_get_profile_id,
+       .put = tasdevice_set_profile_id,
+};
+
+static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = {
+       .name = "Speaker Program Id",
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .info = tasdevice_info_programs,
+       .get = tasdevice_program_get,
+       .put = tasdevice_program_put,
+};
+
+static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = {
+       .name = "Speaker Config Id",
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .info = tasdevice_info_config,
+       .get = tasdevice_config_get,
+       .put = tasdevice_config_put,
+};
+
+static int tas2563_save_calibration(struct tas2781_hda *h)
+{
+       efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
+       char *vars[TASDEV_CALIB_N] = {
+               "R0_%d", "InvR0_%d", "R0_Low_%d", "Power_%d", "TLim_%d"
+       };
+       efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX];
+       unsigned long max_size = TAS2563_CAL_DATA_SIZE;
+       unsigned char var8[TAS2563_CAL_VAR_NAME_MAX];
+       struct tasdevice_priv *p = h->hda_priv;
+       struct calidata *cd = &p->cali_data;
+       struct cali_reg *r = &cd->cali_reg_array;
+       unsigned int offset = 0;
+       unsigned char *data;
+       efi_status_t status;
+       unsigned int attr;
+       int ret, i, j, k;
+
+       cd->cali_dat_sz_per_dev = TAS2563_CAL_DATA_SIZE * TASDEV_CALIB_N;
+
+       /* extra byte for each device is the device number */
+       cd->total_sz = (cd->cali_dat_sz_per_dev + 1) * p->ndev;
+       data = cd->data = devm_kzalloc(p->dev, cd->total_sz,
+               GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       for (i = 0; i < p->ndev; ++i) {
+               data[offset] = i;
+               offset++;
+               for (j = 0; j < TASDEV_CALIB_N; ++j) {
+                       ret = snprintf(var8, sizeof(var8), vars[j], i);
+
+                       if (ret < 0 || ret >= sizeof(var8) - 1) {
+                               dev_err(p->dev, "%s: Read %s failed\n",
+                                       __func__, var8);
+                               return -EINVAL;
+                       }
+                       /*
+                        * Our variable names are ASCII by construction, but
+                        * EFI names are wide chars.  Convert and zero-pad.
+                        */
+                       memset(efi_name, 0, sizeof(efi_name));
+                       for (k = 0; k < sizeof(var8) && var8[k]; k++)
+                               efi_name[k] = var8[k];
+                       status = efi.get_variable(efi_name,
+                               &efi_guid, &attr, &max_size,
+                               &data[offset]);
+                       if (status != EFI_SUCCESS ||
+                               max_size != TAS2563_CAL_DATA_SIZE) {
+                               dev_warn(p->dev,
+                                       "Dev %d: Caldat[%d] read failed %ld\n",
+                                       i, j, status);
+                               return -EINVAL;
+                       }
+                       offset += TAS2563_CAL_DATA_SIZE;
+               }
+       }
+
+       if (cd->total_sz != offset) {
+               dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) dismatch\n",
+                       __func__, cd->total_sz, offset);
+               return -EINVAL;
+       }
+
+       r->r0_reg = TAS2563_CAL_R0;
+       r->invr0_reg = TAS2563_CAL_INVR0;
+       r->r0_low_reg = TAS2563_CAL_R0_LOW;
+       r->pow_reg = TAS2563_CAL_POWER;
+       r->tlimit_reg = TAS2563_CAL_TLIM;
+
+       /*
+        * TAS2781_FMWLIB supports two solutions of calibrated data. One is
+        * from the driver itself: driver reads the calibrated files directly
+        * during probe; The other from user space: during init of audio hal,
+        * the audio hal will pass the calibrated data via kcontrol interface.
+        * Driver will store this data in "struct calidata" for use. For hda
+        * device, calibrated data are usunally saved into UEFI. So Hda side
+        * codec driver use the mixture of these two solutions, driver reads
+        * the data from UEFI, then store this data in "struct calidata" for
+        * use.
+        */
+       p->is_user_space_calidata = true;
+
+       return 0;
+}
+
+static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
+{
+       struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
+       struct hda_codec *codec = tas_hda->priv->codec;
+
+       snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
+       snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
+
+       for (int i = ARRAY_SIZE(hda_priv->snd_ctls) - 1; i >= 0; i--)
+               snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]);
+
+       snd_ctl_remove(codec->card, tas_hda->prof_ctl);
+}
+
+static void tasdev_fw_ready(const struct firmware *fmw, void *context)
+{
+       struct tasdevice_priv *tas_priv = context;
+       struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
+       struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
+       struct hda_codec *codec = tas_priv->codec;
+       int i, ret, spk_id;
+
+       pm_runtime_get_sync(tas_priv->dev);
+       mutex_lock(&tas_priv->codec_lock);
+
+       ret = tasdevice_rca_parser(tas_priv, fmw);
+       if (ret)
+               goto out;
+
+       tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl, tas_priv);
+       ret = snd_ctl_add(codec->card, tas_hda->prof_ctl);
+       if (ret) {
+               dev_err(tas_priv->dev,
+                       "Failed to add KControl %s = %d\n",
+                       tas2781_prof_ctrl.name, ret);
+               goto out;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) {
+               hda_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i],
+                       tas_priv);
+               ret = snd_ctl_add(codec->card, hda_priv->snd_ctls[i]);
+               if (ret) {
+                       dev_err(tas_priv->dev,
+                               "Failed to add KControl %s = %d\n",
+                               tas2781_snd_controls[i].name, ret);
+                       goto out;
+               }
+       }
+
+       tasdevice_dsp_remove(tas_priv);
+
+       tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+       if (tas_priv->speaker_id != NULL) {
+               // Speaker id need to be checked for ASUS only.
+               spk_id = gpiod_get_value(tas_priv->speaker_id);
+               if (spk_id < 0) {
+                       // Speaker id is not valid, use default.
+                       dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);
+                       spk_id = 0;
+               }
+               snprintf(tas_priv->coef_binaryname,
+                         sizeof(tas_priv->coef_binaryname),
+                         "TAS2XXX%04X%d.bin",
+                         lower_16_bits(codec->core.subsystem_id),
+                         spk_id);
+       } else {
+               snprintf(tas_priv->coef_binaryname,
+                         sizeof(tas_priv->coef_binaryname),
+                         "TAS2XXX%04X.bin",
+                         lower_16_bits(codec->core.subsystem_id));
+       }
+       ret = tasdevice_dsp_parser(tas_priv);
+       if (ret) {
+               dev_err(tas_priv->dev, "dspfw load %s error\n",
+                       tas_priv->coef_binaryname);
+               tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+               goto out;
+       }
+
+       tas_hda->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_prog_ctrl,
+               tas_priv);
+       ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl);
+       if (ret) {
+               dev_err(tas_priv->dev,
+                       "Failed to add KControl %s = %d\n",
+                       tas2781_dsp_prog_ctrl.name, ret);
+               goto out;
+       }
+
+       tas_hda->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_conf_ctrl,
+               tas_priv);
+       ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl);
+       if (ret) {
+               dev_err(tas_priv->dev,
+                       "Failed to add KControl %s = %d\n",
+                       tas2781_dsp_conf_ctrl.name, ret);
+               goto out;
+       }
+
+       tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+       tasdevice_prmg_load(tas_priv, 0);
+       if (tas_priv->fmw->nr_programs > 0)
+               tas_priv->cur_prog = 0;
+       if (tas_priv->fmw->nr_configurations > 0)
+               tas_priv->cur_conf = 0;
+
+       /* If calibrated data occurs error, dsp will still works with default
+        * calibrated data inside algo.
+        */
+       hda_priv->save_calibration(tas_hda);
+
+       tasdevice_tuning_switch(tas_hda->priv, 0);
+       tas_hda->priv->playback_started = true;
+
+out:
+       mutex_unlock(&tas_hda->priv->codec_lock);
+       release_firmware(fmw);
+       pm_runtime_put_autosuspend(tas_hda->dev);
+}
+
+static int tas2781_hda_bind(struct device *dev, struct device *master,
+       void *master_data)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct hda_component_parent *parent = master_data;
+       struct hda_component *comp;
+       struct hda_codec *codec;
+       unsigned int subid;
+       int ret;
+
+       comp = hda_component_from_index(parent, tas_hda->priv->index);
+       if (!comp)
+               return -EINVAL;
+
+       if (comp->dev)
+               return -EBUSY;
+
+       codec = parent->codec;
+       subid = codec->core.subsystem_id >> 16;
+
+       switch (subid) {
+       case 0x1028:
+               tas_hda->catlog_id = DELL;
+               break;
+       default:
+               tas_hda->catlog_id = LENOVO;
+               break;
+       }
+
+       pm_runtime_get_sync(dev);
+
+       comp->dev = dev;
+
+       strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+
+       ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready);
+       if (!ret)
+               comp->playback_hook = tas2781_hda_playback_hook;
+
+       pm_runtime_put_autosuspend(dev);
+
+       return ret;
+}
+
+static void tas2781_hda_unbind(struct device *dev,
+       struct device *master, void *master_data)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct hda_component_parent *parent = master_data;
+       struct hda_component *comp;
+
+       comp = hda_component_from_index(parent, tas_hda->priv->index);
+       if (comp && (comp->dev == dev)) {
+               comp->dev = NULL;
+               memset(comp->name, 0, sizeof(comp->name));
+               comp->playback_hook = NULL;
+       }
+
+       tas2781_hda_remove_controls(tas_hda);
+
+       tasdevice_config_info_remove(tas_hda->priv);
+       tasdevice_dsp_remove(tas_hda->priv);
+
+       tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+}
+
+static const struct component_ops tas2781_hda_comp_ops = {
+       .bind = tas2781_hda_bind,
+       .unbind = tas2781_hda_unbind,
+};
+
+static int tas2781_hda_i2c_probe(struct i2c_client *clt)
+{
+       struct tas2781_hda_i2c_priv *hda_priv;
+       struct tas2781_hda *tas_hda;
+       const char *device_name;
+       int ret;
+
+       tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL);
+       if (!tas_hda)
+               return -ENOMEM;
+
+       hda_priv = devm_kzalloc(&clt->dev, sizeof(*hda_priv), GFP_KERNEL);
+       if (!hda_priv)
+               return -ENOMEM;
+
+       tas_hda->hda_priv = hda_priv;
+
+       dev_set_drvdata(&clt->dev, tas_hda);
+       tas_hda->dev = &clt->dev;
+
+       tas_hda->priv = tasdevice_kzalloc(clt);
+       if (!tas_hda->priv)
+               return -ENOMEM;
+
+       if (strstr(dev_name(&clt->dev), "TIAS2781")) {
+               device_name = "TIAS2781";
+               hda_priv->save_calibration = tas2781_save_calibration;
+               tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
+       } else if (strstarts(dev_name(&clt->dev),
+                            "i2c-TXNW2781:00-tas2781-hda.0")) {
+               device_name = "TXNW2781";
+               hda_priv->save_calibration = tas2781_save_calibration;
+               tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
+       } else if (strstr(dev_name(&clt->dev), "INT8866")) {
+               device_name = "INT8866";
+               hda_priv->save_calibration = tas2563_save_calibration;
+               tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
+       } else {
+               return -ENODEV;
+       }
+
+       tas_hda->priv->irq = clt->irq;
+       ret = tas2781_read_acpi(tas_hda->priv, device_name);
+       if (ret)
+               return dev_err_probe(tas_hda->dev, ret,
+                       "Platform not supported\n");
+
+       ret = tasdevice_init(tas_hda->priv);
+       if (ret)
+               goto err;
+
+       pm_runtime_set_autosuspend_delay(tas_hda->dev, 3000);
+       pm_runtime_use_autosuspend(tas_hda->dev);
+       pm_runtime_mark_last_busy(tas_hda->dev);
+       pm_runtime_set_active(tas_hda->dev);
+       pm_runtime_enable(tas_hda->dev);
+
+       tasdevice_reset(tas_hda->priv);
+
+       ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops);
+       if (ret) {
+               dev_err(tas_hda->dev, "Register component failed: %d\n", ret);
+               pm_runtime_disable(tas_hda->dev);
+       }
+
+err:
+       if (ret)
+               tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
+       return ret;
+}
+
+static void tas2781_hda_i2c_remove(struct i2c_client *clt)
+{
+       tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
+}
+
+static int tas2781_runtime_suspend(struct device *dev)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+       dev_dbg(tas_hda->dev, "Runtime Suspend\n");
+
+       mutex_lock(&tas_hda->priv->codec_lock);
+
+       /* The driver powers up the amplifiers at module load time.
+        * Stop the playback if it's unused.
+        */
+       if (tas_hda->priv->playback_started) {
+               tasdevice_tuning_switch(tas_hda->priv, 1);
+               tas_hda->priv->playback_started = false;
+       }
+
+       mutex_unlock(&tas_hda->priv->codec_lock);
+
+       return 0;
+}
+
+static int tas2781_runtime_resume(struct device *dev)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+       dev_dbg(tas_hda->dev, "Runtime Resume\n");
+
+       mutex_lock(&tas_hda->priv->codec_lock);
+
+       tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
+
+       mutex_unlock(&tas_hda->priv->codec_lock);
+
+       return 0;
+}
+
+static int tas2781_system_suspend(struct device *dev)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+       dev_dbg(tas_hda->priv->dev, "System Suspend\n");
+
+       mutex_lock(&tas_hda->priv->codec_lock);
+
+       /* Shutdown chip before system suspend */
+       if (tas_hda->priv->playback_started)
+               tasdevice_tuning_switch(tas_hda->priv, 1);
+
+       mutex_unlock(&tas_hda->priv->codec_lock);
+
+       /*
+        * Reset GPIO may be shared, so cannot reset here.
+        * However beyond this point, amps may be powered down.
+        */
+       return 0;
+}
+
+static int tas2781_system_resume(struct device *dev)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       int i;
+
+       dev_dbg(tas_hda->priv->dev, "System Resume\n");
+
+       mutex_lock(&tas_hda->priv->codec_lock);
+
+       for (i = 0; i < tas_hda->priv->ndev; i++) {
+               tas_hda->priv->tasdevice[i].cur_book = -1;
+               tas_hda->priv->tasdevice[i].cur_prog = -1;
+               tas_hda->priv->tasdevice[i].cur_conf = -1;
+       }
+       tasdevice_reset(tas_hda->priv);
+       tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
+
+       if (tas_hda->priv->playback_started)
+               tasdevice_tuning_switch(tas_hda->priv, 0);
+
+       mutex_unlock(&tas_hda->priv->codec_lock);
+
+       return 0;
+}
+
+static const struct dev_pm_ops tas2781_hda_pm_ops = {
+       RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume)
+};
+
+static const struct i2c_device_id tas2781_hda_i2c_id[] = {
+       { "tas2781-hda" },
+       {}
+};
+
+static const struct acpi_device_id tas2781_acpi_hda_match[] = {
+       {"INT8866", 0 },
+       {"TIAS2781", 0 },
+       {"TXNW2781", 0 },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
+
+static struct i2c_driver tas2781_hda_i2c_driver = {
+       .driver = {
+               .name           = "tas2781-hda",
+               .acpi_match_table = tas2781_acpi_hda_match,
+               .pm             = &tas2781_hda_pm_ops,
+       },
+       .id_table       = tas2781_hda_i2c_id,
+       .probe          = tas2781_hda_i2c_probe,
+       .remove         = tas2781_hda_i2c_remove,
+};
+module_i2c_driver(tas2781_hda_i2c_driver);
+
+MODULE_DESCRIPTION("TAS2781 HDA Driver");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
diff --git a/sound/hda/codecs/side-codecs/tas2781_hda_spi.c b/sound/hda/codecs/side-codecs/tas2781_hda_spi.c
new file mode 100644 (file)
index 0000000..09a5d0f
--- /dev/null
@@ -0,0 +1,954 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2781 HDA SPI driver
+//
+// Copyright 2024 - 2025 Texas Instruments, Inc.
+//
+// Author: Baojun Xu <baojun.xu@ti.com>
+
+#include <linux/acpi.h>
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/cleanup.h>
+#include <linux/crc8.h>
+#include <linux/crc32.h>
+#include <linux/efi.h>
+#include <linux/firmware.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <sound/hda_codec.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+#include <sound/tlv.h>
+#include <sound/tas2781-tlv.h>
+
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_component.h"
+#include "hda_jack.h"
+#include "../generic.h"
+#include "tas2781_hda.h"
+
+#define TASDEVICE_RANGE_MAX_SIZE       (256 * 128)
+#define TASDEVICE_WIN_LEN              128
+#define TAS2781_SPI_MAX_FREQ           (4 * HZ_PER_MHZ)
+/* Flag of calibration registers address. */
+#define TASDEVICE_CALIBRATION_REG_ADDRESS      BIT(7)
+#define TASDEV_UEFI_CALI_REG_ADDR_FLG  BIT(7)
+
+/* System Reset Check Register */
+#define TAS2781_REG_CLK_CONFIG         TASDEVICE_REG(0x0, 0x0, 0x5c)
+#define TAS2781_REG_CLK_CONFIG_RESET   0x19
+
+struct tas2781_hda_spi_priv {
+       struct snd_kcontrol *snd_ctls[3];
+};
+
+static const struct regmap_range_cfg tasdevice_ranges[] = {
+       {
+               .range_min = 0,
+               .range_max = TASDEVICE_RANGE_MAX_SIZE,
+               .selector_reg = TASDEVICE_PAGE_SELECT,
+               .selector_mask = GENMASK(7, 0),
+               .selector_shift = 0,
+               .window_start = 0,
+               .window_len = TASDEVICE_WIN_LEN,
+       },
+};
+
+static const struct regmap_config tasdevice_regmap = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .zero_flag_mask = true,
+       .read_flag_mask = 0x01,
+       .reg_shift = -1,
+       .cache_type = REGCACHE_NONE,
+       .ranges = tasdevice_ranges,
+       .num_ranges = ARRAY_SIZE(tasdevice_ranges),
+       .max_register = TASDEVICE_RANGE_MAX_SIZE,
+};
+
+static int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
+       unsigned short chn, unsigned int reg, unsigned int *val)
+{
+       int ret;
+
+       /*
+        * In our TAS2781 SPI mode, if read from other book (not book 0),
+        * or read from page number larger than 1 in book 0, one more byte
+        * read is needed, and first byte is a dummy byte, need to be ignored.
+        */
+       if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
+               unsigned char data[2];
+
+               ret = tasdevice_dev_bulk_read(tas_priv, chn, reg,
+                       data, sizeof(data));
+               *val = data[1];
+       } else {
+               ret = tasdevice_dev_read(tas_priv, chn, reg, val);
+       }
+       if (ret < 0)
+               dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+       return ret;
+}
+
+static int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
+       unsigned short chn, unsigned int reg, unsigned char *data,
+       unsigned int len)
+{
+       int ret;
+
+       /*
+        * In our TAS2781 SPI mode, if read from other book (not book 0),
+        * or read from page number larger than 1 in book 0, one more byte
+        * read is needed, and first byte is a dummy byte, need to be ignored.
+        */
+       if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
+               unsigned char buf[TASDEVICE_WIN_LEN + 1];
+
+               ret = tasdevice_dev_bulk_read(tas_priv, chn, reg,
+                       buf, len + 1);
+               memcpy(data, buf + 1, len);
+       } else {
+               ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, data, len);
+       }
+       if (ret < 0)
+               dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+       return ret;
+}
+
+static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,
+       unsigned short chn, unsigned int reg, unsigned int mask,
+       unsigned int value)
+{
+       int ret, val;
+
+       /*
+        * In our TAS2781 SPI mode, read/write was masked in last bit of
+        * address, it cause regmap_update_bits() not work as expected.
+        */
+       ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
+       if (ret < 0) {
+               dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+               return ret;
+       }
+
+       ret = tasdevice_dev_write(tas_priv, chn, TASDEVICE_PAGE_REG(reg),
+               (val & ~mask) | (mask & value));
+       if (ret < 0)
+               dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
+
+       return ret;
+}
+
+static int tasdevice_spi_change_chn_book(struct tasdevice_priv *p,
+       unsigned short chn, int book)
+{
+       int ret = 0;
+
+       if (chn == p->index) {
+               struct tasdevice *tasdev = &p->tasdevice[chn];
+               struct regmap *map = p->regmap;
+
+               if (tasdev->cur_book != book) {
+                       ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book);
+                       if (ret < 0)
+                               dev_err(p->dev, "%s, E=%d\n", __func__, ret);
+                       else
+                               tasdev->cur_book = book;
+               }
+       } else {
+               ret = -EXDEV;
+               dev_dbg(p->dev, "Not error, %s ignore channel(%d)\n",
+                       __func__, chn);
+       }
+
+       return ret;
+}
+
+static void tas2781_spi_reset(struct tasdevice_priv *tas_dev)
+{
+       int ret;
+
+       if (tas_dev->reset) {
+               gpiod_set_value_cansleep(tas_dev->reset, 0);
+               fsleep(800);
+               gpiod_set_value_cansleep(tas_dev->reset, 1);
+       } else {
+               ret = tasdevice_dev_write(tas_dev, tas_dev->index,
+                       TASDEVICE_REG_SWRESET, TASDEVICE_REG_SWRESET_RESET);
+               if (ret < 0) {
+                       dev_err(tas_dev->dev, "dev sw-reset fail, %d\n", ret);
+                       return;
+               }
+               fsleep(1000);
+       }
+}
+
+static int tascodec_spi_init(struct tasdevice_priv *tas_priv,
+       void *codec, struct module *module,
+       void (*cont)(const struct firmware *fw, void *context))
+{
+       int ret;
+
+       /*
+        * Codec Lock Hold to ensure that codec_probe and firmware parsing and
+        * loading do not simultaneously execute.
+        */
+       guard(mutex)(&tas_priv->codec_lock);
+
+       scnprintf(tas_priv->rca_binaryname,
+               sizeof(tas_priv->rca_binaryname), "%sRCA%d.bin",
+               tas_priv->dev_name, tas_priv->ndev);
+       crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
+       tas_priv->codec = codec;
+       ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
+               tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv,
+               cont);
+       if (ret)
+               dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n",
+                       ret);
+
+       return ret;
+}
+
+static void tasdevice_spi_init(struct tasdevice_priv *tas_priv)
+{
+       tas_priv->tasdevice[tas_priv->index].cur_book = -1;
+       tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
+       tas_priv->tasdevice[tas_priv->index].cur_prog = -1;
+
+       tas_priv->isspi = true;
+
+       tas_priv->update_bits = tasdevice_spi_dev_update_bits;
+       tas_priv->change_chn_book = tasdevice_spi_change_chn_book;
+       tas_priv->dev_read = tasdevice_spi_dev_read;
+       tas_priv->dev_bulk_read = tasdevice_spi_dev_bulk_read;
+
+       mutex_init(&tas_priv->codec_lock);
+}
+
+static int tasdevice_spi_amp_putvol(struct tasdevice_priv *tas_priv,
+       struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+       unsigned int invert = mc->invert;
+       unsigned char mask;
+       int max = mc->max;
+       int val, ret;
+
+       mask = rounddown_pow_of_two(max);
+       mask <<= mc->shift;
+       val =  clamp(invert ? max - ucontrol->value.integer.value[0] :
+               ucontrol->value.integer.value[0], 0, max);
+
+       ret = tasdevice_spi_dev_update_bits(tas_priv, tas_priv->index,
+               mc->reg, mask, (unsigned int)(val << mc->shift));
+       if (ret)
+               dev_err(tas_priv->dev, "set AMP vol error in dev %d\n",
+                       tas_priv->index);
+
+       return ret;
+}
+
+static int tasdevice_spi_amp_getvol(struct tasdevice_priv *tas_priv,
+       struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+       unsigned int invert = mc->invert;
+       unsigned char mask = 0;
+       int max = mc->max;
+       int ret, val;
+
+       ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index, mc->reg, &val);
+       if (ret) {
+               dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__);
+               return ret;
+       }
+
+       mask = rounddown_pow_of_two(max);
+       mask <<= mc->shift;
+       val = (val & mask) >> mc->shift;
+       val = clamp(invert ? max - val : val, 0, max);
+       ucontrol->value.integer.value[0] = val;
+
+       return ret;
+}
+
+static int tasdevice_spi_digital_putvol(struct tasdevice_priv *p,
+       struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+       unsigned int invert = mc->invert;
+       int max = mc->max;
+       int val, ret;
+
+       val = clamp(invert ? max - ucontrol->value.integer.value[0] :
+               ucontrol->value.integer.value[0], 0, max);
+       ret = tasdevice_dev_write(p, p->index, mc->reg, (unsigned int)val);
+       if (ret)
+               dev_err(p->dev, "set digital vol err in dev %d\n", p->index);
+
+       return ret;
+}
+
+static int tasdevice_spi_digital_getvol(struct tasdevice_priv *p,
+       struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
+{
+       unsigned int invert = mc->invert;
+       int max = mc->max;
+       int ret, val;
+
+       ret = tasdevice_spi_dev_read(p, p->index, mc->reg, &val);
+       if (ret) {
+               dev_err(p->dev, "%s, get digital vol err\n", __func__);
+               return ret;
+       }
+
+       val = clamp(invert ? max - val : val, 0, max);
+       ucontrol->value.integer.value[0] = val;
+
+       return ret;
+}
+
+static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
+       const char *hid, int id)
+{
+       struct tasdevice_priv *p = tas_hda->priv;
+       struct acpi_device *adev;
+       struct device *physdev;
+       u32 values[HDA_MAX_COMPONENTS];
+       const char *property;
+       size_t nval;
+       int ret, i;
+
+       adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
+       if (!adev) {
+               dev_err(p->dev, "Failed to find ACPI device: %s\n", hid);
+               return -ENODEV;
+       }
+
+       strscpy(p->dev_name, hid, sizeof(p->dev_name));
+       physdev = get_device(acpi_get_first_physical_node(adev));
+       acpi_dev_put(adev);
+
+       property = "ti,dev-index";
+       ret = device_property_count_u32(physdev, property);
+       if (ret <= 0 || ret > ARRAY_SIZE(values)) {
+               ret = -EINVAL;
+               goto err;
+       }
+       p->ndev = nval = ret;
+
+       ret = device_property_read_u32_array(physdev, property, values, nval);
+       if (ret)
+               goto err;
+
+       p->index = U8_MAX;
+       for (i = 0; i < nval; i++) {
+               if (values[i] == id) {
+                       p->index = i;
+                       break;
+               }
+       }
+       if (p->index == U8_MAX) {
+               dev_dbg(p->dev, "No index found in %s\n", property);
+               ret = -ENODEV;
+               goto err;
+       }
+
+       if (p->index == 0) {
+               /* All of amps share same RESET pin. */
+               p->reset = devm_gpiod_get_index_optional(physdev, "reset",
+                       p->index, GPIOD_OUT_LOW);
+               if (IS_ERR(p->reset)) {
+                       ret = PTR_ERR(p->reset);
+                       dev_err_probe(p->dev, ret, "Failed on reset GPIO\n");
+                       goto err;
+               }
+       }
+       put_device(physdev);
+
+       return 0;
+err:
+       dev_err(p->dev, "read acpi error, ret: %d\n", ret);
+       put_device(physdev);
+       acpi_dev_put(adev);
+
+       return ret;
+}
+
+static void tas2781_hda_playback_hook(struct device *dev, int action)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct tasdevice_priv *tas_priv = tas_hda->priv;
+
+       if (action == HDA_GEN_PCM_ACT_OPEN) {
+               pm_runtime_get_sync(dev);
+               guard(mutex)(&tas_priv->codec_lock);
+               if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)
+                       tasdevice_tuning_switch(tas_hda->priv, 0);
+       } else if (action == HDA_GEN_PCM_ACT_CLOSE) {
+               guard(mutex)(&tas_priv->codec_lock);
+               if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)
+                       tasdevice_tuning_switch(tas_priv, 1);
+               pm_runtime_put_autosuspend(dev);
+       }
+}
+
+/*
+ * tas2781_digital_getvol - get the volum control
+ * @kcontrol: control pointer
+ * @ucontrol: User data
+ *
+ * Customer Kcontrol for tas2781 is primarily for regmap booking, paging
+ * depends on internal regmap mechanism.
+ * tas2781 contains book and page two-level register map, especially
+ * book switching will set the register BXXP00R7F, after switching to the
+ * correct book, then leverage the mechanism for paging to access the
+ * register.
+ *
+ * Return 0 if succeeded.
+ */
+static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+
+       guard(mutex)(&tas_priv->codec_lock);
+       return tasdevice_spi_digital_getvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+
+       guard(mutex)(&tas_priv->codec_lock);
+       return tasdevice_spi_amp_getvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+
+       guard(mutex)(&tas_priv->codec_lock);
+       return tasdevice_spi_digital_putvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct soc_mixer_control *mc =
+               (struct soc_mixer_control *)kcontrol->private_value;
+
+       guard(mutex)(&tas_priv->codec_lock);
+       return tasdevice_spi_amp_putvol(tas_priv, ucontrol, mc);
+}
+
+static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
+       dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
+               str_on_off(tas_priv->force_fwload_status));
+
+       return 0;
+}
+
+static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       bool change, val = (bool)ucontrol->value.integer.value[0];
+
+       if (tas_priv->force_fwload_status == val) {
+               change = false;
+       } else {
+               change = true;
+               tas_priv->force_fwload_status = val;
+       }
+       dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
+               str_on_off(tas_priv->force_fwload_status));
+
+       return change;
+}
+
+static struct snd_kcontrol_new tas2781_snd_ctls[] = {
+       ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_AMP_LEVEL, 1, 0, 20, 0,
+               tas2781_amp_getvol, tas2781_amp_putvol, amp_vol_tlv),
+       ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_DVC_LVL, 0, 0, 200, 1,
+               tas2781_digital_getvol, tas2781_digital_putvol, dvc_tlv),
+       ACARD_SINGLE_BOOL_EXT(NULL, 0, tas2781_force_fwload_get,
+               tas2781_force_fwload_put),
+};
+
+static struct snd_kcontrol_new tas2781_prof_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .info = tasdevice_info_profile,
+       .get = tasdevice_get_profile_id,
+       .put = tasdevice_set_profile_id,
+};
+
+static struct snd_kcontrol_new tas2781_dsp_ctls[] = {
+       /* Speaker Program */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = tasdevice_info_programs,
+               .get = tasdevice_program_get,
+               .put = tasdevice_program_put,
+       },
+       /* Speaker Config */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = tasdevice_info_config,
+               .get = tasdevice_config_get,
+               .put = tasdevice_config_put,
+       },
+};
+
+static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
+{
+       struct hda_codec *codec = tas_hda->priv->codec;
+       struct tas2781_hda_spi_priv *h_priv = tas_hda->hda_priv;
+
+       snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
+
+       snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
+
+       for (int i = ARRAY_SIZE(h_priv->snd_ctls) - 1; i >= 0; i--)
+               snd_ctl_remove(codec->card, h_priv->snd_ctls[i]);
+
+       snd_ctl_remove(codec->card, tas_hda->prof_ctl);
+}
+
+static int tas2781_hda_spi_prf_ctl(struct tas2781_hda *h)
+{
+       struct tasdevice_priv *p = h->priv;
+       struct hda_codec *c = p->codec;
+       char name[64];
+       int rc;
+
+       snprintf(name, sizeof(name), "Speaker-%d Profile Id", p->index);
+       tas2781_prof_ctl.name = name;
+       h->prof_ctl = snd_ctl_new1(&tas2781_prof_ctl, p);
+       rc = snd_ctl_add(c->card, h->prof_ctl);
+       if (rc)
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_prof_ctl.name, rc);
+       return rc;
+}
+
+static int tas2781_hda_spi_snd_ctls(struct tas2781_hda *h)
+{
+       struct tas2781_hda_spi_priv *h_priv = h->hda_priv;
+       struct tasdevice_priv *p = h->priv;
+       struct hda_codec *c = p->codec;
+       char name[64];
+       int i = 0;
+       int rc;
+
+       snprintf(name, sizeof(name), "Speaker-%d Analog Volume", p->index);
+       tas2781_snd_ctls[i].name = name;
+       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_snd_ctls[i].name, rc);
+               return rc;
+       }
+       i++;
+       snprintf(name, sizeof(name), "Speaker-%d Digital Volume", p->index);
+       tas2781_snd_ctls[i].name = name;
+       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_snd_ctls[i].name, rc);
+               return rc;
+       }
+       i++;
+       snprintf(name, sizeof(name), "Froce Speaker-%d FW Load", p->index);
+       tas2781_snd_ctls[i].name = name;
+       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_snd_ctls[i].name, rc);
+       }
+       return rc;
+}
+
+static int tas2781_hda_spi_dsp_ctls(struct tas2781_hda *h)
+{
+       struct tasdevice_priv *p = h->priv;
+       struct hda_codec *c = p->codec;
+       char name[64];
+       int i = 0;
+       int rc;
+
+       snprintf(name, sizeof(name), "Speaker-%d Program Id", p->index);
+       tas2781_dsp_ctls[i].name = name;
+       h->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
+       rc = snd_ctl_add(c->card, h->dsp_prog_ctl);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_dsp_ctls[i].name, rc);
+               return rc;
+       }
+       i++;
+       snprintf(name, sizeof(name), "Speaker-%d Config Id", p->index);
+       tas2781_dsp_ctls[i].name = name;
+       h->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
+       rc = snd_ctl_add(c->card, h->dsp_conf_ctl);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_dsp_ctls[i].name, rc);
+       }
+
+       return rc;
+}
+
+static void tasdev_fw_ready(const struct firmware *fmw, void *context)
+{
+       struct tasdevice_priv *tas_priv = context;
+       struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
+       struct hda_codec *codec = tas_priv->codec;
+       int ret, val;
+
+       pm_runtime_get_sync(tas_priv->dev);
+       guard(mutex)(&tas_priv->codec_lock);
+
+       ret = tasdevice_rca_parser(tas_priv, fmw);
+       if (ret)
+               goto out;
+
+       /* Add control one time only. */
+       ret = tas2781_hda_spi_prf_ctl(tas_hda);
+       if (ret)
+               goto out;
+
+       ret = tas2781_hda_spi_snd_ctls(tas_hda);
+       if (ret)
+               goto out;
+
+       tasdevice_dsp_remove(tas_priv);
+
+       tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+       scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X-%01d.bin",
+               lower_16_bits(codec->core.subsystem_id), tas_priv->index);
+       ret = tasdevice_dsp_parser(tas_priv);
+       if (ret) {
+               dev_err(tas_priv->dev, "dspfw load %s error\n",
+                       tas_priv->coef_binaryname);
+               tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
+               goto out;
+       }
+
+       ret = tas2781_hda_spi_dsp_ctls(tas_hda);
+       if (ret)
+               goto out;
+       /* Perform AMP reset before firmware download. */
+       tas2781_spi_reset(tas_priv);
+       tas_priv->rcabin.profile_cfg_id = 0;
+
+       tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+       ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index,
+               TAS2781_REG_CLK_CONFIG, &val);
+       if (ret < 0)
+               goto out;
+
+       if (val == TAS2781_REG_CLK_CONFIG_RESET) {
+               ret = tasdevice_prmg_load(tas_priv, 0);
+               if (ret < 0) {
+                       dev_err(tas_priv->dev, "FW download failed = %d\n",
+                               ret);
+                       goto out;
+               }
+               tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+       }
+       if (tas_priv->fmw->nr_programs > 0)
+               tas_priv->tasdevice[tas_priv->index].cur_prog = 0;
+       if (tas_priv->fmw->nr_configurations > 0)
+               tas_priv->tasdevice[tas_priv->index].cur_conf = 0;
+
+       /*
+        * If calibrated data occurs error, dsp will still works with default
+        * calibrated data inside algo.
+        */
+       tas2781_save_calibration(tas_hda);
+out:
+       release_firmware(fmw);
+       pm_runtime_put_autosuspend(tas_hda->priv->dev);
+}
+
+static int tas2781_hda_bind(struct device *dev, struct device *master,
+       void *master_data)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct hda_component_parent *parent = master_data;
+       struct hda_component *comp;
+       struct hda_codec *codec;
+       int ret;
+
+       comp = hda_component_from_index(parent, tas_hda->priv->index);
+       if (!comp)
+               return -EINVAL;
+
+       if (comp->dev)
+               return -EBUSY;
+
+       codec = parent->codec;
+
+       pm_runtime_get_sync(dev);
+
+       comp->dev = dev;
+
+       strscpy(comp->name, dev_name(dev), sizeof(comp->name));
+
+       ret = tascodec_spi_init(tas_hda->priv, codec, THIS_MODULE,
+               tasdev_fw_ready);
+       if (!ret)
+               comp->playback_hook = tas2781_hda_playback_hook;
+
+       pm_runtime_put_autosuspend(dev);
+
+       return ret;
+}
+
+static void tas2781_hda_unbind(struct device *dev, struct device *master,
+                              void *master_data)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct hda_component_parent *parent = master_data;
+       struct tasdevice_priv *tas_priv = tas_hda->priv;
+       struct hda_component *comp;
+
+       comp = hda_component_from_index(parent, tas_priv->index);
+       if (comp && (comp->dev == dev)) {
+               comp->dev = NULL;
+               memset(comp->name, 0, sizeof(comp->name));
+               comp->playback_hook = NULL;
+       }
+
+       tas2781_hda_remove_controls(tas_hda);
+
+       tasdevice_config_info_remove(tas_priv);
+       tasdevice_dsp_remove(tas_priv);
+
+       tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING;
+}
+
+static const struct component_ops tas2781_hda_comp_ops = {
+       .bind = tas2781_hda_bind,
+       .unbind = tas2781_hda_unbind,
+};
+
+static int tas2781_hda_spi_probe(struct spi_device *spi)
+{
+       struct tas2781_hda_spi_priv *hda_priv;
+       struct tasdevice_priv *tas_priv;
+       struct tas2781_hda *tas_hda;
+       const char *device_name;
+       int ret = 0;
+
+       tas_hda = devm_kzalloc(&spi->dev, sizeof(*tas_hda), GFP_KERNEL);
+       if (!tas_hda)
+               return -ENOMEM;
+
+       hda_priv = devm_kzalloc(&spi->dev, sizeof(*hda_priv), GFP_KERNEL);
+       if (!hda_priv)
+               return -ENOMEM;
+
+       tas_hda->hda_priv = hda_priv;
+       spi->max_speed_hz = TAS2781_SPI_MAX_FREQ;
+
+       tas_priv = devm_kzalloc(&spi->dev, sizeof(*tas_priv), GFP_KERNEL);
+       if (!tas_priv)
+               return -ENOMEM;
+       tas_priv->dev = &spi->dev;
+       tas_hda->priv = tas_priv;
+       tas_priv->regmap = devm_regmap_init_spi(spi, &tasdevice_regmap);
+       if (IS_ERR(tas_priv->regmap)) {
+               ret = PTR_ERR(tas_priv->regmap);
+               dev_err(tas_priv->dev, "Failed to allocate regmap: %d\n",
+                       ret);
+               return ret;
+       }
+       if (strstr(dev_name(&spi->dev), "TXNW2781")) {
+               device_name = "TXNW2781";
+       } else {
+               dev_err(tas_priv->dev, "Unmatched spi dev %s\n",
+                       dev_name(&spi->dev));
+               return -ENODEV;
+       }
+
+       tas_priv->irq = spi->irq;
+       dev_set_drvdata(&spi->dev, tas_hda);
+       ret = tas2781_read_acpi(tas_hda, device_name,
+                               spi_get_chipselect(spi, 0));
+       if (ret)
+               return dev_err_probe(tas_priv->dev, ret,
+                               "Platform not supported\n");
+
+       tasdevice_spi_init(tas_priv);
+
+       pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000);
+       pm_runtime_use_autosuspend(tas_priv->dev);
+       pm_runtime_set_active(tas_priv->dev);
+       pm_runtime_get_noresume(tas_priv->dev);
+       pm_runtime_enable(tas_priv->dev);
+
+       pm_runtime_put_autosuspend(tas_priv->dev);
+
+       ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
+       if (ret) {
+               dev_err(tas_priv->dev, "Register component fail: %d\n", ret);
+               pm_runtime_disable(tas_priv->dev);
+               tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
+       }
+
+       return ret;
+}
+
+static void tas2781_hda_spi_remove(struct spi_device *spi)
+{
+       tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
+}
+
+static int tas2781_runtime_suspend(struct device *dev)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct tasdevice_priv *tas_priv = tas_hda->priv;
+
+       guard(mutex)(&tas_priv->codec_lock);
+
+       if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
+               && tas_priv->playback_started)
+               tasdevice_tuning_switch(tas_priv, 1);
+
+       tas_priv->tasdevice[tas_priv->index].cur_book = -1;
+       tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
+
+       return 0;
+}
+
+static int tas2781_runtime_resume(struct device *dev)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct tasdevice_priv *tas_priv = tas_hda->priv;
+
+       guard(mutex)(&tas_priv->codec_lock);
+
+       if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
+               && tas_priv->playback_started)
+               tasdevice_tuning_switch(tas_priv, 0);
+
+       return 0;
+}
+
+static int tas2781_system_suspend(struct device *dev)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct tasdevice_priv *tas_priv = tas_hda->priv;
+       int ret;
+
+       ret = pm_runtime_force_suspend(dev);
+       if (ret)
+               return ret;
+
+       /* Shutdown chip before system suspend */
+       if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
+               && tas_priv->playback_started)
+               tasdevice_tuning_switch(tas_priv, 1);
+
+       return 0;
+}
+
+static int tas2781_system_resume(struct device *dev)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+       struct tasdevice_priv *tas_priv = tas_hda->priv;
+       int ret, val;
+
+       ret = pm_runtime_force_resume(dev);
+       if (ret)
+               return ret;
+
+       guard(mutex)(&tas_priv->codec_lock);
+       ret = tas_priv->dev_read(tas_priv, tas_priv->index,
+               TAS2781_REG_CLK_CONFIG, &val);
+       if (ret < 0)
+               return ret;
+
+       if (val == TAS2781_REG_CLK_CONFIG_RESET) {
+               tas_priv->tasdevice[tas_priv->index].cur_book = -1;
+               tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
+               tas_priv->tasdevice[tas_priv->index].cur_prog = -1;
+
+               ret = tasdevice_prmg_load(tas_priv, 0);
+               if (ret < 0) {
+                       dev_err(tas_priv->dev,
+                               "FW download failed = %d\n", ret);
+                       return ret;
+               }
+               tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
+
+               if (tas_priv->playback_started)
+                       tasdevice_tuning_switch(tas_priv, 0);
+       }
+
+       return ret;
+}
+
+static const struct dev_pm_ops tas2781_hda_pm_ops = {
+       RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL)
+       SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume)
+};
+
+static const struct spi_device_id tas2781_hda_spi_id[] = {
+       { "tas2781-hda", },
+       {}
+};
+
+static const struct acpi_device_id tas2781_acpi_hda_match[] = {
+       {"TXNW2781", },
+       {}
+};
+MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
+
+static struct spi_driver tas2781_hda_spi_driver = {
+       .driver = {
+               .name           = "tas2781-hda",
+               .acpi_match_table = tas2781_acpi_hda_match,
+               .pm             = &tas2781_hda_pm_ops,
+       },
+       .id_table       = tas2781_hda_spi_id,
+       .probe          = tas2781_hda_spi_probe,
+       .remove         = tas2781_hda_spi_remove,
+};
+module_spi_driver(tas2781_hda_spi_driver);
+
+MODULE_DESCRIPTION("TAS2781 HDA SPI Driver");
+MODULE_AUTHOR("Baojun, Xu, <baojun.xug@ti.com>");
+MODULE_LICENSE("GPL");
+MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
diff --git a/sound/hda/codecs/sigmatel.c b/sound/hda/codecs/sigmatel.c
new file mode 100644 (file)
index 0000000..56274ff
--- /dev/null
@@ -0,0 +1,5161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for SigmaTel STAC92xx
+ *
+ * Copyright (c) 2005 Embedded Alley Solutions, Inc.
+ * Matt Porter <mporter@embeddedalley.com>
+ *
+ * Based on cmedia.c and realtek.c
+ * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
+ */
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_beep.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+enum {
+       STAC_REF,
+       STAC_9200_OQO,
+       STAC_9200_DELL_D21,
+       STAC_9200_DELL_D22,
+       STAC_9200_DELL_D23,
+       STAC_9200_DELL_M21,
+       STAC_9200_DELL_M22,
+       STAC_9200_DELL_M23,
+       STAC_9200_DELL_M24,
+       STAC_9200_DELL_M25,
+       STAC_9200_DELL_M26,
+       STAC_9200_DELL_M27,
+       STAC_9200_M4,
+       STAC_9200_M4_2,
+       STAC_9200_PANASONIC,
+       STAC_9200_EAPD_INIT,
+       STAC_9200_MODELS
+};
+
+enum {
+       STAC_9205_REF,
+       STAC_9205_DELL_M42,
+       STAC_9205_DELL_M43,
+       STAC_9205_DELL_M44,
+       STAC_9205_EAPD,
+       STAC_9205_MODELS
+};
+
+enum {
+       STAC_92HD73XX_NO_JD, /* no jack-detection */
+       STAC_92HD73XX_REF,
+       STAC_92HD73XX_INTEL,
+       STAC_DELL_M6_AMIC,
+       STAC_DELL_M6_DMIC,
+       STAC_DELL_M6_BOTH,
+       STAC_DELL_EQ,
+       STAC_ALIENWARE_M17X,
+       STAC_ELO_VUPOINT_15MX,
+       STAC_92HD89XX_HP_FRONT_JACK,
+       STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
+       STAC_92HD73XX_ASUS_MOBO,
+       STAC_92HD73XX_MODELS
+};
+
+enum {
+       STAC_92HD83XXX_REF,
+       STAC_92HD83XXX_PWR_REF,
+       STAC_DELL_S14,
+       STAC_DELL_VOSTRO_3500,
+       STAC_92HD83XXX_HP_cNB11_INTQUAD,
+       STAC_HP_DV7_4000,
+       STAC_HP_ZEPHYR,
+       STAC_92HD83XXX_HP_LED,
+       STAC_92HD83XXX_HP_INV_LED,
+       STAC_92HD83XXX_HP_MIC_LED,
+       STAC_HP_LED_GPIO10,
+       STAC_92HD83XXX_HEADSET_JACK,
+       STAC_92HD83XXX_HP,
+       STAC_HP_ENVY_BASS,
+       STAC_HP_BNB13_EQ,
+       STAC_HP_ENVY_TS_BASS,
+       STAC_HP_ENVY_TS_DAC_BIND,
+       STAC_92HD83XXX_GPIO10_EAPD,
+       STAC_92HD83XXX_MODELS
+};
+
+enum {
+       STAC_92HD71BXX_REF,
+       STAC_DELL_M4_1,
+       STAC_DELL_M4_2,
+       STAC_DELL_M4_3,
+       STAC_HP_M4,
+       STAC_HP_DV4,
+       STAC_HP_DV5,
+       STAC_HP_HDX,
+       STAC_92HD71BXX_HP,
+       STAC_92HD71BXX_NO_DMIC,
+       STAC_92HD71BXX_NO_SMUX,
+       STAC_92HD71BXX_MODELS
+};
+
+enum {
+       STAC_92HD95_HP_LED,
+       STAC_92HD95_HP_BASS,
+       STAC_92HD95_MODELS
+};
+
+enum {
+       STAC_925x_REF,
+       STAC_M1,
+       STAC_M1_2,
+       STAC_M2,
+       STAC_M2_2,
+       STAC_M3,
+       STAC_M5,
+       STAC_M6,
+       STAC_925x_MODELS
+};
+
+enum {
+       STAC_D945_REF,
+       STAC_D945GTP3,
+       STAC_D945GTP5,
+       STAC_INTEL_MAC_V1,
+       STAC_INTEL_MAC_V2,
+       STAC_INTEL_MAC_V3,
+       STAC_INTEL_MAC_V4,
+       STAC_INTEL_MAC_V5,
+       STAC_INTEL_MAC_AUTO,
+       STAC_ECS_202,
+       STAC_922X_DELL_D81,
+       STAC_922X_DELL_D82,
+       STAC_922X_DELL_M81,
+       STAC_922X_DELL_M82,
+       STAC_922X_INTEL_MAC_GPIO,
+       STAC_922X_MODELS
+};
+
+enum {
+       STAC_D965_REF_NO_JD, /* no jack-detection */
+       STAC_D965_REF,
+       STAC_D965_3ST,
+       STAC_D965_5ST,
+       STAC_D965_5ST_NO_FP,
+       STAC_D965_VERBS,
+       STAC_DELL_3ST,
+       STAC_DELL_BIOS,
+       STAC_NEMO_DEFAULT,
+       STAC_DELL_BIOS_AMIC,
+       STAC_DELL_BIOS_SPDIF,
+       STAC_927X_DELL_DMIC,
+       STAC_927X_VOLKNOB,
+       STAC_927X_MODELS
+};
+
+enum {
+       STAC_9872_VAIO,
+       STAC_9872_MODELS
+};
+
+struct sigmatel_spec {
+       struct hda_gen_spec gen;
+
+       unsigned int eapd_switch: 1;
+       unsigned int linear_tone_beep:1;
+       unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */
+       unsigned int volknob_init:1; /* special volume-knob initialization */
+       unsigned int powerdown_adcs:1;
+       unsigned int have_spdif_mux:1;
+
+       /* gpio lines */
+       unsigned int eapd_mask;
+       unsigned int gpio_mask;
+       unsigned int gpio_dir;
+       unsigned int gpio_data;
+       unsigned int gpio_mute;
+       unsigned int gpio_led;
+       unsigned int gpio_led_polarity;
+       unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
+       unsigned int vref_led;
+       int default_polarity;
+
+       unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
+       unsigned int mic_enabled; /* current mic mute state (bitmask) */
+
+       /* stream */
+       unsigned int stream_delay;
+
+       /* analog loopback */
+       const struct snd_kcontrol_new *aloopback_ctl;
+       unsigned int aloopback;
+       unsigned char aloopback_mask;
+       unsigned char aloopback_shift;
+
+       /* power management */
+       unsigned int power_map_bits;
+       unsigned int num_pwrs;
+       const hda_nid_t *pwr_nids;
+       unsigned int active_adcs;
+
+       /* beep widgets */
+       hda_nid_t anabeep_nid;
+       bool beep_power_on;
+
+       /* SPDIF-out mux */
+       const char * const *spdif_labels;
+       struct hda_input_mux spdif_mux;
+       unsigned int cur_smux[2];
+};
+
+#define AC_VERB_IDT_SET_POWER_MAP      0x7ec
+#define AC_VERB_IDT_GET_POWER_MAP      0xfec
+
+static const hda_nid_t stac92hd73xx_pwr_nids[8] = {
+       0x0a, 0x0b, 0x0c, 0xd, 0x0e,
+       0x0f, 0x10, 0x11
+};
+
+static const hda_nid_t stac92hd83xxx_pwr_nids[7] = {
+       0x0a, 0x0b, 0x0c, 0xd, 0x0e,
+       0x0f, 0x10
+};
+
+static const hda_nid_t stac92hd71bxx_pwr_nids[3] = {
+       0x0a, 0x0d, 0x0f
+};
+
+
+/*
+ * PCM hooks
+ */
+static void stac_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+                                  struct hda_codec *codec,
+                                  struct snd_pcm_substream *substream,
+                                  int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       if (action == HDA_GEN_PCM_ACT_OPEN && spec->stream_delay)
+               msleep(spec->stream_delay);
+}
+
+static void stac_capture_pcm_hook(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream,
+                                 int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int i, idx = 0;
+
+       if (!spec->powerdown_adcs)
+               return;
+
+       for (i = 0; i < spec->gen.num_all_adcs; i++) {
+               if (spec->gen.all_adcs[i] == hinfo->nid) {
+                       idx = i;
+                       break;
+               }
+       }
+
+       switch (action) {
+       case HDA_GEN_PCM_ACT_OPEN:
+               msleep(40);
+               snd_hda_codec_write(codec, hinfo->nid, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+               spec->active_adcs |= (1 << idx);
+               break;
+       case HDA_GEN_PCM_ACT_CLOSE:
+               snd_hda_codec_write(codec, hinfo->nid, 0,
+                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
+               spec->active_adcs &= ~(1 << idx);
+               break;
+       }
+}
+
+/*
+ * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
+ * funky external mute control using GPIO pins.
+ */
+
+static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
+                         unsigned int dir_mask, unsigned int data)
+{
+       unsigned int gpiostate, gpiomask, gpiodir;
+       hda_nid_t fg = codec->core.afg;
+
+       codec_dbg(codec, "%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
+
+       gpiostate = snd_hda_codec_read(codec, fg, 0,
+                                      AC_VERB_GET_GPIO_DATA, 0);
+       gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
+
+       gpiomask = snd_hda_codec_read(codec, fg, 0,
+                                     AC_VERB_GET_GPIO_MASK, 0);
+       gpiomask |= mask;
+
+       gpiodir = snd_hda_codec_read(codec, fg, 0,
+                                    AC_VERB_GET_GPIO_DIRECTION, 0);
+       gpiodir |= dir_mask;
+
+       /* Configure GPIOx as CMOS */
+       snd_hda_codec_write(codec, fg, 0, 0x7e7, 0);
+
+       snd_hda_codec_write(codec, fg, 0,
+                           AC_VERB_SET_GPIO_MASK, gpiomask);
+       snd_hda_codec_read(codec, fg, 0,
+                          AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
+
+       msleep(1);
+
+       snd_hda_codec_read(codec, fg, 0,
+                          AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
+}
+
+/* hook for controlling mic-mute LED GPIO */
+static int stac_capture_led_update(struct led_classdev *led_cdev,
+                                  enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (brightness)
+               spec->gpio_data |= spec->mic_mute_led_gpio;
+       else
+               spec->gpio_data &= ~spec->mic_mute_led_gpio;
+       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
+       return 0;
+}
+
+static int stac_vrefout_set(struct hda_codec *codec,
+                                       hda_nid_t nid, unsigned int new_vref)
+{
+       int error, pinctl;
+
+       codec_dbg(codec, "%s, nid %x ctl %x\n", __func__, nid, new_vref);
+       pinctl = snd_hda_codec_read(codec, nid, 0,
+                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+
+       if (pinctl < 0)
+               return pinctl;
+
+       pinctl &= 0xff;
+       pinctl &= ~AC_PINCTL_VREFEN;
+       pinctl |= (new_vref & AC_PINCTL_VREFEN);
+
+       error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl);
+       if (error < 0)
+               return error;
+
+       return 1;
+}
+
+/* prevent codec AFG to D3 state when vref-out pin is used for mute LED */
+/* this hook is set in stac_setup_gpio() */
+static unsigned int stac_vref_led_power_filter(struct hda_codec *codec,
+                                              hda_nid_t nid,
+                                              unsigned int power_state)
+{
+       if (nid == codec->core.afg && power_state == AC_PWRST_D3)
+               return AC_PWRST_D1;
+       return snd_hda_gen_path_power_filter(codec, nid, power_state);
+}
+
+/* update mute-LED accoring to the master switch */
+static void stac_update_led_status(struct hda_codec *codec, bool muted)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (!spec->gpio_led)
+               return;
+
+       /* LED state is inverted on these systems */
+       if (spec->gpio_led_polarity)
+               muted = !muted;
+
+       if (!spec->vref_mute_led_nid) {
+               if (muted)
+                       spec->gpio_data |= spec->gpio_led;
+               else
+                       spec->gpio_data &= ~spec->gpio_led;
+               stac_gpio_set(codec, spec->gpio_mask,
+                               spec->gpio_dir, spec->gpio_data);
+       } else {
+               spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
+               stac_vrefout_set(codec, spec->vref_mute_led_nid,
+                                spec->vref_led);
+       }
+}
+
+/* vmaster hook to update mute LED */
+static int stac_vmaster_hook(struct led_classdev *led_cdev,
+                            enum led_brightness brightness)
+{
+       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
+
+       stac_update_led_status(codec, brightness);
+       return 0;
+}
+
+/* automute hook to handle GPIO mute and EAPD updates */
+static void stac_update_outputs(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (spec->gpio_mute)
+               spec->gen.master_mute =
+                       !(snd_hda_codec_read(codec, codec->core.afg, 0,
+                               AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
+
+       snd_hda_gen_update_outputs(codec);
+
+       if (spec->eapd_mask && spec->eapd_switch) {
+               unsigned int val = spec->gpio_data;
+               if (spec->gen.speaker_muted)
+                       val &= ~spec->eapd_mask;
+               else
+                       val |= spec->eapd_mask;
+               if (spec->gpio_data != val) {
+                       spec->gpio_data = val;
+                       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir,
+                                     val);
+               }
+       }
+}
+
+static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
+                                 bool enable, bool do_write)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int idx, val;
+
+       for (idx = 0; idx < spec->num_pwrs; idx++) {
+               if (spec->pwr_nids[idx] == nid)
+                       break;
+       }
+       if (idx >= spec->num_pwrs)
+               return;
+
+       idx = 1 << idx;
+
+       val = spec->power_map_bits;
+       if (enable)
+               val &= ~idx;
+       else
+               val |= idx;
+
+       /* power down unused output ports */
+       if (val != spec->power_map_bits) {
+               spec->power_map_bits = val;
+               if (do_write)
+                       snd_hda_codec_write(codec, codec->core.afg, 0,
+                                           AC_VERB_IDT_SET_POWER_MAP, val);
+       }
+}
+
+/* update power bit per jack plug/unplug */
+static void jack_update_power(struct hda_codec *codec,
+                             struct hda_jack_callback *jack)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int i;
+
+       if (!spec->num_pwrs)
+               return;
+
+       if (jack && jack->nid) {
+               stac_toggle_power_map(codec, jack->nid,
+                                     snd_hda_jack_detect(codec, jack->nid),
+                                     true);
+               return;
+       }
+
+       /* update all jacks */
+       for (i = 0; i < spec->num_pwrs; i++) {
+               hda_nid_t nid = spec->pwr_nids[i];
+               if (!snd_hda_jack_tbl_get(codec, nid))
+                       continue;
+               stac_toggle_power_map(codec, nid,
+                                     snd_hda_jack_detect(codec, nid),
+                                     false);
+       }
+
+       snd_hda_codec_write(codec, codec->core.afg, 0,
+                           AC_VERB_IDT_SET_POWER_MAP,
+                           spec->power_map_bits);
+}
+
+static void stac_vref_event(struct hda_codec *codec,
+                           struct hda_jack_callback *event)
+{
+       unsigned int data;
+
+       data = snd_hda_codec_read(codec, codec->core.afg, 0,
+                                 AC_VERB_GET_GPIO_DATA, 0);
+       /* toggle VREF state based on GPIOx status */
+       snd_hda_codec_write(codec, codec->core.afg, 0, 0x7e0,
+                           !!(data & (1 << event->private_data)));
+}
+
+/* initialize the power map and enable the power event to jacks that
+ * haven't been assigned to automute
+ */
+static void stac_init_power_map(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int i;
+
+       for (i = 0; i < spec->num_pwrs; i++)  {
+               hda_nid_t nid = spec->pwr_nids[i];
+               unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
+               def_conf = get_defcfg_connect(def_conf);
+               if (def_conf == AC_JACK_PORT_COMPLEX &&
+                   spec->vref_mute_led_nid != nid &&
+                   is_jack_detectable(codec, nid)) {
+                       snd_hda_jack_detect_enable_callback(codec, nid,
+                                                           jack_update_power);
+               } else {
+                       if (def_conf == AC_JACK_PORT_NONE)
+                               stac_toggle_power_map(codec, nid, false, false);
+                       else
+                               stac_toggle_power_map(codec, nid, true, false);
+               }
+       }
+}
+
+/*
+ */
+
+static inline bool get_int_hint(struct hda_codec *codec, const char *key,
+                               int *valp)
+{
+       return !snd_hda_get_int_hint(codec, key, valp);
+}
+
+/* override some hints from the hwdep entry */
+static void stac_store_hints(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int val;
+
+       if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) {
+               spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
+                       spec->gpio_mask;
+       }
+       if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
+               spec->gpio_dir &= spec->gpio_mask;
+       if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
+               spec->gpio_data &= spec->gpio_mask;
+       if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
+               spec->eapd_mask &= spec->gpio_mask;
+       if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
+               spec->gpio_mute &= spec->gpio_mask;
+       val = snd_hda_get_bool_hint(codec, "eapd_switch");
+       if (val >= 0)
+               spec->eapd_switch = val;
+}
+
+/*
+ * loopback controls
+ */
+
+#define stac_aloopback_info snd_ctl_boolean_mono_info
+
+static int stac_aloopback_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       struct sigmatel_spec *spec = codec->spec;
+
+       ucontrol->value.integer.value[0] = !!(spec->aloopback &
+                                             (spec->aloopback_mask << idx));
+       return 0;
+}
+
+static int stac_aloopback_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+       unsigned int dac_mode;
+       unsigned int val, idx_val;
+
+       idx_val = spec->aloopback_mask << idx;
+       if (ucontrol->value.integer.value[0])
+               val = spec->aloopback | idx_val;
+       else
+               val = spec->aloopback & ~idx_val;
+       if (spec->aloopback == val)
+               return 0;
+
+       spec->aloopback = val;
+
+       /* Only return the bits defined by the shift value of the
+        * first two bytes of the mask
+        */
+       dac_mode = snd_hda_codec_read(codec, codec->core.afg, 0,
+                                     kcontrol->private_value & 0xFFFF, 0x0);
+       dac_mode >>= spec->aloopback_shift;
+
+       if (spec->aloopback & idx_val) {
+               snd_hda_power_up(codec);
+               dac_mode |= idx_val;
+       } else {
+               snd_hda_power_down(codec);
+               dac_mode &= ~idx_val;
+       }
+
+       snd_hda_codec_write_cache(codec, codec->core.afg, 0,
+               kcontrol->private_value >> 16, dac_mode);
+
+       return 1;
+}
+
+#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
+       { \
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+               .name  = "Analog Loopback", \
+               .count = cnt, \
+               .info  = stac_aloopback_info, \
+               .get   = stac_aloopback_get, \
+               .put   = stac_aloopback_put, \
+               .private_value = verb_read | (verb_write << 16), \
+       }
+
+/*
+ * Mute LED handling on HP laptops
+ */
+
+/* check whether it's a HP laptop with a docking port */
+static bool hp_bnb2011_with_dock(struct hda_codec *codec)
+{
+       if (codec->core.vendor_id != 0x111d7605 &&
+           codec->core.vendor_id != 0x111d76d1)
+               return false;
+
+       switch (codec->core.subsystem_id) {
+       case 0x103c1618:
+       case 0x103c1619:
+       case 0x103c161a:
+       case 0x103c161b:
+       case 0x103c161c:
+       case 0x103c161d:
+       case 0x103c161e:
+       case 0x103c161f:
+
+       case 0x103c162a:
+       case 0x103c162b:
+
+       case 0x103c1630:
+       case 0x103c1631:
+
+       case 0x103c1633:
+       case 0x103c1634:
+       case 0x103c1635:
+
+       case 0x103c3587:
+       case 0x103c3588:
+       case 0x103c3589:
+       case 0x103c358a:
+
+       case 0x103c3667:
+       case 0x103c3668:
+       case 0x103c3669:
+
+               return true;
+       }
+       return false;
+}
+
+static bool hp_blike_system(u32 subsystem_id)
+{
+       switch (subsystem_id) {
+       case 0x103c1473: /* HP ProBook 6550b */
+       case 0x103c1520:
+       case 0x103c1521:
+       case 0x103c1523:
+       case 0x103c1524:
+       case 0x103c1525:
+       case 0x103c1722:
+       case 0x103c1723:
+       case 0x103c1724:
+       case 0x103c1725:
+       case 0x103c1726:
+       case 0x103c1727:
+       case 0x103c1728:
+       case 0x103c1729:
+       case 0x103c172a:
+       case 0x103c172b:
+       case 0x103c307e:
+       case 0x103c307f:
+       case 0x103c3080:
+       case 0x103c3081:
+       case 0x103c7007:
+       case 0x103c7008:
+               return true;
+       }
+       return false;
+}
+
+static void set_hp_led_gpio(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int gpio;
+
+       if (spec->gpio_led)
+               return;
+
+       gpio = snd_hda_param_read(codec, codec->core.afg, AC_PAR_GPIO_CAP);
+       gpio &= AC_GPIO_IO_COUNT;
+       if (gpio > 3)
+               spec->gpio_led = 0x08; /* GPIO 3 */
+       else
+               spec->gpio_led = 0x01; /* GPIO 0 */
+}
+
+/*
+ * This method searches for the mute LED GPIO configuration
+ * provided as OEM string in SMBIOS. The format of that string
+ * is HP_Mute_LED_P_G or HP_Mute_LED_P
+ * where P can be 0 or 1 and defines mute LED GPIO control state (low/high)
+ * that corresponds to the NOT muted state of the master volume
+ * and G is the index of the GPIO to use as the mute LED control (0..9)
+ * If _G portion is missing it is assigned based on the codec ID
+ *
+ * So, HP B-series like systems may have HP_Mute_LED_0 (current models)
+ * or  HP_Mute_LED_0_3 (future models) OEM SMBIOS strings
+ *
+ *
+ * The dv-series laptops don't seem to have the HP_Mute_LED* strings in
+ * SMBIOS - at least the ones I have seen do not have them - which include
+ * my own system (HP Pavilion dv6-1110ax) and my cousin's
+ * HP Pavilion dv9500t CTO.
+ * Need more information on whether it is true across the entire series.
+ * -- kunal
+ */
+static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       const struct dmi_device *dev = NULL;
+
+       if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
+               get_int_hint(codec, "gpio_led_polarity",
+                            &spec->gpio_led_polarity);
+               return 1;
+       }
+
+       while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
+               if (sscanf(dev->name, "HP_Mute_LED_%u_%x",
+                          &spec->gpio_led_polarity,
+                          &spec->gpio_led) == 2) {
+                       unsigned int max_gpio;
+                       max_gpio = snd_hda_param_read(codec, codec->core.afg,
+                                                     AC_PAR_GPIO_CAP);
+                       max_gpio &= AC_GPIO_IO_COUNT;
+                       if (spec->gpio_led < max_gpio)
+                               spec->gpio_led = 1 << spec->gpio_led;
+                       else
+                               spec->vref_mute_led_nid = spec->gpio_led;
+                       return 1;
+               }
+               if (sscanf(dev->name, "HP_Mute_LED_%u",
+                          &spec->gpio_led_polarity) == 1) {
+                       set_hp_led_gpio(codec);
+                       return 1;
+               }
+               /* BIOS bug: unfilled OEM string */
+               if (strstr(dev->name, "HP_Mute_LED_P_G")) {
+                       set_hp_led_gpio(codec);
+                       if (default_polarity >= 0)
+                               spec->gpio_led_polarity = default_polarity;
+                       else
+                               spec->gpio_led_polarity = 1;
+                       return 1;
+               }
+       }
+
+       /*
+        * Fallback case - if we don't find the DMI strings,
+        * we statically set the GPIO - if not a B-series system
+        * and default polarity is provided
+        */
+       if (!hp_blike_system(codec->core.subsystem_id) &&
+           (default_polarity == 0 || default_polarity == 1)) {
+               set_hp_led_gpio(codec);
+               spec->gpio_led_polarity = default_polarity;
+               return 1;
+       }
+       return 0;
+}
+
+/* check whether a built-in speaker is included in parsed pins */
+static bool has_builtin_speaker(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       const hda_nid_t *nid_pin;
+       int nids, i;
+
+       if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
+               nid_pin = spec->gen.autocfg.line_out_pins;
+               nids = spec->gen.autocfg.line_outs;
+       } else {
+               nid_pin = spec->gen.autocfg.speaker_pins;
+               nids = spec->gen.autocfg.speaker_outs;
+       }
+
+       for (i = 0; i < nids; i++) {
+               unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid_pin[i]);
+               if (snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT)
+                       return true;
+       }
+       return false;
+}
+
+/*
+ * PC beep controls
+ */
+
+/* create PC beep volume controls */
+static int stac_auto_create_beep_ctls(struct hda_codec *codec,
+                                               hda_nid_t nid)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+       struct snd_kcontrol_new *knew;
+       static const struct snd_kcontrol_new abeep_mute_ctl =
+               HDA_CODEC_MUTE(NULL, 0, 0, 0);
+       static const struct snd_kcontrol_new dbeep_mute_ctl =
+               HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0);
+       static const struct snd_kcontrol_new beep_vol_ctl =
+               HDA_CODEC_VOLUME(NULL, 0, 0, 0);
+
+       /* check for mute support for the amp */
+       if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
+               const struct snd_kcontrol_new *temp;
+               if (spec->anabeep_nid == nid)
+                       temp = &abeep_mute_ctl;
+               else
+                       temp = &dbeep_mute_ctl;
+               knew = snd_hda_gen_add_kctl(&spec->gen,
+                                           "Beep Playback Switch", temp);
+               if (!knew)
+                       return -ENOMEM;
+               knew->private_value =
+                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT);
+       }
+
+       /* check to see if there is volume support for the amp */
+       if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
+               knew = snd_hda_gen_add_kctl(&spec->gen,
+                                           "Beep Playback Volume",
+                                           &beep_vol_ctl);
+               if (!knew)
+                       return -ENOMEM;
+               knew->private_value =
+                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT);
+       }
+       return 0;
+}
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+#define stac_dig_beep_switch_info snd_ctl_boolean_mono_info
+
+static int stac_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       ucontrol->value.integer.value[0] = codec->beep->enabled;
+       return 0;
+}
+
+static int stac_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
+}
+
+static const struct snd_kcontrol_new stac_dig_beep_ctrl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Beep Playback Switch",
+       .info = stac_dig_beep_switch_info,
+       .get = stac_dig_beep_switch_get,
+       .put = stac_dig_beep_switch_put,
+};
+
+static int stac_beep_switch_ctl(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_dig_beep_ctrl))
+               return -ENOMEM;
+       return 0;
+}
+#endif
+
+/*
+ * SPDIF-out mux controls
+ */
+
+static int stac_smux_enum_info(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_info *uinfo)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       return snd_hda_input_mux_info(&spec->spdif_mux, uinfo);
+}
+
+static int stac_smux_enum_get(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+       ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
+       return 0;
+}
+
+static int stac_smux_enum_put(struct snd_kcontrol *kcontrol,
+                             struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
+
+       return snd_hda_input_mux_put(codec, &spec->spdif_mux, ucontrol,
+                                    spec->gen.autocfg.dig_out_pins[smux_idx],
+                                    &spec->cur_smux[smux_idx]);
+}
+
+static const struct snd_kcontrol_new stac_smux_mixer = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "IEC958 Playback Source",
+       /* count set later */
+       .info = stac_smux_enum_info,
+       .get = stac_smux_enum_get,
+       .put = stac_smux_enum_put,
+};
+
+static const char * const stac_spdif_labels[] = {
+       "Digital Playback", "Analog Mux 1", "Analog Mux 2", NULL
+};
+
+static int stac_create_spdif_mux_ctls(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
+       const char * const *labels = spec->spdif_labels;
+       struct snd_kcontrol_new *kctl;
+       int i, num_cons;
+
+       if (cfg->dig_outs < 1)
+               return 0;
+
+       num_cons = snd_hda_get_num_conns(codec, cfg->dig_out_pins[0]);
+       if (num_cons <= 1)
+               return 0;
+
+       if (!labels)
+               labels = stac_spdif_labels;
+       for (i = 0; i < num_cons; i++) {
+               if (snd_BUG_ON(!labels[i]))
+                       return -EINVAL;
+               snd_hda_add_imux_item(codec, &spec->spdif_mux, labels[i], i, NULL);
+       }
+
+       kctl = snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_smux_mixer);
+       if (!kctl)
+               return -ENOMEM;
+       kctl->count = cfg->dig_outs;
+
+       return 0;
+}
+
+static const struct hda_verb stac9200_eapd_init[] = {
+       /* set dac0mux for dac converter */
+       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
+       {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+       {}
+};
+
+static const struct hda_verb dell_eq_core_init[] = {
+       /* set master volume to max value without distortion
+        * and direct control */
+       { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
+       {}
+};
+
+static const struct hda_verb stac92hd73xx_core_init[] = {
+       /* set master volume and direct control */
+       { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       {}
+};
+
+static const struct hda_verb stac92hd83xxx_core_init[] = {
+       /* power state controls amps */
+       { 0x01, AC_VERB_SET_EAPD, 1 << 2},
+       {}
+};
+
+static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = {
+       { 0x22, 0x785, 0x43 },
+       { 0x22, 0x782, 0xe0 },
+       { 0x22, 0x795, 0x00 },
+       {}
+};
+
+static const struct hda_verb stac92hd71bxx_core_init[] = {
+       /* set master volume and direct control */
+       { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       {}
+};
+
+static const hda_nid_t stac92hd71bxx_unmute_nids[] = {
+       /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
+       0x0f, 0x0a, 0x0d, 0
+};
+
+static const struct hda_verb stac925x_core_init[] = {
+       /* set dac0mux for dac converter */
+       { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
+       /* mute the master volume */
+       { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
+       {}
+};
+
+static const struct hda_verb stac922x_core_init[] = {
+       /* set master volume and direct control */
+       { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       {}
+};
+
+static const struct hda_verb d965_core_init[] = {
+       /* unmute node 0x1b */
+       { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       /* select node 0x03 as DAC */
+       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {}
+};
+
+static const struct hda_verb dell_3st_core_init[] = {
+       /* don't set delta bit */
+       {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
+       /* unmute node 0x1b */
+       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
+       /* select node 0x03 as DAC */
+       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
+       {}
+};
+
+static const struct hda_verb stac927x_core_init[] = {
+       /* set master volume and direct control */
+       { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* enable analog pc beep path */
+       { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
+       {}
+};
+
+static const struct hda_verb stac927x_volknob_core_init[] = {
+       /* don't set delta bit */
+       {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
+       /* enable analog pc beep path */
+       {0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
+       {}
+};
+
+static const struct hda_verb stac9205_core_init[] = {
+       /* set master volume and direct control */
+       { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
+       /* enable analog pc beep path */
+       { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
+       {}
+};
+
+static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback =
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3);
+
+static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback =
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4);
+
+static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback =
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5);
+
+static const struct snd_kcontrol_new stac92hd71bxx_loopback =
+       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2);
+
+static const struct snd_kcontrol_new stac9205_loopback =
+       STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1);
+
+static const struct snd_kcontrol_new stac927x_loopback =
+       STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1);
+
+static const struct hda_pintbl ref9200_pin_configs[] = {
+       { 0x08, 0x01c47010 },
+       { 0x09, 0x01447010 },
+       { 0x0d, 0x0221401f },
+       { 0x0e, 0x01114010 },
+       { 0x0f, 0x02a19020 },
+       { 0x10, 0x01a19021 },
+       { 0x11, 0x90100140 },
+       { 0x12, 0x01813122 },
+       {}
+};
+
+static const struct hda_pintbl gateway9200_m4_pin_configs[] = {
+       { 0x08, 0x400000fe },
+       { 0x09, 0x404500f4 },
+       { 0x0d, 0x400100f0 },
+       { 0x0e, 0x90110010 },
+       { 0x0f, 0x400100f1 },
+       { 0x10, 0x02a1902e },
+       { 0x11, 0x500000f2 },
+       { 0x12, 0x500000f3 },
+       {}
+};
+
+static const struct hda_pintbl gateway9200_m4_2_pin_configs[] = {
+       { 0x08, 0x400000fe },
+       { 0x09, 0x404500f4 },
+       { 0x0d, 0x400100f0 },
+       { 0x0e, 0x90110010 },
+       { 0x0f, 0x400100f1 },
+       { 0x10, 0x02a1902e },
+       { 0x11, 0x500000f2 },
+       { 0x12, 0x500000f3 },
+       {}
+};
+
+/*
+    STAC 9200 pin configs for
+    102801A8
+    102801DE
+    102801E8
+*/
+static const struct hda_pintbl dell9200_d21_pin_configs[] = {
+       { 0x08, 0x400001f0 },
+       { 0x09, 0x400001f1 },
+       { 0x0d, 0x02214030 },
+       { 0x0e, 0x01014010 },
+       { 0x0f, 0x02a19020 },
+       { 0x10, 0x01a19021 },
+       { 0x11, 0x90100140 },
+       { 0x12, 0x01813122 },
+       {}
+};
+
+/*
+    STAC 9200 pin configs for
+    102801C0
+    102801C1
+*/
+static const struct hda_pintbl dell9200_d22_pin_configs[] = {
+       { 0x08, 0x400001f0 },
+       { 0x09, 0x400001f1 },
+       { 0x0d, 0x0221401f },
+       { 0x0e, 0x01014010 },
+       { 0x0f, 0x01813020 },
+       { 0x10, 0x02a19021 },
+       { 0x11, 0x90100140 },
+       { 0x12, 0x400001f2 },
+       {}
+};
+
+/*
+    STAC 9200 pin configs for
+    102801C4 (Dell Dimension E310)
+    102801C5
+    102801C7
+    102801D9
+    102801DA
+    102801E3
+*/
+static const struct hda_pintbl dell9200_d23_pin_configs[] = {
+       { 0x08, 0x400001f0 },
+       { 0x09, 0x400001f1 },
+       { 0x0d, 0x0221401f },
+       { 0x0e, 0x01014010 },
+       { 0x0f, 0x01813020 },
+       { 0x10, 0x01a19021 },
+       { 0x11, 0x90100140 },
+       { 0x12, 0x400001f2 },
+       {}
+};
+
+
+/* 
+    STAC 9200-32 pin configs for
+    102801B5 (Dell Inspiron 630m)
+    102801D8 (Dell Inspiron 640m)
+*/
+static const struct hda_pintbl dell9200_m21_pin_configs[] = {
+       { 0x08, 0x40c003fa },
+       { 0x09, 0x03441340 },
+       { 0x0d, 0x0321121f },
+       { 0x0e, 0x90170310 },
+       { 0x0f, 0x408003fb },
+       { 0x10, 0x03a11020 },
+       { 0x11, 0x401003fc },
+       { 0x12, 0x403003fd },
+       {}
+};
+
+/* 
+    STAC 9200-32 pin configs for
+    102801C2 (Dell Latitude D620)
+    102801C8 
+    102801CC (Dell Latitude D820)
+    102801D4 
+    102801D6 
+*/
+static const struct hda_pintbl dell9200_m22_pin_configs[] = {
+       { 0x08, 0x40c003fa },
+       { 0x09, 0x0144131f },
+       { 0x0d, 0x0321121f },
+       { 0x0e, 0x90170310 },
+       { 0x0f, 0x90a70321 },
+       { 0x10, 0x03a11020 },
+       { 0x11, 0x401003fb },
+       { 0x12, 0x40f000fc },
+       {}
+};
+
+/* 
+    STAC 9200-32 pin configs for
+    102801CE (Dell XPS M1710)
+    102801CF (Dell Precision M90)
+*/
+static const struct hda_pintbl dell9200_m23_pin_configs[] = {
+       { 0x08, 0x40c003fa },
+       { 0x09, 0x01441340 },
+       { 0x0d, 0x0421421f },
+       { 0x0e, 0x90170310 },
+       { 0x0f, 0x408003fb },
+       { 0x10, 0x04a1102e },
+       { 0x11, 0x90170311 },
+       { 0x12, 0x403003fc },
+       {}
+};
+
+/*
+    STAC 9200-32 pin configs for 
+    102801C9
+    102801CA
+    102801CB (Dell Latitude 120L)
+    102801D3
+*/
+static const struct hda_pintbl dell9200_m24_pin_configs[] = {
+       { 0x08, 0x40c003fa },
+       { 0x09, 0x404003fb },
+       { 0x0d, 0x0321121f },
+       { 0x0e, 0x90170310 },
+       { 0x0f, 0x408003fc },
+       { 0x10, 0x03a11020 },
+       { 0x11, 0x401003fd },
+       { 0x12, 0x403003fe },
+       {}
+};
+
+/*
+    STAC 9200-32 pin configs for
+    102801BD (Dell Inspiron E1505n)
+    102801EE
+    102801EF
+*/
+static const struct hda_pintbl dell9200_m25_pin_configs[] = {
+       { 0x08, 0x40c003fa },
+       { 0x09, 0x01441340 },
+       { 0x0d, 0x0421121f },
+       { 0x0e, 0x90170310 },
+       { 0x0f, 0x408003fb },
+       { 0x10, 0x04a11020 },
+       { 0x11, 0x401003fc },
+       { 0x12, 0x403003fd },
+       {}
+};
+
+/*
+    STAC 9200-32 pin configs for
+    102801F5 (Dell Inspiron 1501)
+    102801F6
+*/
+static const struct hda_pintbl dell9200_m26_pin_configs[] = {
+       { 0x08, 0x40c003fa },
+       { 0x09, 0x404003fb },
+       { 0x0d, 0x0421121f },
+       { 0x0e, 0x90170310 },
+       { 0x0f, 0x408003fc },
+       { 0x10, 0x04a11020 },
+       { 0x11, 0x401003fd },
+       { 0x12, 0x403003fe },
+       {}
+};
+
+/*
+    STAC 9200-32
+    102801CD (Dell Inspiron E1705/9400)
+*/
+static const struct hda_pintbl dell9200_m27_pin_configs[] = {
+       { 0x08, 0x40c003fa },
+       { 0x09, 0x01441340 },
+       { 0x0d, 0x0421121f },
+       { 0x0e, 0x90170310 },
+       { 0x0f, 0x90170310 },
+       { 0x10, 0x04a11020 },
+       { 0x11, 0x90170310 },
+       { 0x12, 0x40f003fc },
+       {}
+};
+
+static const struct hda_pintbl oqo9200_pin_configs[] = {
+       { 0x08, 0x40c000f0 },
+       { 0x09, 0x404000f1 },
+       { 0x0d, 0x0221121f },
+       { 0x0e, 0x02211210 },
+       { 0x0f, 0x90170111 },
+       { 0x10, 0x90a70120 },
+       { 0x11, 0x400000f2 },
+       { 0x12, 0x400000f3 },
+       {}
+};
+
+/*
+ *  STAC 92HD700
+ *  18881000 Amigaone X1000
+ */
+static const struct hda_pintbl nemo_pin_configs[] = {
+       { 0x0a, 0x02214020 },   /* Front panel HP socket */
+       { 0x0b, 0x02a19080 },   /* Front Mic */
+       { 0x0c, 0x0181304e },   /* Line in */
+       { 0x0d, 0x01014010 },   /* Line out */
+       { 0x0e, 0x01a19040 },   /* Rear Mic */
+       { 0x0f, 0x01011012 },   /* Rear speakers */
+       { 0x10, 0x01016011 },   /* Center speaker */
+       { 0x11, 0x01012014 },   /* Side speakers (7.1) */
+       { 0x12, 0x103301f0 },   /* Motherboard CD line in connector */
+       { 0x13, 0x411111f0 },   /* Unused */
+       { 0x14, 0x411111f0 },   /* Unused */
+       { 0x21, 0x01442170 },   /* S/PDIF line out */
+       { 0x22, 0x411111f0 },   /* Unused */
+       { 0x23, 0x411111f0 },   /* Unused */
+       {}
+};
+
+static void stac9200_fixup_panasonic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gpio_mask = spec->gpio_dir = 0x09;
+               spec->gpio_data = 0x00;
+               /* CF-74 has no headphone detection, and the driver should *NOT*
+                * do detection and HP/speaker toggle because the hardware does it.
+                */
+               spec->gen.suppress_auto_mute = 1;
+       }
+}
+
+
+static const struct hda_fixup stac9200_fixups[] = {
+       [STAC_REF] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = ref9200_pin_configs,
+       },
+       [STAC_9200_OQO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = oqo9200_pin_configs,
+               .chained = true,
+               .chain_id = STAC_9200_EAPD_INIT,
+       },
+       [STAC_9200_DELL_D21] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_d21_pin_configs,
+       },
+       [STAC_9200_DELL_D22] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_d22_pin_configs,
+       },
+       [STAC_9200_DELL_D23] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_d23_pin_configs,
+       },
+       [STAC_9200_DELL_M21] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_m21_pin_configs,
+       },
+       [STAC_9200_DELL_M22] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_m22_pin_configs,
+       },
+       [STAC_9200_DELL_M23] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_m23_pin_configs,
+       },
+       [STAC_9200_DELL_M24] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_m24_pin_configs,
+       },
+       [STAC_9200_DELL_M25] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_m25_pin_configs,
+       },
+       [STAC_9200_DELL_M26] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_m26_pin_configs,
+       },
+       [STAC_9200_DELL_M27] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell9200_m27_pin_configs,
+       },
+       [STAC_9200_M4] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = gateway9200_m4_pin_configs,
+               .chained = true,
+               .chain_id = STAC_9200_EAPD_INIT,
+       },
+       [STAC_9200_M4_2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = gateway9200_m4_2_pin_configs,
+               .chained = true,
+               .chain_id = STAC_9200_EAPD_INIT,
+       },
+       [STAC_9200_PANASONIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac9200_fixup_panasonic,
+       },
+       [STAC_9200_EAPD_INIT] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+                       {}
+               },
+       },
+};
+
+static const struct hda_model_fixup stac9200_models[] = {
+       { .id = STAC_REF, .name = "ref" },
+       { .id = STAC_9200_OQO, .name = "oqo" },
+       { .id = STAC_9200_DELL_D21, .name = "dell-d21" },
+       { .id = STAC_9200_DELL_D22, .name = "dell-d22" },
+       { .id = STAC_9200_DELL_D23, .name = "dell-d23" },
+       { .id = STAC_9200_DELL_M21, .name = "dell-m21" },
+       { .id = STAC_9200_DELL_M22, .name = "dell-m22" },
+       { .id = STAC_9200_DELL_M23, .name = "dell-m23" },
+       { .id = STAC_9200_DELL_M24, .name = "dell-m24" },
+       { .id = STAC_9200_DELL_M25, .name = "dell-m25" },
+       { .id = STAC_9200_DELL_M26, .name = "dell-m26" },
+       { .id = STAC_9200_DELL_M27, .name = "dell-m27" },
+       { .id = STAC_9200_M4, .name = "gateway-m4" },
+       { .id = STAC_9200_M4_2, .name = "gateway-m4-2" },
+       { .id = STAC_9200_PANASONIC, .name = "panasonic" },
+       {}
+};
+
+static const struct hda_quirk stac9200_fixup_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_REF),
+       /* Dell laptops have BIOS problem */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
+                     "unknown Dell", STAC_9200_DELL_D21),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
+                     "Dell Inspiron 630m", STAC_9200_DELL_M21),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
+                     "Dell Inspiron E1505n", STAC_9200_DELL_M25),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
+                     "unknown Dell", STAC_9200_DELL_D22),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
+                     "unknown Dell", STAC_9200_DELL_D22),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
+                     "Dell Latitude D620", STAC_9200_DELL_M22),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
+                     "unknown Dell", STAC_9200_DELL_D23),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
+                     "unknown Dell", STAC_9200_DELL_D23),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
+                     "unknown Dell", STAC_9200_DELL_M22),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
+                     "unknown Dell", STAC_9200_DELL_M24),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
+                     "unknown Dell", STAC_9200_DELL_M24),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
+                     "Dell Latitude 120L", STAC_9200_DELL_M24),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
+                     "Dell Latitude D820", STAC_9200_DELL_M22),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
+                     "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
+                     "Dell XPS M1710", STAC_9200_DELL_M23),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
+                     "Dell Precision M90", STAC_9200_DELL_M23),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
+                     "unknown Dell", STAC_9200_DELL_M22),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
+                     "unknown Dell", STAC_9200_DELL_M22),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
+                     "unknown Dell", STAC_9200_DELL_M22),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
+                     "Dell Inspiron 640m", STAC_9200_DELL_M21),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
+                     "unknown Dell", STAC_9200_DELL_D23),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
+                     "unknown Dell", STAC_9200_DELL_D23),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
+                     "unknown Dell", STAC_9200_DELL_D21),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
+                     "unknown Dell", STAC_9200_DELL_D23),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
+                     "unknown Dell", STAC_9200_DELL_D21),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
+                     "unknown Dell", STAC_9200_DELL_M25),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
+                     "unknown Dell", STAC_9200_DELL_M25),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
+                     "Dell Inspiron 1501", STAC_9200_DELL_M26),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
+                     "unknown Dell", STAC_9200_DELL_M26),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0201,
+                     "Dell Latitude D430", STAC_9200_DELL_M22),
+       /* Panasonic */
+       SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
+       /* Gateway machines needs EAPD to be set on resume */
+       SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4),
+       SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2),
+       SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2),
+       /* OQO Mobile */
+       SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
+       {} /* terminator */
+};
+
+static const struct hda_pintbl ref925x_pin_configs[] = {
+       { 0x07, 0x40c003f0 },
+       { 0x08, 0x424503f2 },
+       { 0x0a, 0x01813022 },
+       { 0x0b, 0x02a19021 },
+       { 0x0c, 0x90a70320 },
+       { 0x0d, 0x02214210 },
+       { 0x10, 0x01019020 },
+       { 0x11, 0x9033032e },
+       {}
+};
+
+static const struct hda_pintbl stac925xM1_pin_configs[] = {
+       { 0x07, 0x40c003f4 },
+       { 0x08, 0x424503f2 },
+       { 0x0a, 0x400000f3 },
+       { 0x0b, 0x02a19020 },
+       { 0x0c, 0x40a000f0 },
+       { 0x0d, 0x90100210 },
+       { 0x10, 0x400003f1 },
+       { 0x11, 0x9033032e },
+       {}
+};
+
+static const struct hda_pintbl stac925xM1_2_pin_configs[] = {
+       { 0x07, 0x40c003f4 },
+       { 0x08, 0x424503f2 },
+       { 0x0a, 0x400000f3 },
+       { 0x0b, 0x02a19020 },
+       { 0x0c, 0x40a000f0 },
+       { 0x0d, 0x90100210 },
+       { 0x10, 0x400003f1 },
+       { 0x11, 0x9033032e },
+       {}
+};
+
+static const struct hda_pintbl stac925xM2_pin_configs[] = {
+       { 0x07, 0x40c003f4 },
+       { 0x08, 0x424503f2 },
+       { 0x0a, 0x400000f3 },
+       { 0x0b, 0x02a19020 },
+       { 0x0c, 0x40a000f0 },
+       { 0x0d, 0x90100210 },
+       { 0x10, 0x400003f1 },
+       { 0x11, 0x9033032e },
+       {}
+};
+
+static const struct hda_pintbl stac925xM2_2_pin_configs[] = {
+       { 0x07, 0x40c003f4 },
+       { 0x08, 0x424503f2 },
+       { 0x0a, 0x400000f3 },
+       { 0x0b, 0x02a19020 },
+       { 0x0c, 0x40a000f0 },
+       { 0x0d, 0x90100210 },
+       { 0x10, 0x400003f1 },
+       { 0x11, 0x9033032e },
+       {}
+};
+
+static const struct hda_pintbl stac925xM3_pin_configs[] = {
+       { 0x07, 0x40c003f4 },
+       { 0x08, 0x424503f2 },
+       { 0x0a, 0x400000f3 },
+       { 0x0b, 0x02a19020 },
+       { 0x0c, 0x40a000f0 },
+       { 0x0d, 0x90100210 },
+       { 0x10, 0x400003f1 },
+       { 0x11, 0x503303f3 },
+       {}
+};
+
+static const struct hda_pintbl stac925xM5_pin_configs[] = {
+       { 0x07, 0x40c003f4 },
+       { 0x08, 0x424503f2 },
+       { 0x0a, 0x400000f3 },
+       { 0x0b, 0x02a19020 },
+       { 0x0c, 0x40a000f0 },
+       { 0x0d, 0x90100210 },
+       { 0x10, 0x400003f1 },
+       { 0x11, 0x9033032e },
+       {}
+};
+
+static const struct hda_pintbl stac925xM6_pin_configs[] = {
+       { 0x07, 0x40c003f4 },
+       { 0x08, 0x424503f2 },
+       { 0x0a, 0x400000f3 },
+       { 0x0b, 0x02a19020 },
+       { 0x0c, 0x40a000f0 },
+       { 0x0d, 0x90100210 },
+       { 0x10, 0x400003f1 },
+       { 0x11, 0x90330320 },
+       {}
+};
+
+static const struct hda_fixup stac925x_fixups[] = {
+       [STAC_REF] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = ref925x_pin_configs,
+       },
+       [STAC_M1] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac925xM1_pin_configs,
+       },
+       [STAC_M1_2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac925xM1_2_pin_configs,
+       },
+       [STAC_M2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac925xM2_pin_configs,
+       },
+       [STAC_M2_2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac925xM2_2_pin_configs,
+       },
+       [STAC_M3] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac925xM3_pin_configs,
+       },
+       [STAC_M5] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac925xM5_pin_configs,
+       },
+       [STAC_M6] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac925xM6_pin_configs,
+       },
+};
+
+static const struct hda_model_fixup stac925x_models[] = {
+       { .id = STAC_REF, .name = "ref" },
+       { .id = STAC_M1, .name = "m1" },
+       { .id = STAC_M1_2, .name = "m1-2" },
+       { .id = STAC_M2, .name = "m2" },
+       { .id = STAC_M2_2, .name = "m2-2" },
+       { .id = STAC_M3, .name = "m3" },
+       { .id = STAC_M5, .name = "m5" },
+       { .id = STAC_M6, .name = "m6" },
+       {}
+};
+
+static const struct hda_quirk stac925x_fixup_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
+       SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
+
+       /* Default table for unknown ID */
+       SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2),
+
+       /* gateway machines are checked via codec ssid */
+       SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
+       SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
+       SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
+       SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2),
+       SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2),
+       /* Not sure about the brand name for those */
+       SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1),
+       SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3),
+       SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6),
+       SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2),
+       {} /* terminator */
+};
+
+static const struct hda_pintbl ref92hd73xx_pin_configs[] = {
+       // Port A-H
+       { 0x0a, 0x02214030 },
+       { 0x0b, 0x02a19040 },
+       { 0x0c, 0x01a19020 },
+       { 0x0d, 0x02214030 },
+       { 0x0e, 0x0181302e },
+       { 0x0f, 0x01014010 },
+       { 0x10, 0x01014020 },
+       { 0x11, 0x01014030 },
+       // CD in
+       { 0x12, 0x02319040 },
+       // Digial Mic ins
+       { 0x13, 0x90a000f0 },
+       { 0x14, 0x90a000f0 },
+       // Digital outs
+       { 0x22, 0x01452050 },
+       { 0x23, 0x01452050 },
+       {}
+};
+
+static const struct hda_pintbl dell_m6_pin_configs[] = {
+       { 0x0a, 0x0321101f },
+       { 0x0b, 0x4f00000f },
+       { 0x0c, 0x4f0000f0 },
+       { 0x0d, 0x90170110 },
+       { 0x0e, 0x03a11020 },
+       { 0x0f, 0x0321101f },
+       { 0x10, 0x4f0000f0 },
+       { 0x11, 0x4f0000f0 },
+       { 0x12, 0x4f0000f0 },
+       { 0x13, 0x90a60160 },
+       { 0x14, 0x4f0000f0 },
+       { 0x22, 0x4f0000f0 },
+       { 0x23, 0x4f0000f0 },
+       {}
+};
+
+static const struct hda_pintbl alienware_m17x_pin_configs[] = {
+       { 0x0a, 0x0321101f },
+       { 0x0b, 0x0321101f },
+       { 0x0c, 0x03a11020 },
+       { 0x0d, 0x03014020 },
+       { 0x0e, 0x90170110 },
+       { 0x0f, 0x4f0000f0 },
+       { 0x10, 0x4f0000f0 },
+       { 0x11, 0x4f0000f0 },
+       { 0x12, 0x4f0000f0 },
+       { 0x13, 0x90a60160 },
+       { 0x14, 0x4f0000f0 },
+       { 0x22, 0x4f0000f0 },
+       { 0x23, 0x904601b0 },
+       {}
+};
+
+static const struct hda_pintbl intel_dg45id_pin_configs[] = {
+       // Analog outputs
+       { 0x0a, 0x02214230 },
+       { 0x0b, 0x02A19240 },
+       { 0x0c, 0x01013214 },
+       { 0x0d, 0x01014210 },
+       { 0x0e, 0x01A19250 },
+       { 0x0f, 0x01011212 },
+       { 0x10, 0x01016211 },
+       // Digital output
+       { 0x22, 0x01451380 },
+       { 0x23, 0x40f000f0 },
+       {}
+};
+
+static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = {
+       { 0x0a, 0x02214030 },
+       { 0x0b, 0x02A19010 },
+       {}
+};
+
+static const struct hda_pintbl stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs[] = {
+       { 0x0e, 0x400000f0 },
+       {}
+};
+
+static void stac92hd73xx_fixup_ref(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       snd_hda_apply_pincfgs(codec, ref92hd73xx_pin_configs);
+       spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0;
+}
+
+static void stac92hd73xx_fixup_dell(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       snd_hda_apply_pincfgs(codec, dell_m6_pin_configs);
+       spec->eapd_switch = 0;
+}
+
+static void stac92hd73xx_fixup_dell_eq(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       stac92hd73xx_fixup_dell(codec);
+       snd_hda_add_verbs(codec, dell_eq_core_init);
+       spec->volknob_init = 1;
+}
+
+/* Analog Mics */
+static void stac92hd73xx_fixup_dell_m6_amic(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       stac92hd73xx_fixup_dell(codec);
+       snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
+}
+
+/* Digital Mics */
+static void stac92hd73xx_fixup_dell_m6_dmic(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       stac92hd73xx_fixup_dell(codec);
+       snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
+}
+
+/* Both */
+static void stac92hd73xx_fixup_dell_m6_both(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       stac92hd73xx_fixup_dell(codec);
+       snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
+       snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
+}
+
+static void stac92hd73xx_fixup_alienware_m17x(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       snd_hda_apply_pincfgs(codec, alienware_m17x_pin_configs);
+       spec->eapd_switch = 0;
+}
+
+static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               codec->no_jack_detect = 1;
+}
+
+
+static void stac92hd73xx_disable_automute(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       spec->gen.suppress_auto_mute = 1;
+}
+
+static const struct hda_fixup stac92hd73xx_fixups[] = {
+       [STAC_92HD73XX_REF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_fixup_ref,
+       },
+       [STAC_DELL_M6_AMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_fixup_dell_m6_amic,
+       },
+       [STAC_DELL_M6_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_fixup_dell_m6_dmic,
+       },
+       [STAC_DELL_M6_BOTH] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_fixup_dell_m6_both,
+       },
+       [STAC_DELL_EQ]  = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_fixup_dell_eq,
+       },
+       [STAC_ALIENWARE_M17X] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_fixup_alienware_m17x,
+       },
+       [STAC_ELO_VUPOINT_15MX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_disable_automute,
+       },
+       [STAC_92HD73XX_INTEL] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = intel_dg45id_pin_configs,
+       },
+       [STAC_92HD73XX_NO_JD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd73xx_fixup_no_jd,
+       },
+       [STAC_92HD89XX_HP_FRONT_JACK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac92hd89xx_hp_front_jack_pin_configs,
+       },
+       [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs,
+       },
+       [STAC_92HD73XX_ASUS_MOBO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* enable 5.1 and SPDIF out */
+                       { 0x0c, 0x01014411 },
+                       { 0x0d, 0x01014410 },
+                       { 0x0e, 0x01014412 },
+                       { 0x22, 0x014b1180 },
+                       { }
+               }
+       },
+};
+
+static const struct hda_model_fixup stac92hd73xx_models[] = {
+       { .id = STAC_92HD73XX_NO_JD, .name = "no-jd" },
+       { .id = STAC_92HD73XX_REF, .name = "ref" },
+       { .id = STAC_92HD73XX_INTEL, .name = "intel" },
+       { .id = STAC_DELL_M6_AMIC, .name = "dell-m6-amic" },
+       { .id = STAC_DELL_M6_DMIC, .name = "dell-m6-dmic" },
+       { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
+       { .id = STAC_DELL_EQ, .name = "dell-eq" },
+       { .id = STAC_ALIENWARE_M17X, .name = "alienware" },
+       { .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" },
+       { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
+       {}
+};
+
+static const struct hda_quirk stac92hd73xx_fixup_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                               "DFI LanParty", STAC_92HD73XX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                               "DFI LanParty", STAC_92HD73XX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5001,
+                               "Intel DP45SG", STAC_92HD73XX_INTEL),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5002,
+                               "Intel DG45ID", STAC_92HD73XX_INTEL),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5003,
+                               "Intel DG45FC", STAC_92HD73XX_INTEL),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
+                               "Dell Studio 1535", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
+                               "unknown Dell", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
+                               "unknown Dell", STAC_DELL_M6_BOTH),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
+                               "unknown Dell", STAC_DELL_M6_BOTH),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
+                               "unknown Dell", STAC_DELL_M6_AMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
+                               "unknown Dell", STAC_DELL_M6_AMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
+                               "unknown Dell", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0272,
+                               "unknown Dell", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f,
+                               "Dell Studio 1537", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
+                               "Dell Studio 17", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be,
+                               "Dell Studio 1555", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd,
+                               "Dell Studio 1557", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
+                               "Dell Studio XPS 1645", STAC_DELL_M6_DMIC),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
+                               "Dell Studio 1558", STAC_DELL_M6_DMIC),
+       /* codec SSID matching */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1,
+                     "Alienware M17x", STAC_ALIENWARE_M17X),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
+                     "Alienware M17x", STAC_ALIENWARE_M17X),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
+                     "Alienware M17x R3", STAC_DELL_EQ),
+       SND_PCI_QUIRK(0x1059, 0x1011,
+                     "ELO VuPoint 15MX", STAC_ELO_VUPOINT_15MX),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927,
+                               "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
+                               "unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10",
+                     STAC_92HD73XX_ASUS_MOBO),
+       {} /* terminator */
+};
+
+static const struct hda_pintbl ref92hd83xxx_pin_configs[] = {
+       { 0x0a, 0x02214030 },
+       { 0x0b, 0x02211010 },
+       { 0x0c, 0x02a19020 },
+       { 0x0d, 0x02170130 },
+       { 0x0e, 0x01014050 },
+       { 0x0f, 0x01819040 },
+       { 0x10, 0x01014020 },
+       { 0x11, 0x90a3014e },
+       { 0x1f, 0x01451160 },
+       { 0x20, 0x98560170 },
+       {}
+};
+
+static const struct hda_pintbl dell_s14_pin_configs[] = {
+       { 0x0a, 0x0221403f },
+       { 0x0b, 0x0221101f },
+       { 0x0c, 0x02a19020 },
+       { 0x0d, 0x90170110 },
+       { 0x0e, 0x40f000f0 },
+       { 0x0f, 0x40f000f0 },
+       { 0x10, 0x40f000f0 },
+       { 0x11, 0x90a60160 },
+       { 0x1f, 0x40f000f0 },
+       { 0x20, 0x40f000f0 },
+       {}
+};
+
+static const struct hda_pintbl dell_vostro_3500_pin_configs[] = {
+       { 0x0a, 0x02a11020 },
+       { 0x0b, 0x0221101f },
+       { 0x0c, 0x400000f0 },
+       { 0x0d, 0x90170110 },
+       { 0x0e, 0x400000f1 },
+       { 0x0f, 0x400000f2 },
+       { 0x10, 0x400000f3 },
+       { 0x11, 0x90a60160 },
+       { 0x1f, 0x400000f4 },
+       { 0x20, 0x400000f5 },
+       {}
+};
+
+static const struct hda_pintbl hp_dv7_4000_pin_configs[] = {
+       { 0x0a, 0x03a12050 },
+       { 0x0b, 0x0321201f },
+       { 0x0c, 0x40f000f0 },
+       { 0x0d, 0x90170110 },
+       { 0x0e, 0x40f000f0 },
+       { 0x0f, 0x40f000f0 },
+       { 0x10, 0x90170110 },
+       { 0x11, 0xd5a30140 },
+       { 0x1f, 0x40f000f0 },
+       { 0x20, 0x40f000f0 },
+       {}
+};
+
+static const struct hda_pintbl hp_zephyr_pin_configs[] = {
+       { 0x0a, 0x01813050 },
+       { 0x0b, 0x0421201f },
+       { 0x0c, 0x04a1205e },
+       { 0x0d, 0x96130310 },
+       { 0x0e, 0x96130310 },
+       { 0x0f, 0x0101401f },
+       { 0x10, 0x1111611f },
+       { 0x11, 0xd5a30130 },
+       {}
+};
+
+static const struct hda_pintbl hp_cNB11_intquad_pin_configs[] = {
+       { 0x0a, 0x40f000f0 },
+       { 0x0b, 0x0221101f },
+       { 0x0c, 0x02a11020 },
+       { 0x0d, 0x92170110 },
+       { 0x0e, 0x40f000f0 },
+       { 0x0f, 0x92170110 },
+       { 0x10, 0x40f000f0 },
+       { 0x11, 0xd5a30130 },
+       { 0x1f, 0x40f000f0 },
+       { 0x20, 0x40f000f0 },
+       {}
+};
+
+static void stac92hd83xxx_fixup_hp(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       if (hp_bnb2011_with_dock(codec)) {
+               snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f);
+               snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e);
+       }
+
+       if (find_mute_led_cfg(codec, spec->default_polarity))
+               codec_dbg(codec, "mute LED gpio %d polarity %d\n",
+                               spec->gpio_led,
+                               spec->gpio_led_polarity);
+
+       /* allow auto-switching of dock line-in */
+       spec->gen.line_in_auto_switch = true;
+}
+
+static void stac92hd83xxx_fixup_hp_zephyr(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       snd_hda_apply_pincfgs(codec, hp_zephyr_pin_configs);
+       snd_hda_add_verbs(codec, stac92hd83xxx_hp_zephyr_init);
+}
+
+static void stac92hd83xxx_fixup_hp_led(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->default_polarity = 0;
+}
+
+static void stac92hd83xxx_fixup_hp_inv_led(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->default_polarity = 1;
+}
+
+static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
+               /* resetting controller clears GPIO, so we need to keep on */
+               codec->core.power_caps &= ~AC_PWRST_CLKSTOP;
+       }
+}
+
+static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gpio_led = 0x10; /* GPIO4 */
+               spec->default_polarity = 0;
+       }
+}
+
+static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->headset_jack = 1;
+}
+
+static void stac92hd83xxx_fixup_gpio10_eapd(struct hda_codec *codec,
+                                           const struct hda_fixup *fix,
+                                           int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       spec->eapd_mask = spec->gpio_mask = spec->gpio_dir =
+               spec->gpio_data = 0x10;
+       spec->eapd_switch = 0;
+}
+
+static void hp_envy_ts_fixup_dac_bind(struct hda_codec *codec,
+                                           const struct hda_fixup *fix,
+                                           int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       static const hda_nid_t preferred_pairs[] = {
+               0xd, 0x13,
+               0
+       };
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       spec->gen.preferred_dacs = preferred_pairs;
+}
+
+static const struct hda_verb hp_bnb13_eq_verbs[] = {
+       /* 44.1KHz base */
+       { 0x22, 0x7A6, 0x3E },
+       { 0x22, 0x7A7, 0x68 },
+       { 0x22, 0x7A8, 0x17 },
+       { 0x22, 0x7A9, 0x3E },
+       { 0x22, 0x7AA, 0x68 },
+       { 0x22, 0x7AB, 0x17 },
+       { 0x22, 0x7AC, 0x00 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x83 },
+       { 0x22, 0x7A7, 0x2F },
+       { 0x22, 0x7A8, 0xD1 },
+       { 0x22, 0x7A9, 0x83 },
+       { 0x22, 0x7AA, 0x2F },
+       { 0x22, 0x7AB, 0xD1 },
+       { 0x22, 0x7AC, 0x01 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3E },
+       { 0x22, 0x7A7, 0x68 },
+       { 0x22, 0x7A8, 0x17 },
+       { 0x22, 0x7A9, 0x3E },
+       { 0x22, 0x7AA, 0x68 },
+       { 0x22, 0x7AB, 0x17 },
+       { 0x22, 0x7AC, 0x02 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x7C },
+       { 0x22, 0x7A7, 0xC6 },
+       { 0x22, 0x7A8, 0x0C },
+       { 0x22, 0x7A9, 0x7C },
+       { 0x22, 0x7AA, 0xC6 },
+       { 0x22, 0x7AB, 0x0C },
+       { 0x22, 0x7AC, 0x03 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xC3 },
+       { 0x22, 0x7A7, 0x25 },
+       { 0x22, 0x7A8, 0xAF },
+       { 0x22, 0x7A9, 0xC3 },
+       { 0x22, 0x7AA, 0x25 },
+       { 0x22, 0x7AB, 0xAF },
+       { 0x22, 0x7AC, 0x04 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3E },
+       { 0x22, 0x7A7, 0x85 },
+       { 0x22, 0x7A8, 0x73 },
+       { 0x22, 0x7A9, 0x3E },
+       { 0x22, 0x7AA, 0x85 },
+       { 0x22, 0x7AB, 0x73 },
+       { 0x22, 0x7AC, 0x05 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x85 },
+       { 0x22, 0x7A7, 0x39 },
+       { 0x22, 0x7A8, 0xC7 },
+       { 0x22, 0x7A9, 0x85 },
+       { 0x22, 0x7AA, 0x39 },
+       { 0x22, 0x7AB, 0xC7 },
+       { 0x22, 0x7AC, 0x06 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3C },
+       { 0x22, 0x7A7, 0x90 },
+       { 0x22, 0x7A8, 0xB0 },
+       { 0x22, 0x7A9, 0x3C },
+       { 0x22, 0x7AA, 0x90 },
+       { 0x22, 0x7AB, 0xB0 },
+       { 0x22, 0x7AC, 0x07 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x7A },
+       { 0x22, 0x7A7, 0xC6 },
+       { 0x22, 0x7A8, 0x39 },
+       { 0x22, 0x7A9, 0x7A },
+       { 0x22, 0x7AA, 0xC6 },
+       { 0x22, 0x7AB, 0x39 },
+       { 0x22, 0x7AC, 0x08 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xC4 },
+       { 0x22, 0x7A7, 0xE9 },
+       { 0x22, 0x7A8, 0xDC },
+       { 0x22, 0x7A9, 0xC4 },
+       { 0x22, 0x7AA, 0xE9 },
+       { 0x22, 0x7AB, 0xDC },
+       { 0x22, 0x7AC, 0x09 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3D },
+       { 0x22, 0x7A7, 0xE1 },
+       { 0x22, 0x7A8, 0x0D },
+       { 0x22, 0x7A9, 0x3D },
+       { 0x22, 0x7AA, 0xE1 },
+       { 0x22, 0x7AB, 0x0D },
+       { 0x22, 0x7AC, 0x0A },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x89 },
+       { 0x22, 0x7A7, 0xB6 },
+       { 0x22, 0x7A8, 0xEB },
+       { 0x22, 0x7A9, 0x89 },
+       { 0x22, 0x7AA, 0xB6 },
+       { 0x22, 0x7AB, 0xEB },
+       { 0x22, 0x7AC, 0x0B },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x39 },
+       { 0x22, 0x7A7, 0x9D },
+       { 0x22, 0x7A8, 0xFE },
+       { 0x22, 0x7A9, 0x39 },
+       { 0x22, 0x7AA, 0x9D },
+       { 0x22, 0x7AB, 0xFE },
+       { 0x22, 0x7AC, 0x0C },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x76 },
+       { 0x22, 0x7A7, 0x49 },
+       { 0x22, 0x7A8, 0x15 },
+       { 0x22, 0x7A9, 0x76 },
+       { 0x22, 0x7AA, 0x49 },
+       { 0x22, 0x7AB, 0x15 },
+       { 0x22, 0x7AC, 0x0D },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xC8 },
+       { 0x22, 0x7A7, 0x80 },
+       { 0x22, 0x7A8, 0xF5 },
+       { 0x22, 0x7A9, 0xC8 },
+       { 0x22, 0x7AA, 0x80 },
+       { 0x22, 0x7AB, 0xF5 },
+       { 0x22, 0x7AC, 0x0E },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x40 },
+       { 0x22, 0x7A7, 0x00 },
+       { 0x22, 0x7A8, 0x00 },
+       { 0x22, 0x7A9, 0x40 },
+       { 0x22, 0x7AA, 0x00 },
+       { 0x22, 0x7AB, 0x00 },
+       { 0x22, 0x7AC, 0x0F },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x90 },
+       { 0x22, 0x7A7, 0x68 },
+       { 0x22, 0x7A8, 0xF1 },
+       { 0x22, 0x7A9, 0x90 },
+       { 0x22, 0x7AA, 0x68 },
+       { 0x22, 0x7AB, 0xF1 },
+       { 0x22, 0x7AC, 0x10 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x34 },
+       { 0x22, 0x7A7, 0x47 },
+       { 0x22, 0x7A8, 0x6C },
+       { 0x22, 0x7A9, 0x34 },
+       { 0x22, 0x7AA, 0x47 },
+       { 0x22, 0x7AB, 0x6C },
+       { 0x22, 0x7AC, 0x11 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x6F },
+       { 0x22, 0x7A7, 0x97 },
+       { 0x22, 0x7A8, 0x0F },
+       { 0x22, 0x7A9, 0x6F },
+       { 0x22, 0x7AA, 0x97 },
+       { 0x22, 0x7AB, 0x0F },
+       { 0x22, 0x7AC, 0x12 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xCB },
+       { 0x22, 0x7A7, 0xB8 },
+       { 0x22, 0x7A8, 0x94 },
+       { 0x22, 0x7A9, 0xCB },
+       { 0x22, 0x7AA, 0xB8 },
+       { 0x22, 0x7AB, 0x94 },
+       { 0x22, 0x7AC, 0x13 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x40 },
+       { 0x22, 0x7A7, 0x00 },
+       { 0x22, 0x7A8, 0x00 },
+       { 0x22, 0x7A9, 0x40 },
+       { 0x22, 0x7AA, 0x00 },
+       { 0x22, 0x7AB, 0x00 },
+       { 0x22, 0x7AC, 0x14 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x95 },
+       { 0x22, 0x7A7, 0x76 },
+       { 0x22, 0x7A8, 0x5B },
+       { 0x22, 0x7A9, 0x95 },
+       { 0x22, 0x7AA, 0x76 },
+       { 0x22, 0x7AB, 0x5B },
+       { 0x22, 0x7AC, 0x15 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x31 },
+       { 0x22, 0x7A7, 0xAC },
+       { 0x22, 0x7A8, 0x31 },
+       { 0x22, 0x7A9, 0x31 },
+       { 0x22, 0x7AA, 0xAC },
+       { 0x22, 0x7AB, 0x31 },
+       { 0x22, 0x7AC, 0x16 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x6A },
+       { 0x22, 0x7A7, 0x89 },
+       { 0x22, 0x7A8, 0xA5 },
+       { 0x22, 0x7A9, 0x6A },
+       { 0x22, 0x7AA, 0x89 },
+       { 0x22, 0x7AB, 0xA5 },
+       { 0x22, 0x7AC, 0x17 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xCE },
+       { 0x22, 0x7A7, 0x53 },
+       { 0x22, 0x7A8, 0xCF },
+       { 0x22, 0x7A9, 0xCE },
+       { 0x22, 0x7AA, 0x53 },
+       { 0x22, 0x7AB, 0xCF },
+       { 0x22, 0x7AC, 0x18 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x40 },
+       { 0x22, 0x7A7, 0x00 },
+       { 0x22, 0x7A8, 0x00 },
+       { 0x22, 0x7A9, 0x40 },
+       { 0x22, 0x7AA, 0x00 },
+       { 0x22, 0x7AB, 0x00 },
+       { 0x22, 0x7AC, 0x19 },
+       { 0x22, 0x7AD, 0x80 },
+       /* 48KHz base */
+       { 0x22, 0x7A6, 0x3E },
+       { 0x22, 0x7A7, 0x88 },
+       { 0x22, 0x7A8, 0xDC },
+       { 0x22, 0x7A9, 0x3E },
+       { 0x22, 0x7AA, 0x88 },
+       { 0x22, 0x7AB, 0xDC },
+       { 0x22, 0x7AC, 0x1A },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x82 },
+       { 0x22, 0x7A7, 0xEE },
+       { 0x22, 0x7A8, 0x46 },
+       { 0x22, 0x7A9, 0x82 },
+       { 0x22, 0x7AA, 0xEE },
+       { 0x22, 0x7AB, 0x46 },
+       { 0x22, 0x7AC, 0x1B },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3E },
+       { 0x22, 0x7A7, 0x88 },
+       { 0x22, 0x7A8, 0xDC },
+       { 0x22, 0x7A9, 0x3E },
+       { 0x22, 0x7AA, 0x88 },
+       { 0x22, 0x7AB, 0xDC },
+       { 0x22, 0x7AC, 0x1C },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x7D },
+       { 0x22, 0x7A7, 0x09 },
+       { 0x22, 0x7A8, 0x28 },
+       { 0x22, 0x7A9, 0x7D },
+       { 0x22, 0x7AA, 0x09 },
+       { 0x22, 0x7AB, 0x28 },
+       { 0x22, 0x7AC, 0x1D },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xC2 },
+       { 0x22, 0x7A7, 0xE5 },
+       { 0x22, 0x7A8, 0xB4 },
+       { 0x22, 0x7A9, 0xC2 },
+       { 0x22, 0x7AA, 0xE5 },
+       { 0x22, 0x7AB, 0xB4 },
+       { 0x22, 0x7AC, 0x1E },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3E },
+       { 0x22, 0x7A7, 0xA3 },
+       { 0x22, 0x7A8, 0x1F },
+       { 0x22, 0x7A9, 0x3E },
+       { 0x22, 0x7AA, 0xA3 },
+       { 0x22, 0x7AB, 0x1F },
+       { 0x22, 0x7AC, 0x1F },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x84 },
+       { 0x22, 0x7A7, 0xCA },
+       { 0x22, 0x7A8, 0xF1 },
+       { 0x22, 0x7A9, 0x84 },
+       { 0x22, 0x7AA, 0xCA },
+       { 0x22, 0x7AB, 0xF1 },
+       { 0x22, 0x7AC, 0x20 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3C },
+       { 0x22, 0x7A7, 0xD5 },
+       { 0x22, 0x7A8, 0x9C },
+       { 0x22, 0x7A9, 0x3C },
+       { 0x22, 0x7AA, 0xD5 },
+       { 0x22, 0x7AB, 0x9C },
+       { 0x22, 0x7AC, 0x21 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x7B },
+       { 0x22, 0x7A7, 0x35 },
+       { 0x22, 0x7A8, 0x0F },
+       { 0x22, 0x7A9, 0x7B },
+       { 0x22, 0x7AA, 0x35 },
+       { 0x22, 0x7AB, 0x0F },
+       { 0x22, 0x7AC, 0x22 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xC4 },
+       { 0x22, 0x7A7, 0x87 },
+       { 0x22, 0x7A8, 0x45 },
+       { 0x22, 0x7A9, 0xC4 },
+       { 0x22, 0x7AA, 0x87 },
+       { 0x22, 0x7AB, 0x45 },
+       { 0x22, 0x7AC, 0x23 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3E },
+       { 0x22, 0x7A7, 0x0A },
+       { 0x22, 0x7A8, 0x78 },
+       { 0x22, 0x7A9, 0x3E },
+       { 0x22, 0x7AA, 0x0A },
+       { 0x22, 0x7AB, 0x78 },
+       { 0x22, 0x7AC, 0x24 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x88 },
+       { 0x22, 0x7A7, 0xE2 },
+       { 0x22, 0x7A8, 0x05 },
+       { 0x22, 0x7A9, 0x88 },
+       { 0x22, 0x7AA, 0xE2 },
+       { 0x22, 0x7AB, 0x05 },
+       { 0x22, 0x7AC, 0x25 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x3A },
+       { 0x22, 0x7A7, 0x1A },
+       { 0x22, 0x7A8, 0xA3 },
+       { 0x22, 0x7A9, 0x3A },
+       { 0x22, 0x7AA, 0x1A },
+       { 0x22, 0x7AB, 0xA3 },
+       { 0x22, 0x7AC, 0x26 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x77 },
+       { 0x22, 0x7A7, 0x1D },
+       { 0x22, 0x7A8, 0xFB },
+       { 0x22, 0x7A9, 0x77 },
+       { 0x22, 0x7AA, 0x1D },
+       { 0x22, 0x7AB, 0xFB },
+       { 0x22, 0x7AC, 0x27 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xC7 },
+       { 0x22, 0x7A7, 0xDA },
+       { 0x22, 0x7A8, 0xE5 },
+       { 0x22, 0x7A9, 0xC7 },
+       { 0x22, 0x7AA, 0xDA },
+       { 0x22, 0x7AB, 0xE5 },
+       { 0x22, 0x7AC, 0x28 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x40 },
+       { 0x22, 0x7A7, 0x00 },
+       { 0x22, 0x7A8, 0x00 },
+       { 0x22, 0x7A9, 0x40 },
+       { 0x22, 0x7AA, 0x00 },
+       { 0x22, 0x7AB, 0x00 },
+       { 0x22, 0x7AC, 0x29 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x8E },
+       { 0x22, 0x7A7, 0xD7 },
+       { 0x22, 0x7A8, 0x22 },
+       { 0x22, 0x7A9, 0x8E },
+       { 0x22, 0x7AA, 0xD7 },
+       { 0x22, 0x7AB, 0x22 },
+       { 0x22, 0x7AC, 0x2A },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x35 },
+       { 0x22, 0x7A7, 0x26 },
+       { 0x22, 0x7A8, 0xC6 },
+       { 0x22, 0x7A9, 0x35 },
+       { 0x22, 0x7AA, 0x26 },
+       { 0x22, 0x7AB, 0xC6 },
+       { 0x22, 0x7AC, 0x2B },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x71 },
+       { 0x22, 0x7A7, 0x28 },
+       { 0x22, 0x7A8, 0xDE },
+       { 0x22, 0x7A9, 0x71 },
+       { 0x22, 0x7AA, 0x28 },
+       { 0x22, 0x7AB, 0xDE },
+       { 0x22, 0x7AC, 0x2C },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xCA },
+       { 0x22, 0x7A7, 0xD9 },
+       { 0x22, 0x7A8, 0x3A },
+       { 0x22, 0x7A9, 0xCA },
+       { 0x22, 0x7AA, 0xD9 },
+       { 0x22, 0x7AB, 0x3A },
+       { 0x22, 0x7AC, 0x2D },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x40 },
+       { 0x22, 0x7A7, 0x00 },
+       { 0x22, 0x7A8, 0x00 },
+       { 0x22, 0x7A9, 0x40 },
+       { 0x22, 0x7AA, 0x00 },
+       { 0x22, 0x7AB, 0x00 },
+       { 0x22, 0x7AC, 0x2E },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x93 },
+       { 0x22, 0x7A7, 0x5E },
+       { 0x22, 0x7A8, 0xD8 },
+       { 0x22, 0x7A9, 0x93 },
+       { 0x22, 0x7AA, 0x5E },
+       { 0x22, 0x7AB, 0xD8 },
+       { 0x22, 0x7AC, 0x2F },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x32 },
+       { 0x22, 0x7A7, 0xB7 },
+       { 0x22, 0x7A8, 0xB1 },
+       { 0x22, 0x7A9, 0x32 },
+       { 0x22, 0x7AA, 0xB7 },
+       { 0x22, 0x7AB, 0xB1 },
+       { 0x22, 0x7AC, 0x30 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x6C },
+       { 0x22, 0x7A7, 0xA1 },
+       { 0x22, 0x7A8, 0x28 },
+       { 0x22, 0x7A9, 0x6C },
+       { 0x22, 0x7AA, 0xA1 },
+       { 0x22, 0x7AB, 0x28 },
+       { 0x22, 0x7AC, 0x31 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0xCD },
+       { 0x22, 0x7A7, 0x48 },
+       { 0x22, 0x7A8, 0x4F },
+       { 0x22, 0x7A9, 0xCD },
+       { 0x22, 0x7AA, 0x48 },
+       { 0x22, 0x7AB, 0x4F },
+       { 0x22, 0x7AC, 0x32 },
+       { 0x22, 0x7AD, 0x80 },
+       { 0x22, 0x7A6, 0x40 },
+       { 0x22, 0x7A7, 0x00 },
+       { 0x22, 0x7A8, 0x00 },
+       { 0x22, 0x7A9, 0x40 },
+       { 0x22, 0x7AA, 0x00 },
+       { 0x22, 0x7AB, 0x00 },
+       { 0x22, 0x7AC, 0x33 },
+       { 0x22, 0x7AD, 0x80 },
+       /* common */
+       { 0x22, 0x782, 0xC1 },
+       { 0x22, 0x771, 0x2C },
+       { 0x22, 0x772, 0x2C },
+       { 0x22, 0x788, 0x04 },
+       { 0x01, 0x7B0, 0x08 },
+       {}
+};
+
+static const struct hda_fixup stac92hd83xxx_fixups[] = {
+       [STAC_92HD83XXX_REF] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = ref92hd83xxx_pin_configs,
+       },
+       [STAC_92HD83XXX_PWR_REF] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = ref92hd83xxx_pin_configs,
+       },
+       [STAC_DELL_S14] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_s14_pin_configs,
+       },
+       [STAC_DELL_VOSTRO_3500] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_vostro_3500_pin_configs,
+       },
+       [STAC_92HD83XXX_HP_cNB11_INTQUAD] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = hp_cNB11_intquad_pin_configs,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
+       [STAC_92HD83XXX_HP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_hp,
+       },
+       [STAC_HP_DV7_4000] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = hp_dv7_4000_pin_configs,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
+       [STAC_HP_ZEPHYR] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_hp_zephyr,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
+       [STAC_92HD83XXX_HP_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_hp_led,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
+       [STAC_92HD83XXX_HP_INV_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_hp_inv_led,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
+       [STAC_92HD83XXX_HP_MIC_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_hp_mic_led,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
+       [STAC_HP_LED_GPIO10] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_hp_led_gpio10,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP,
+       },
+       [STAC_92HD83XXX_HEADSET_JACK] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_headset_jack,
+       },
+       [STAC_HP_ENVY_BASS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x0f, 0x90170111 },
+                       {}
+               },
+       },
+       [STAC_HP_BNB13_EQ] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = hp_bnb13_eq_verbs,
+               .chained = true,
+               .chain_id = STAC_92HD83XXX_HP_MIC_LED,
+       },
+       [STAC_HP_ENVY_TS_BASS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       { 0x10, 0x92170111 },
+                       {}
+               },
+       },
+       [STAC_HP_ENVY_TS_DAC_BIND] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = hp_envy_ts_fixup_dac_bind,
+               .chained = true,
+               .chain_id = STAC_HP_ENVY_TS_BASS,
+       },
+       [STAC_92HD83XXX_GPIO10_EAPD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd83xxx_fixup_gpio10_eapd,
+       },
+};
+
+static const struct hda_model_fixup stac92hd83xxx_models[] = {
+       { .id = STAC_92HD83XXX_REF, .name = "ref" },
+       { .id = STAC_92HD83XXX_PWR_REF, .name = "mic-ref" },
+       { .id = STAC_DELL_S14, .name = "dell-s14" },
+       { .id = STAC_DELL_VOSTRO_3500, .name = "dell-vostro-3500" },
+       { .id = STAC_92HD83XXX_HP_cNB11_INTQUAD, .name = "hp_cNB11_intquad" },
+       { .id = STAC_HP_DV7_4000, .name = "hp-dv7-4000" },
+       { .id = STAC_HP_ZEPHYR, .name = "hp-zephyr" },
+       { .id = STAC_92HD83XXX_HP_LED, .name = "hp-led" },
+       { .id = STAC_92HD83XXX_HP_INV_LED, .name = "hp-inv-led" },
+       { .id = STAC_92HD83XXX_HP_MIC_LED, .name = "hp-mic-led" },
+       { .id = STAC_92HD83XXX_HEADSET_JACK, .name = "headset-jack" },
+       { .id = STAC_HP_ENVY_BASS, .name = "hp-envy-bass" },
+       { .id = STAC_HP_BNB13_EQ, .name = "hp-bnb13-eq" },
+       { .id = STAC_HP_ENVY_TS_BASS, .name = "hp-envy-ts-bass" },
+       {}
+};
+
+static const struct hda_quirk stac92hd83xxx_fixup_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_92HD83XXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_92HD83XXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
+                     "unknown Dell", STAC_DELL_S14),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0532,
+                     "Dell Latitude E6230", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0533,
+                     "Dell Latitude E6330", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0534,
+                     "Dell Latitude E6430", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0535,
+                     "Dell Latitude E6530", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053c,
+                     "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053d,
+                     "Dell Latitude E5530", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0549,
+                     "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x057d,
+                     "Dell Latitude E6430s", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0584,
+                     "Dell Latitude E6430U", STAC_92HD83XXX_HEADSET_JACK),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028,
+                     "Dell Vostro 3500", STAC_DELL_VOSTRO_3500),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659,
+                         "HP Pavilion dv7", STAC_HP_DV7_4000),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888,
+                         "HP Envy Spectre", STAC_HP_ENVY_BASS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899,
+                         "HP Folio 13", STAC_HP_LED_GPIO10),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
+                         "HP Folio", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1909,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190A,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190e,
+                         "HP ENVY TS", STAC_HP_ENVY_TS_BASS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1967,
+                         "HP ENVY TS", STAC_HP_ENVY_TS_DAC_BIND),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1940,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1941,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1942,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1943,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1944,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1945,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1946,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1948,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1949,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194A,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194B,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194C,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194E,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194F,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1950,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1951,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195A,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195B,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195C,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1991,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2103,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2104,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2105,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2106,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2107,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2108,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2109,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x210A,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x210B,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211C,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211D,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211E,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211F,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2120,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2121,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2122,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2123,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x213E,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x213F,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2140,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B2,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B3,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B5,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B6,
+                         "HP bNB13", STAC_HP_BNB13_EQ),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900,
+                         "HP", STAC_92HD83XXX_HP_MIC_LED),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2000,
+                         "HP", STAC_92HD83XXX_HP_MIC_LED),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2100,
+                         "HP", STAC_92HD83XXX_HP_MIC_LED),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593,
+                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561,
+                         "HP", STAC_HP_ZEPHYR),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660,
+                         "HP Mini", STAC_92HD83XXX_HP_LED),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E,
+                         "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a,
+                     "HP Mini", STAC_92HD83XXX_HP_LED),
+       SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP),
+       /* match both for 0xfa91 and 0xfa93 */
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_TOSHIBA, 0xfffd, 0xfa91,
+                     "Toshiba Satellite S50D", STAC_92HD83XXX_GPIO10_EAPD),
+       {} /* terminator */
+};
+
+/* HP dv7 bass switch - GPIO5 */
+#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info
+static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20);
+       return 0;
+}
+
+static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct sigmatel_spec *spec = codec->spec;
+       unsigned int gpio_data;
+
+       gpio_data = (spec->gpio_data & ~0x20) |
+               (ucontrol->value.integer.value[0] ? 0x20 : 0);
+       if (gpio_data == spec->gpio_data)
+               return 0;
+       spec->gpio_data = gpio_data;
+       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
+       return 1;
+}
+
+static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .info = stac_hp_bass_gpio_info,
+       .get = stac_hp_bass_gpio_get,
+       .put = stac_hp_bass_gpio_put,
+};
+
+static int stac_add_hp_bass_switch(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (!snd_hda_gen_add_kctl(&spec->gen, "Bass Speaker Playback Switch",
+                                 &stac_hp_bass_sw_ctrl))
+               return -ENOMEM;
+
+       spec->gpio_mask |= 0x20;
+       spec->gpio_dir |= 0x20;
+       spec->gpio_data |= 0x20;
+       return 0;
+}
+
+static const struct hda_pintbl ref92hd71bxx_pin_configs[] = {
+       { 0x0a, 0x02214030 },
+       { 0x0b, 0x02a19040 },
+       { 0x0c, 0x01a19020 },
+       { 0x0d, 0x01014010 },
+       { 0x0e, 0x0181302e },
+       { 0x0f, 0x01014010 },
+       { 0x14, 0x01019020 },
+       { 0x18, 0x90a000f0 },
+       { 0x19, 0x90a000f0 },
+       { 0x1e, 0x01452050 },
+       { 0x1f, 0x01452050 },
+       {}
+};
+
+static const struct hda_pintbl dell_m4_1_pin_configs[] = {
+       { 0x0a, 0x0421101f },
+       { 0x0b, 0x04a11221 },
+       { 0x0c, 0x40f000f0 },
+       { 0x0d, 0x90170110 },
+       { 0x0e, 0x23a1902e },
+       { 0x0f, 0x23014250 },
+       { 0x14, 0x40f000f0 },
+       { 0x18, 0x90a000f0 },
+       { 0x19, 0x40f000f0 },
+       { 0x1e, 0x4f0000f0 },
+       { 0x1f, 0x4f0000f0 },
+       {}
+};
+
+static const struct hda_pintbl dell_m4_2_pin_configs[] = {
+       { 0x0a, 0x0421101f },
+       { 0x0b, 0x04a11221 },
+       { 0x0c, 0x90a70330 },
+       { 0x0d, 0x90170110 },
+       { 0x0e, 0x23a1902e },
+       { 0x0f, 0x23014250 },
+       { 0x14, 0x40f000f0 },
+       { 0x18, 0x40f000f0 },
+       { 0x19, 0x40f000f0 },
+       { 0x1e, 0x044413b0 },
+       { 0x1f, 0x044413b0 },
+       {}
+};
+
+static const struct hda_pintbl dell_m4_3_pin_configs[] = {
+       { 0x0a, 0x0421101f },
+       { 0x0b, 0x04a11221 },
+       { 0x0c, 0x90a70330 },
+       { 0x0d, 0x90170110 },
+       { 0x0e, 0x40f000f0 },
+       { 0x0f, 0x40f000f0 },
+       { 0x14, 0x40f000f0 },
+       { 0x18, 0x90a000f0 },
+       { 0x19, 0x40f000f0 },
+       { 0x1e, 0x044413b0 },
+       { 0x1f, 0x044413b0 },
+       {}
+};
+
+static void stac92hd71bxx_fixup_ref(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       snd_hda_apply_pincfgs(codec, ref92hd71bxx_pin_configs);
+       spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0;
+}
+
+static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec,
+                                     const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct hda_jack_callback *jack;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       /* Enable VREF power saving on GPIO1 detect */
+       snd_hda_codec_write_cache(codec, codec->core.afg, 0,
+                                 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
+       jack = snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
+                                                  stac_vref_event);
+       if (!IS_ERR(jack))
+               jack->private_data = 0x02;
+
+       spec->gpio_mask |= 0x02;
+
+       /* enable internal microphone */
+       snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040);
+}
+
+static void stac92hd71bxx_fixup_hp_dv4(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       spec->gpio_led = 0x01;
+}
+
+static void stac92hd71bxx_fixup_hp_dv5(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       unsigned int cap;
+
+       switch (action) {
+       case HDA_FIXUP_ACT_PRE_PROBE:
+               snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
+               break;
+
+       case HDA_FIXUP_ACT_PROBE:
+               /* enable bass on HP dv7 */
+               cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP);
+               cap &= AC_GPIO_IO_COUNT;
+               if (cap >= 6)
+                       stac_add_hp_bass_switch(codec);
+               break;
+       }
+}
+
+static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec,
+                                      const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+       spec->gpio_led = 0x08;
+}
+
+static bool is_hp_output(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin);
+
+       /* count line-out, too, as BIOS sets often so */
+       return get_defcfg_connect(pin_cfg) != AC_JACK_PORT_NONE &&
+               (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
+                get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT);
+}
+
+static void fixup_hp_headphone(struct hda_codec *codec, hda_nid_t pin)
+{
+       unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin);
+
+       /* It was changed in the BIOS to just satisfy MS DTM.
+        * Lets turn it back into follower HP
+        */
+       pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) |
+               (AC_JACK_HP_OUT << AC_DEFCFG_DEVICE_SHIFT);
+       pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC | AC_DEFCFG_SEQUENCE))) |
+               0x1f;
+       snd_hda_codec_set_pincfg(codec, pin, pin_cfg);
+}
+
+static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       /* when both output A and F are assigned, these are supposedly
+        * dock and built-in headphones; fix both pin configs
+        */
+       if (is_hp_output(codec, 0x0a) && is_hp_output(codec, 0x0f)) {
+               fixup_hp_headphone(codec, 0x0a);
+               fixup_hp_headphone(codec, 0x0f);
+       }
+
+       if (find_mute_led_cfg(codec, 1))
+               codec_dbg(codec, "mute LED gpio %d polarity %d\n",
+                               spec->gpio_led,
+                               spec->gpio_led_polarity);
+
+}
+
+static const struct hda_fixup stac92hd71bxx_fixups[] = {
+       [STAC_92HD71BXX_REF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd71bxx_fixup_ref,
+       },
+       [STAC_DELL_M4_1] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_m4_1_pin_configs,
+       },
+       [STAC_DELL_M4_2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_m4_2_pin_configs,
+       },
+       [STAC_DELL_M4_3] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_m4_3_pin_configs,
+       },
+       [STAC_HP_M4] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd71bxx_fixup_hp_m4,
+               .chained = true,
+               .chain_id = STAC_92HD71BXX_HP,
+       },
+       [STAC_HP_DV4] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd71bxx_fixup_hp_dv4,
+               .chained = true,
+               .chain_id = STAC_HP_DV5,
+       },
+       [STAC_HP_DV5] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd71bxx_fixup_hp_dv5,
+               .chained = true,
+               .chain_id = STAC_92HD71BXX_HP,
+       },
+       [STAC_HP_HDX] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd71bxx_fixup_hp_hdx,
+               .chained = true,
+               .chain_id = STAC_92HD71BXX_HP,
+       },
+       [STAC_92HD71BXX_HP] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd71bxx_fixup_hp,
+       },
+};
+
+static const struct hda_model_fixup stac92hd71bxx_models[] = {
+       { .id = STAC_92HD71BXX_REF, .name = "ref" },
+       { .id = STAC_DELL_M4_1, .name = "dell-m4-1" },
+       { .id = STAC_DELL_M4_2, .name = "dell-m4-2" },
+       { .id = STAC_DELL_M4_3, .name = "dell-m4-3" },
+       { .id = STAC_HP_M4, .name = "hp-m4" },
+       { .id = STAC_HP_DV4, .name = "hp-dv4" },
+       { .id = STAC_HP_DV5, .name = "hp-dv5" },
+       { .id = STAC_HP_HDX, .name = "hp-hdx" },
+       { .id = STAC_HP_DV4, .name = "hp-dv4-1222nr" },
+       {}
+};
+
+static const struct hda_quirk stac92hd71bxx_fixup_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_92HD71BXX_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_92HD71BXX_REF),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x1720,
+                         "HP", STAC_HP_DV5),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
+                     "HP", STAC_HP_DV5),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
+                     "HP dv4-7", STAC_HP_DV4),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3600,
+                     "HP dv4-7", STAC_HP_DV5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610,
+                     "HP HDX", STAC_HP_HDX),  /* HDX18 */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
+                     "HP mini 1000", STAC_HP_M4),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b,
+                     "HP HDX", STAC_HP_HDX),  /* HDX16 */
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3620,
+                     "HP dv6", STAC_HP_DV5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061,
+                     "HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x363e,
+                     "HP DV6", STAC_HP_DV5),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010,
+                     "HP", STAC_HP_DV5),
+       SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD71BXX_HP),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
+                               "unknown Dell", STAC_DELL_M4_1),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
+                               "unknown Dell", STAC_DELL_M4_1),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
+                               "unknown Dell", STAC_DELL_M4_1),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
+                               "unknown Dell", STAC_DELL_M4_1),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
+                               "unknown Dell", STAC_DELL_M4_1),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
+                               "unknown Dell", STAC_DELL_M4_1),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
+                               "unknown Dell", STAC_DELL_M4_1),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
+                               "unknown Dell", STAC_DELL_M4_2),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
+                               "unknown Dell", STAC_DELL_M4_2),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
+                               "unknown Dell", STAC_DELL_M4_2),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
+                               "unknown Dell", STAC_DELL_M4_2),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02aa,
+                               "unknown Dell", STAC_DELL_M4_3),
+       {} /* terminator */
+};
+
+static const struct hda_pintbl ref922x_pin_configs[] = {
+       { 0x0a, 0x01014010 },
+       { 0x0b, 0x01016011 },
+       { 0x0c, 0x01012012 },
+       { 0x0d, 0x0221401f },
+       { 0x0e, 0x01813122 },
+       { 0x0f, 0x01011014 },
+       { 0x10, 0x01441030 },
+       { 0x11, 0x01c41030 },
+       { 0x15, 0x40000100 },
+       { 0x1b, 0x40000100 },
+       {}
+};
+
+/*
+    STAC 922X pin configs for
+    102801A7
+    102801AB
+    102801A9
+    102801D1
+    102801D2
+*/
+static const struct hda_pintbl dell_922x_d81_pin_configs[] = {
+       { 0x0a, 0x02214030 },
+       { 0x0b, 0x01a19021 },
+       { 0x0c, 0x01111012 },
+       { 0x0d, 0x01114010 },
+       { 0x0e, 0x02a19020 },
+       { 0x0f, 0x01117011 },
+       { 0x10, 0x400001f0 },
+       { 0x11, 0x400001f1 },
+       { 0x15, 0x01813122 },
+       { 0x1b, 0x400001f2 },
+       {}
+};
+
+/*
+    STAC 922X pin configs for
+    102801AC
+    102801D0
+*/
+static const struct hda_pintbl dell_922x_d82_pin_configs[] = {
+       { 0x0a, 0x02214030 },
+       { 0x0b, 0x01a19021 },
+       { 0x0c, 0x01111012 },
+       { 0x0d, 0x01114010 },
+       { 0x0e, 0x02a19020 },
+       { 0x0f, 0x01117011 },
+       { 0x10, 0x01451140 },
+       { 0x11, 0x400001f0 },
+       { 0x15, 0x01813122 },
+       { 0x1b, 0x400001f1 },
+       {}
+};
+
+/*
+    STAC 922X pin configs for
+    102801BF
+*/
+static const struct hda_pintbl dell_922x_m81_pin_configs[] = {
+       { 0x0a, 0x0321101f },
+       { 0x0b, 0x01112024 },
+       { 0x0c, 0x01111222 },
+       { 0x0d, 0x91174220 },
+       { 0x0e, 0x03a11050 },
+       { 0x0f, 0x01116221 },
+       { 0x10, 0x90a70330 },
+       { 0x11, 0x01452340 },
+       { 0x15, 0x40C003f1 },
+       { 0x1b, 0x405003f0 },
+       {}
+};
+
+/*
+    STAC 9221 A1 pin configs for
+    102801D7 (Dell XPS M1210)
+*/
+static const struct hda_pintbl dell_922x_m82_pin_configs[] = {
+       { 0x0a, 0x02211211 },
+       { 0x0b, 0x408103ff },
+       { 0x0c, 0x02a1123e },
+       { 0x0d, 0x90100310 },
+       { 0x0e, 0x408003f1 },
+       { 0x0f, 0x0221121f },
+       { 0x10, 0x03451340 },
+       { 0x11, 0x40c003f2 },
+       { 0x15, 0x508003f3 },
+       { 0x1b, 0x405003f4 },
+       {}
+};
+
+static const struct hda_pintbl d945gtp3_pin_configs[] = {
+       { 0x0a, 0x0221401f },
+       { 0x0b, 0x01a19022 },
+       { 0x0c, 0x01813021 },
+       { 0x0d, 0x01014010 },
+       { 0x0e, 0x40000100 },
+       { 0x0f, 0x40000100 },
+       { 0x10, 0x40000100 },
+       { 0x11, 0x40000100 },
+       { 0x15, 0x02a19120 },
+       { 0x1b, 0x40000100 },
+       {}
+};
+
+static const struct hda_pintbl d945gtp5_pin_configs[] = {
+       { 0x0a, 0x0221401f },
+       { 0x0b, 0x01011012 },
+       { 0x0c, 0x01813024 },
+       { 0x0d, 0x01014010 },
+       { 0x0e, 0x01a19021 },
+       { 0x0f, 0x01016011 },
+       { 0x10, 0x01452130 },
+       { 0x11, 0x40000100 },
+       { 0x15, 0x02a19320 },
+       { 0x1b, 0x40000100 },
+       {}
+};
+
+static const struct hda_pintbl intel_mac_v1_pin_configs[] = {
+       { 0x0a, 0x0121e21f },
+       { 0x0b, 0x400000ff },
+       { 0x0c, 0x9017e110 },
+       { 0x0d, 0x400000fd },
+       { 0x0e, 0x400000fe },
+       { 0x0f, 0x0181e020 },
+       { 0x10, 0x1145e030 },
+       { 0x11, 0x11c5e240 },
+       { 0x15, 0x400000fc },
+       { 0x1b, 0x400000fb },
+       {}
+};
+
+static const struct hda_pintbl intel_mac_v2_pin_configs[] = {
+       { 0x0a, 0x0121e21f },
+       { 0x0b, 0x90a7012e },
+       { 0x0c, 0x9017e110 },
+       { 0x0d, 0x400000fd },
+       { 0x0e, 0x400000fe },
+       { 0x0f, 0x0181e020 },
+       { 0x10, 0x1145e230 },
+       { 0x11, 0x500000fa },
+       { 0x15, 0x400000fc },
+       { 0x1b, 0x400000fb },
+       {}
+};
+
+static const struct hda_pintbl intel_mac_v3_pin_configs[] = {
+       { 0x0a, 0x0121e21f },
+       { 0x0b, 0x90a7012e },
+       { 0x0c, 0x9017e110 },
+       { 0x0d, 0x400000fd },
+       { 0x0e, 0x400000fe },
+       { 0x0f, 0x0181e020 },
+       { 0x10, 0x1145e230 },
+       { 0x11, 0x11c5e240 },
+       { 0x15, 0x400000fc },
+       { 0x1b, 0x400000fb },
+       {}
+};
+
+static const struct hda_pintbl intel_mac_v4_pin_configs[] = {
+       { 0x0a, 0x0321e21f },
+       { 0x0b, 0x03a1e02e },
+       { 0x0c, 0x9017e110 },
+       { 0x0d, 0x9017e11f },
+       { 0x0e, 0x400000fe },
+       { 0x0f, 0x0381e020 },
+       { 0x10, 0x1345e230 },
+       { 0x11, 0x13c5e240 },
+       { 0x15, 0x400000fc },
+       { 0x1b, 0x400000fb },
+       {}
+};
+
+static const struct hda_pintbl intel_mac_v5_pin_configs[] = {
+       { 0x0a, 0x0321e21f },
+       { 0x0b, 0x03a1e02e },
+       { 0x0c, 0x9017e110 },
+       { 0x0d, 0x9017e11f },
+       { 0x0e, 0x400000fe },
+       { 0x0f, 0x0381e020 },
+       { 0x10, 0x1345e230 },
+       { 0x11, 0x13c5e240 },
+       { 0x15, 0x400000fc },
+       { 0x1b, 0x400000fb },
+       {}
+};
+
+static const struct hda_pintbl ecs202_pin_configs[] = {
+       { 0x0a, 0x0221401f },
+       { 0x0b, 0x02a19020 },
+       { 0x0c, 0x01a19020 },
+       { 0x0d, 0x01114010 },
+       { 0x0e, 0x408000f0 },
+       { 0x0f, 0x01813022 },
+       { 0x10, 0x074510a0 },
+       { 0x11, 0x40c400f1 },
+       { 0x15, 0x9037012e },
+       { 0x1b, 0x40e000f2 },
+       {}
+};
+
+/* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */
+static const struct hda_quirk stac922x_intel_mac_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3),
+       SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1),
+       SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2),
+       SND_PCI_QUIRK(0x106b, 0x0700, "Mac", STAC_INTEL_MAC_V2),
+       SND_PCI_QUIRK(0x106b, 0x0e00, "Mac", STAC_INTEL_MAC_V3),
+       SND_PCI_QUIRK(0x106b, 0x0f00, "Mac", STAC_INTEL_MAC_V3),
+       SND_PCI_QUIRK(0x106b, 0x1600, "Mac", STAC_INTEL_MAC_V3),
+       SND_PCI_QUIRK(0x106b, 0x1700, "Mac", STAC_INTEL_MAC_V3),
+       SND_PCI_QUIRK(0x106b, 0x0200, "Mac", STAC_INTEL_MAC_V3),
+       SND_PCI_QUIRK(0x106b, 0x1e00, "Mac", STAC_INTEL_MAC_V3),
+       SND_PCI_QUIRK(0x106b, 0x1a00, "Mac", STAC_INTEL_MAC_V4),
+       SND_PCI_QUIRK(0x106b, 0x0a00, "Mac", STAC_INTEL_MAC_V5),
+       SND_PCI_QUIRK(0x106b, 0x2200, "Mac", STAC_INTEL_MAC_V5),
+       {}
+};
+
+static const struct hda_fixup stac922x_fixups[];
+
+/* remap the fixup from codec SSID and apply it */
+static void stac922x_fixup_intel_mac_auto(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
+       snd_hda_pick_fixup(codec, NULL, stac922x_intel_mac_fixup_tbl,
+                          stac922x_fixups);
+       if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
+               snd_hda_apply_fixup(codec, action);
+}
+
+static void stac922x_fixup_intel_mac_gpio(struct hda_codec *codec,
+                                         const struct hda_fixup *fix,
+                                         int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               spec->gpio_mask = spec->gpio_dir = 0x03;
+               spec->gpio_data = 0x03;
+       }
+}
+
+static const struct hda_fixup stac922x_fixups[] = {
+       [STAC_D945_REF] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = ref922x_pin_configs,
+       },
+       [STAC_D945GTP3] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = d945gtp3_pin_configs,
+       },
+       [STAC_D945GTP5] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = d945gtp5_pin_configs,
+       },
+       [STAC_INTEL_MAC_AUTO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac922x_fixup_intel_mac_auto,
+       },
+       [STAC_INTEL_MAC_V1] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = intel_mac_v1_pin_configs,
+               .chained = true,
+               .chain_id = STAC_922X_INTEL_MAC_GPIO,
+       },
+       [STAC_INTEL_MAC_V2] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = intel_mac_v2_pin_configs,
+               .chained = true,
+               .chain_id = STAC_922X_INTEL_MAC_GPIO,
+       },
+       [STAC_INTEL_MAC_V3] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = intel_mac_v3_pin_configs,
+               .chained = true,
+               .chain_id = STAC_922X_INTEL_MAC_GPIO,
+       },
+       [STAC_INTEL_MAC_V4] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = intel_mac_v4_pin_configs,
+               .chained = true,
+               .chain_id = STAC_922X_INTEL_MAC_GPIO,
+       },
+       [STAC_INTEL_MAC_V5] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = intel_mac_v5_pin_configs,
+               .chained = true,
+               .chain_id = STAC_922X_INTEL_MAC_GPIO,
+       },
+       [STAC_922X_INTEL_MAC_GPIO] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac922x_fixup_intel_mac_gpio,
+       },
+       [STAC_ECS_202] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = ecs202_pin_configs,
+       },
+       [STAC_922X_DELL_D81] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_922x_d81_pin_configs,
+       },
+       [STAC_922X_DELL_D82] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_922x_d82_pin_configs,
+       },
+       [STAC_922X_DELL_M81] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_922x_m81_pin_configs,
+       },
+       [STAC_922X_DELL_M82] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_922x_m82_pin_configs,
+       },
+};
+
+static const struct hda_model_fixup stac922x_models[] = {
+       { .id = STAC_D945_REF, .name = "ref" },
+       { .id = STAC_D945GTP5, .name = "5stack" },
+       { .id = STAC_D945GTP3, .name = "3stack" },
+       { .id = STAC_INTEL_MAC_V1, .name = "intel-mac-v1" },
+       { .id = STAC_INTEL_MAC_V2, .name = "intel-mac-v2" },
+       { .id = STAC_INTEL_MAC_V3, .name = "intel-mac-v3" },
+       { .id = STAC_INTEL_MAC_V4, .name = "intel-mac-v4" },
+       { .id = STAC_INTEL_MAC_V5, .name = "intel-mac-v5" },
+       { .id = STAC_INTEL_MAC_AUTO, .name = "intel-mac-auto" },
+       { .id = STAC_ECS_202, .name = "ecs202" },
+       { .id = STAC_922X_DELL_D81, .name = "dell-d81" },
+       { .id = STAC_922X_DELL_D82, .name = "dell-d82" },
+       { .id = STAC_922X_DELL_M81, .name = "dell-m81" },
+       { .id = STAC_922X_DELL_M82, .name = "dell-m82" },
+       /* for backward compatibility */
+       { .id = STAC_INTEL_MAC_V3, .name = "macmini" },
+       { .id = STAC_INTEL_MAC_V5, .name = "macbook" },
+       { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro-v1" },
+       { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro" },
+       { .id = STAC_INTEL_MAC_V2, .name = "imac-intel" },
+       { .id = STAC_INTEL_MAC_V3, .name = "imac-intel-20" },
+       {}
+};
+
+static const struct hda_quirk stac922x_fixup_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_D945_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_D945_REF),
+       /* Intel 945G based systems */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
+                     "Intel D945G", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
+                     "Intel D945G", STAC_D945GTP3),
+       /* Intel D945G 5-stack systems */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
+                     "Intel D945G", STAC_D945GTP5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
+                     "Intel D945G", STAC_D945GTP5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
+                     "Intel D945G", STAC_D945GTP5),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
+                     "Intel D945G", STAC_D945GTP5),
+       /* Intel 945P based systems */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
+                     "Intel D945P", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
+                     "Intel D945P", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
+                     "Intel D945P", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
+                     "Intel D945P", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
+                     "Intel D945P", STAC_D945GTP3),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
+                     "Intel D945P", STAC_D945GTP5),
+       /* other intel */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204,
+                     "Intel D945", STAC_D945_REF),
+       /* other systems  */
+
+       /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
+       SND_PCI_QUIRK(0x8384, 0x7680, "Mac", STAC_INTEL_MAC_AUTO),
+
+       /* Dell systems  */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
+                     "unknown Dell", STAC_922X_DELL_D81),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
+                     "unknown Dell", STAC_922X_DELL_D81),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
+                     "unknown Dell", STAC_922X_DELL_D81),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
+                     "unknown Dell", STAC_922X_DELL_D82),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
+                     "unknown Dell", STAC_922X_DELL_M81),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
+                     "unknown Dell", STAC_922X_DELL_D82),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
+                     "unknown Dell", STAC_922X_DELL_D81),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
+                     "unknown Dell", STAC_922X_DELL_D81),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
+                     "Dell XPS M1210", STAC_922X_DELL_M82),
+       /* ECS/PC Chips boards */
+       SND_PCI_QUIRK_MASK(0x1019, 0xf000, 0x2000,
+                     "ECS/PC chips", STAC_ECS_202),
+       {} /* terminator */
+};
+
+static const struct hda_pintbl ref927x_pin_configs[] = {
+       { 0x0a, 0x02214020 },
+       { 0x0b, 0x02a19080 },
+       { 0x0c, 0x0181304e },
+       { 0x0d, 0x01014010 },
+       { 0x0e, 0x01a19040 },
+       { 0x0f, 0x01011012 },
+       { 0x10, 0x01016011 },
+       { 0x11, 0x0101201f },
+       { 0x12, 0x183301f0 },
+       { 0x13, 0x18a001f0 },
+       { 0x14, 0x18a001f0 },
+       { 0x21, 0x01442070 },
+       { 0x22, 0x01c42190 },
+       { 0x23, 0x40000100 },
+       {}
+};
+
+static const struct hda_pintbl d965_3st_pin_configs[] = {
+       { 0x0a, 0x0221401f },
+       { 0x0b, 0x02a19120 },
+       { 0x0c, 0x40000100 },
+       { 0x0d, 0x01014011 },
+       { 0x0e, 0x01a19021 },
+       { 0x0f, 0x01813024 },
+       { 0x10, 0x40000100 },
+       { 0x11, 0x40000100 },
+       { 0x12, 0x40000100 },
+       { 0x13, 0x40000100 },
+       { 0x14, 0x40000100 },
+       { 0x21, 0x40000100 },
+       { 0x22, 0x40000100 },
+       { 0x23, 0x40000100 },
+       {}
+};
+
+static const struct hda_pintbl d965_5st_pin_configs[] = {
+       { 0x0a, 0x02214020 },
+       { 0x0b, 0x02a19080 },
+       { 0x0c, 0x0181304e },
+       { 0x0d, 0x01014010 },
+       { 0x0e, 0x01a19040 },
+       { 0x0f, 0x01011012 },
+       { 0x10, 0x01016011 },
+       { 0x11, 0x40000100 },
+       { 0x12, 0x40000100 },
+       { 0x13, 0x40000100 },
+       { 0x14, 0x40000100 },
+       { 0x21, 0x01442070 },
+       { 0x22, 0x40000100 },
+       { 0x23, 0x40000100 },
+       {}
+};
+
+static const struct hda_pintbl d965_5st_no_fp_pin_configs[] = {
+       { 0x0a, 0x40000100 },
+       { 0x0b, 0x40000100 },
+       { 0x0c, 0x0181304e },
+       { 0x0d, 0x01014010 },
+       { 0x0e, 0x01a19040 },
+       { 0x0f, 0x01011012 },
+       { 0x10, 0x01016011 },
+       { 0x11, 0x40000100 },
+       { 0x12, 0x40000100 },
+       { 0x13, 0x40000100 },
+       { 0x14, 0x40000100 },
+       { 0x21, 0x01442070 },
+       { 0x22, 0x40000100 },
+       { 0x23, 0x40000100 },
+       {}
+};
+
+static const struct hda_pintbl dell_3st_pin_configs[] = {
+       { 0x0a, 0x02211230 },
+       { 0x0b, 0x02a11220 },
+       { 0x0c, 0x01a19040 },
+       { 0x0d, 0x01114210 },
+       { 0x0e, 0x01111212 },
+       { 0x0f, 0x01116211 },
+       { 0x10, 0x01813050 },
+       { 0x11, 0x01112214 },
+       { 0x12, 0x403003fa },
+       { 0x13, 0x90a60040 },
+       { 0x14, 0x90a60040 },
+       { 0x21, 0x404003fb },
+       { 0x22, 0x40c003fc },
+       { 0x23, 0x40000100 },
+       {}
+};
+
+static void stac927x_fixup_ref_no_jd(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       /* no jack detecion for ref-no-jd model */
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               codec->no_jack_detect = 1;
+}
+
+static void stac927x_fixup_ref(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               snd_hda_apply_pincfgs(codec, ref927x_pin_configs);
+               spec->eapd_mask = spec->gpio_mask = 0;
+               spec->gpio_dir = spec->gpio_data = 0;
+       }
+}
+
+static void stac927x_fixup_dell_dmic(struct hda_codec *codec,
+                                    const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       if (codec->core.subsystem_id != 0x1028022f) {
+               /* GPIO2 High = Enable EAPD */
+               spec->eapd_mask = spec->gpio_mask = 0x04;
+               spec->gpio_dir = spec->gpio_data = 0x04;
+       }
+
+       snd_hda_add_verbs(codec, dell_3st_core_init);
+       spec->volknob_init = 1;
+}
+
+static void stac927x_fixup_volknob(struct hda_codec *codec,
+                                  const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               snd_hda_add_verbs(codec, stac927x_volknob_core_init);
+               spec->volknob_init = 1;
+       }
+}
+
+static const struct hda_fixup stac927x_fixups[] = {
+       [STAC_D965_REF_NO_JD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac927x_fixup_ref_no_jd,
+               .chained = true,
+               .chain_id = STAC_D965_REF,
+       },
+       [STAC_D965_REF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac927x_fixup_ref,
+       },
+       [STAC_D965_3ST] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = d965_3st_pin_configs,
+               .chained = true,
+               .chain_id = STAC_D965_VERBS,
+       },
+       [STAC_D965_5ST] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = d965_5st_pin_configs,
+               .chained = true,
+               .chain_id = STAC_D965_VERBS,
+       },
+       [STAC_D965_VERBS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = d965_core_init,
+       },
+       [STAC_D965_5ST_NO_FP] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = d965_5st_no_fp_pin_configs,
+       },
+       [STAC_NEMO_DEFAULT] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = nemo_pin_configs,
+       },
+       [STAC_DELL_3ST] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_3st_pin_configs,
+               .chained = true,
+               .chain_id = STAC_927X_DELL_DMIC,
+       },
+       [STAC_DELL_BIOS] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* correct the front output jack as a hp out */
+                       { 0x0f, 0x0221101f },
+                       /* correct the front input jack as a mic */
+                       { 0x0e, 0x02a79130 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = STAC_927X_DELL_DMIC,
+       },
+       [STAC_DELL_BIOS_AMIC] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* configure the analog microphone on some laptops */
+                       { 0x0c, 0x90a79130 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = STAC_DELL_BIOS,
+       },
+       [STAC_DELL_BIOS_SPDIF] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* correct the device field to SPDIF out */
+                       { 0x21, 0x01442070 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = STAC_DELL_BIOS,
+       },
+       [STAC_927X_DELL_DMIC] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac927x_fixup_dell_dmic,
+       },
+       [STAC_927X_VOLKNOB] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac927x_fixup_volknob,
+       },
+};
+
+static const struct hda_model_fixup stac927x_models[] = {
+       { .id = STAC_D965_REF_NO_JD, .name = "ref-no-jd" },
+       { .id = STAC_D965_REF, .name = "ref" },
+       { .id = STAC_D965_3ST, .name = "3stack" },
+       { .id = STAC_D965_5ST, .name = "5stack" },
+       { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
+       { .id = STAC_DELL_3ST, .name = "dell-3stack" },
+       { .id = STAC_DELL_BIOS, .name = "dell-bios" },
+       { .id = STAC_NEMO_DEFAULT, .name = "nemo-default" },
+       { .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
+       { .id = STAC_927X_VOLKNOB, .name = "volknob" },
+       {}
+};
+
+static const struct hda_quirk stac927x_fixup_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_D965_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_D965_REF),
+        /* Intel 946 based systems */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
+       /* 965 based 3 stack systems */
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2100,
+                          "Intel D965", STAC_D965_3ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
+                          "Intel D965", STAC_D965_3ST),
+       /* Dell 3 stack systems */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01ed, "Dell     ", STAC_DELL_3ST),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f4, "Dell     ", STAC_DELL_3ST),
+       /* Dell 3 stack systems with verb table in BIOS */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS_SPDIF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0242, "Dell     ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0243, "Dell     ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x02ff, "Dell     ", STAC_DELL_BIOS),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0209, "Dell XPS 1330", STAC_DELL_BIOS_SPDIF),
+       /* 965 based 5 stack systems */
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300,
+                          "Intel D965", STAC_D965_5ST),
+       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
+                          "Intel D965", STAC_D965_5ST),
+       /* Nemo */
+       SND_PCI_QUIRK(0x1888, 0x1000, "AmigaOne X1000", STAC_NEMO_DEFAULT),
+       /* volume-knob fixes */
+       SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB),
+       {} /* terminator */
+};
+
+static const struct hda_pintbl ref9205_pin_configs[] = {
+       { 0x0a, 0x40000100 },
+       { 0x0b, 0x40000100 },
+       { 0x0c, 0x01016011 },
+       { 0x0d, 0x01014010 },
+       { 0x0e, 0x01813122 },
+       { 0x0f, 0x01a19021 },
+       { 0x14, 0x01019020 },
+       { 0x16, 0x40000100 },
+       { 0x17, 0x90a000f0 },
+       { 0x18, 0x90a000f0 },
+       { 0x21, 0x01441030 },
+       { 0x22, 0x01c41030 },
+       {}
+};
+
+/*
+    STAC 9205 pin configs for
+    102801F1
+    102801F2
+    102801FC
+    102801FD
+    10280204
+    1028021F
+    10280228 (Dell Vostro 1500)
+    10280229 (Dell Vostro 1700)
+*/
+static const struct hda_pintbl dell_9205_m42_pin_configs[] = {
+       { 0x0a, 0x0321101F },
+       { 0x0b, 0x03A11020 },
+       { 0x0c, 0x400003FA },
+       { 0x0d, 0x90170310 },
+       { 0x0e, 0x400003FB },
+       { 0x0f, 0x400003FC },
+       { 0x14, 0x400003FD },
+       { 0x16, 0x40F000F9 },
+       { 0x17, 0x90A60330 },
+       { 0x18, 0x400003FF },
+       { 0x21, 0x0144131F },
+       { 0x22, 0x40C003FE },
+       {}
+};
+
+/*
+    STAC 9205 pin configs for
+    102801F9
+    102801FA
+    102801FE
+    102801FF (Dell Precision M4300)
+    10280206
+    10280200
+    10280201
+*/
+static const struct hda_pintbl dell_9205_m43_pin_configs[] = {
+       { 0x0a, 0x0321101f },
+       { 0x0b, 0x03a11020 },
+       { 0x0c, 0x90a70330 },
+       { 0x0d, 0x90170310 },
+       { 0x0e, 0x400000fe },
+       { 0x0f, 0x400000ff },
+       { 0x14, 0x400000fd },
+       { 0x16, 0x40f000f9 },
+       { 0x17, 0x400000fa },
+       { 0x18, 0x400000fc },
+       { 0x21, 0x0144131f },
+       { 0x22, 0x40c003f8 },
+       /* Enable SPDIF in/out */
+       { 0x1f, 0x01441030 },
+       { 0x20, 0x1c410030 },
+       {}
+};
+
+static const struct hda_pintbl dell_9205_m44_pin_configs[] = {
+       { 0x0a, 0x0421101f },
+       { 0x0b, 0x04a11020 },
+       { 0x0c, 0x400003fa },
+       { 0x0d, 0x90170310 },
+       { 0x0e, 0x400003fb },
+       { 0x0f, 0x400003fc },
+       { 0x14, 0x400003fd },
+       { 0x16, 0x400003f9 },
+       { 0x17, 0x90a60330 },
+       { 0x18, 0x400003ff },
+       { 0x21, 0x01441340 },
+       { 0x22, 0x40c003fe },
+       {}
+};
+
+static void stac9205_fixup_ref(struct hda_codec *codec,
+                              const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               snd_hda_apply_pincfgs(codec, ref9205_pin_configs);
+               /* SPDIF-In enabled */
+               spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0;
+       }
+}
+
+static void stac9205_fixup_dell_m43(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       struct hda_jack_callback *jack;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+               snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs);
+
+               /* Enable unsol response for GPIO4/Dock HP connection */
+               snd_hda_codec_write_cache(codec, codec->core.afg, 0,
+                       AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
+               jack = snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
+                                                          stac_vref_event);
+               if (!IS_ERR(jack))
+                       jack->private_data = 0x01;
+
+               spec->gpio_dir = 0x0b;
+               spec->eapd_mask = 0x01;
+               spec->gpio_mask = 0x1b;
+               spec->gpio_mute = 0x10;
+               /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
+                * GPIO3 Low = DRM
+                */
+               spec->gpio_data = 0x01;
+       }
+}
+
+static void stac9205_fixup_eapd(struct hda_codec *codec,
+                               const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               spec->eapd_switch = 0;
+}
+
+static const struct hda_fixup stac9205_fixups[] = {
+       [STAC_9205_REF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac9205_fixup_ref,
+       },
+       [STAC_9205_DELL_M42] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_9205_m42_pin_configs,
+       },
+       [STAC_9205_DELL_M43] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac9205_fixup_dell_m43,
+       },
+       [STAC_9205_DELL_M44] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = dell_9205_m44_pin_configs,
+       },
+       [STAC_9205_EAPD] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac9205_fixup_eapd,
+       },
+       {}
+};
+
+static const struct hda_model_fixup stac9205_models[] = {
+       { .id = STAC_9205_REF, .name = "ref" },
+       { .id = STAC_9205_DELL_M42, .name = "dell-m42" },
+       { .id = STAC_9205_DELL_M43, .name = "dell-m43" },
+       { .id = STAC_9205_DELL_M44, .name = "dell-m44" },
+       { .id = STAC_9205_EAPD, .name = "eapd" },
+       {}
+};
+
+static const struct hda_quirk stac9205_fixup_tbl[] = {
+       /* SigmaTel reference board */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
+                     "DFI LanParty", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
+                     "SigmaTel", STAC_9205_REF),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
+                     "DFI LanParty", STAC_9205_REF),
+       /* Dell */
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
+                     "unknown Dell", STAC_9205_DELL_M42),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
+                     "unknown Dell", STAC_9205_DELL_M42),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
+                     "unknown Dell", STAC_9205_DELL_M42),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
+                     "unknown Dell", STAC_9205_DELL_M42),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
+                     "Dell Precision M4300", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
+                     "unknown Dell", STAC_9205_DELL_M42),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
+                     "Dell Precision", STAC_9205_DELL_M43),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
+                     "Dell Inspiron", STAC_9205_DELL_M44),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
+                     "Dell Vostro 1500", STAC_9205_DELL_M42),
+       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0229,
+                     "Dell Vostro 1700", STAC_9205_DELL_M42),
+       /* Gateway */
+       SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD),
+       SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
+       {} /* terminator */
+};
+
+static void stac92hd95_fixup_hp_led(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       if (action != HDA_FIXUP_ACT_PRE_PROBE)
+               return;
+
+       if (find_mute_led_cfg(codec, spec->default_polarity))
+               codec_dbg(codec, "mute LED gpio %d polarity %d\n",
+                               spec->gpio_led,
+                               spec->gpio_led_polarity);
+}
+
+static const struct hda_fixup stac92hd95_fixups[] = {
+       [STAC_92HD95_HP_LED] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = stac92hd95_fixup_hp_led,
+       },
+       [STAC_92HD95_HP_BASS] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       {0x1a, 0x795, 0x00}, /* HPF to 100Hz */
+                       {}
+               },
+               .chained = true,
+               .chain_id = STAC_92HD95_HP_LED,
+       },
+};
+
+static const struct hda_quirk stac92hd95_fixup_tbl[] = {
+       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1911, "HP Spectre 13", STAC_92HD95_HP_BASS),
+       {} /* terminator */
+};
+
+static const struct hda_model_fixup stac92hd95_models[] = {
+       { .id = STAC_92HD95_HP_LED, .name = "hp-led" },
+       { .id = STAC_92HD95_HP_BASS, .name = "hp-bass" },
+       {}
+};
+
+
+static int stac_parse_auto_config(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int err;
+       int flags = 0;
+
+       if (spec->headset_jack)
+               flags |= HDA_PINCFG_HEADSET_MIC;
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, flags);
+       if (err < 0)
+               return err;
+
+       /* add hooks */
+       spec->gen.pcm_playback_hook = stac_playback_pcm_hook;
+       spec->gen.pcm_capture_hook = stac_capture_pcm_hook;
+
+       spec->gen.automute_hook = stac_update_outputs;
+
+       if (spec->gpio_led)
+               snd_hda_gen_add_mute_led_cdev(codec, stac_vmaster_hook);
+
+       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+       if (err < 0)
+               return err;
+
+       if (spec->vref_mute_led_nid) {
+               err = snd_hda_gen_fix_pin_power(codec, spec->vref_mute_led_nid);
+               if (err < 0)
+                       return err;
+       }
+
+       /* setup analog beep controls */
+       if (spec->anabeep_nid > 0) {
+               err = stac_auto_create_beep_ctls(codec,
+                                                spec->anabeep_nid);
+               if (err < 0)
+                       return err;
+       }
+
+       /* setup digital beep controls and input device */
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+       if (spec->gen.beep_nid) {
+               hda_nid_t nid = spec->gen.beep_nid;
+               unsigned int caps;
+
+               err = stac_auto_create_beep_ctls(codec, nid);
+               if (err < 0)
+                       return err;
+               if (codec->beep) {
+                       /* IDT/STAC codecs have linear beep tone parameter */
+                       codec->beep->linear_tone = spec->linear_tone_beep;
+                       /* keep power up while beep is enabled */
+                       codec->beep->keep_power_at_enable = 1;
+                       /* if no beep switch is available, make its own one */
+                       caps = query_amp_caps(codec, nid, HDA_OUTPUT);
+                       if (!(caps & AC_AMPCAP_MUTE)) {
+                               err = stac_beep_switch_ctl(codec);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+       }
+#endif
+
+       if (spec->aloopback_ctl &&
+           snd_hda_get_bool_hint(codec, "loopback") == 1) {
+               unsigned int wr_verb =
+                       spec->aloopback_ctl->private_value >> 16;
+               if (snd_hdac_regmap_add_vendor_verb(&codec->core, wr_verb))
+                       return -ENOMEM;
+               if (!snd_hda_gen_add_kctl(&spec->gen, NULL, spec->aloopback_ctl))
+                       return -ENOMEM;
+       }
+
+       if (spec->have_spdif_mux) {
+               err = stac_create_spdif_mux_ctls(codec);
+               if (err < 0)
+                       return err;
+       }
+
+       stac_init_power_map(codec);
+
+       return 0;
+}
+
+static int stac_init(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+       int i;
+
+       /* override some hints */
+       stac_store_hints(codec);
+
+       /* set up GPIO */
+       /* turn on EAPD statically when spec->eapd_switch isn't set.
+        * otherwise, unsol event will turn it on/off dynamically
+        */
+       if (!spec->eapd_switch)
+               spec->gpio_data |= spec->eapd_mask;
+       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
+
+       snd_hda_gen_init(codec);
+
+       /* sync the power-map */
+       if (spec->num_pwrs)
+               snd_hda_codec_write(codec, codec->core.afg, 0,
+                                   AC_VERB_IDT_SET_POWER_MAP,
+                                   spec->power_map_bits);
+
+       /* power down inactive ADCs */
+       if (spec->powerdown_adcs) {
+               for (i = 0; i < spec->gen.num_all_adcs; i++) {
+                       if (spec->active_adcs & (1 << i))
+                               continue;
+                       snd_hda_codec_write(codec, spec->gen.all_adcs[i], 0,
+                                           AC_VERB_SET_POWER_STATE,
+                                           AC_PWRST_D3);
+               }
+       }
+
+       return 0;
+}
+
+#define stac_free      snd_hda_gen_free
+
+#ifdef CONFIG_SND_PROC_FS
+static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
+                              struct hda_codec *codec, hda_nid_t nid)
+{
+       if (nid == codec->core.afg)
+               snd_iprintf(buffer, "Power-Map: 0x%02x\n", 
+                           snd_hda_codec_read(codec, nid, 0,
+                                              AC_VERB_IDT_GET_POWER_MAP, 0));
+}
+
+static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
+                                 struct hda_codec *codec,
+                                 unsigned int verb)
+{
+       snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
+                   snd_hda_codec_read(codec, codec->core.afg, 0, verb, 0));
+}
+
+/* stac92hd71bxx, stac92hd73xx */
+static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer,
+                                struct hda_codec *codec, hda_nid_t nid)
+{
+       stac92hd_proc_hook(buffer, codec, nid);
+       if (nid == codec->core.afg)
+               analog_loop_proc_hook(buffer, codec, 0xfa0);
+}
+
+static void stac9205_proc_hook(struct snd_info_buffer *buffer,
+                              struct hda_codec *codec, hda_nid_t nid)
+{
+       if (nid == codec->core.afg)
+               analog_loop_proc_hook(buffer, codec, 0xfe0);
+}
+
+static void stac927x_proc_hook(struct snd_info_buffer *buffer,
+                              struct hda_codec *codec, hda_nid_t nid)
+{
+       if (nid == codec->core.afg)
+               analog_loop_proc_hook(buffer, codec, 0xfeb);
+}
+#else
+#define stac92hd_proc_hook     NULL
+#define stac92hd7x_proc_hook   NULL
+#define stac9205_proc_hook     NULL
+#define stac927x_proc_hook     NULL
+#endif
+
+static int stac_suspend(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       snd_hda_shutup_pins(codec);
+
+       if (spec->eapd_mask)
+               stac_gpio_set(codec, spec->gpio_mask,
+                               spec->gpio_dir, spec->gpio_data &
+                               ~spec->eapd_mask);
+
+       return 0;
+}
+
+static const struct hda_codec_ops stac_patch_ops = {
+       .build_controls = snd_hda_gen_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = stac_init,
+       .free = stac_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .suspend = stac_suspend,
+};
+
+static int alloc_stac_spec(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (!spec)
+               return -ENOMEM;
+       snd_hda_gen_spec_init(&spec->gen);
+       codec->spec = spec;
+       codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */
+       spec->gen.dac_min_mute = true;
+       codec->patch_ops = stac_patch_ops;
+       return 0;
+}
+
+static int patch_stac9200(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->linear_tone_beep = 1;
+       spec->gen.own_eapd_ctl = 1;
+
+       codec->power_filter = snd_hda_codec_eapd_power_filter;
+
+       snd_hda_add_verbs(codec, stac9200_eapd_init);
+
+       snd_hda_pick_fixup(codec, stac9200_models, stac9200_fixup_tbl,
+                          stac9200_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+static int patch_stac925x(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->linear_tone_beep = 1;
+       spec->gen.own_eapd_ctl = 1;
+
+       snd_hda_add_verbs(codec, stac925x_core_init);
+
+       snd_hda_pick_fixup(codec, stac925x_models, stac925x_fixup_tbl,
+                          stac925x_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+static int patch_stac92hd73xx(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+       int num_dacs;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       /* enable power_save_node only for new 92HD89xx chips, as it causes
+        * click noises on old 92HD73xx chips.
+        */
+       if ((codec->core.vendor_id & 0xfffffff0) != 0x111d7670)
+               codec->power_save_node = 1;
+       spec->linear_tone_beep = 0;
+       spec->gen.mixer_nid = 0x1d;
+       spec->have_spdif_mux = 1;
+
+       num_dacs = snd_hda_get_num_conns(codec, 0x0a) - 1;
+       if (num_dacs < 3 || num_dacs > 5) {
+               codec_warn(codec,
+                          "Could not determine number of channels defaulting to DAC count\n");
+               num_dacs = 5;
+       }
+
+       switch (num_dacs) {
+       case 0x3: /* 6 Channel */
+               spec->aloopback_ctl = &stac92hd73xx_6ch_loopback;
+               break;
+       case 0x4: /* 8 Channel */
+               spec->aloopback_ctl = &stac92hd73xx_8ch_loopback;
+               break;
+       case 0x5: /* 10 Channel */
+               spec->aloopback_ctl = &stac92hd73xx_10ch_loopback;
+               break;
+       }
+
+       spec->aloopback_mask = 0x01;
+       spec->aloopback_shift = 8;
+
+       spec->gen.beep_nid = 0x1c; /* digital beep */
+
+       /* GPIO0 High = Enable EAPD */
+       spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
+       spec->gpio_data = 0x01;
+
+       spec->eapd_switch = 1;
+
+       spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
+       spec->pwr_nids = stac92hd73xx_pwr_nids;
+
+       spec->gen.own_eapd_ctl = 1;
+       spec->gen.power_down_unused = 1;
+
+       snd_hda_pick_fixup(codec, stac92hd73xx_models, stac92hd73xx_fixup_tbl,
+                          stac92hd73xx_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       if (!spec->volknob_init)
+               snd_hda_add_verbs(codec, stac92hd73xx_core_init);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       /* Don't GPIO-mute speakers if there are no internal speakers, because
+        * the GPIO might be necessary for Headphone
+        */
+       if (spec->eapd_switch && !has_builtin_speaker(codec))
+               spec->eapd_switch = 0;
+
+       codec->proc_widget_hook = stac92hd7x_proc_hook;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+static void stac_setup_gpio(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec = codec->spec;
+
+       spec->gpio_mask |= spec->eapd_mask;
+       if (spec->gpio_led) {
+               if (!spec->vref_mute_led_nid) {
+                       spec->gpio_mask |= spec->gpio_led;
+                       spec->gpio_dir |= spec->gpio_led;
+                       spec->gpio_data |= spec->gpio_led;
+               } else {
+                       codec->power_filter = stac_vref_led_power_filter;
+               }
+       }
+
+       if (spec->mic_mute_led_gpio) {
+               spec->gpio_mask |= spec->mic_mute_led_gpio;
+               spec->gpio_dir |= spec->mic_mute_led_gpio;
+               spec->mic_enabled = 0;
+               spec->gpio_data |= spec->mic_mute_led_gpio;
+               snd_hda_gen_add_micmute_led_cdev(codec, stac_capture_led_update);
+       }
+}
+
+static int patch_stac92hd83xxx(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       /* longer delay needed for D3 */
+       codec->core.power_caps &= ~AC_PWRST_EPSS;
+
+       spec = codec->spec;
+       codec->power_save_node = 1;
+       spec->linear_tone_beep = 0;
+       spec->gen.own_eapd_ctl = 1;
+       spec->gen.power_down_unused = 1;
+       spec->gen.mixer_nid = 0x1b;
+
+       spec->gen.beep_nid = 0x21; /* digital beep */
+       spec->pwr_nids = stac92hd83xxx_pwr_nids;
+       spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
+       spec->default_polarity = -1; /* no default cfg */
+
+       snd_hda_add_verbs(codec, stac92hd83xxx_core_init);
+
+       snd_hda_pick_fixup(codec, stac92hd83xxx_models, stac92hd83xxx_fixup_tbl,
+                          stac92hd83xxx_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       stac_setup_gpio(codec);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       codec->proc_widget_hook = stac92hd_proc_hook;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+static const hda_nid_t stac92hd95_pwr_nids[] = {
+       0x0a, 0x0b, 0x0c, 0x0d
+};
+
+static int patch_stac92hd95(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       /* longer delay needed for D3 */
+       codec->core.power_caps &= ~AC_PWRST_EPSS;
+
+       spec = codec->spec;
+       codec->power_save_node = 1;
+       spec->linear_tone_beep = 0;
+       spec->gen.own_eapd_ctl = 1;
+       spec->gen.power_down_unused = 1;
+
+       spec->gen.beep_nid = 0x19; /* digital beep */
+       spec->pwr_nids = stac92hd95_pwr_nids;
+       spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids);
+       spec->default_polarity = 0;
+
+       snd_hda_pick_fixup(codec, stac92hd95_models, stac92hd95_fixup_tbl,
+                          stac92hd95_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       stac_setup_gpio(codec);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       codec->proc_widget_hook = stac92hd_proc_hook;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+static int patch_stac92hd71bxx(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       const hda_nid_t *unmute_nids = stac92hd71bxx_unmute_nids;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       /* disabled power_save_node since it causes noises on a Dell machine */
+       /* codec->power_save_node = 1; */
+       spec->linear_tone_beep = 0;
+       spec->gen.own_eapd_ctl = 1;
+       spec->gen.power_down_unused = 1;
+       spec->gen.mixer_nid = 0x17;
+       spec->have_spdif_mux = 1;
+
+       /* GPIO0 = EAPD */
+       spec->gpio_mask = 0x01;
+       spec->gpio_dir = 0x01;
+       spec->gpio_data = 0x01;
+
+       switch (codec->core.vendor_id) {
+       case 0x111d76b6: /* 4 Port without Analog Mixer */
+       case 0x111d76b7:
+               unmute_nids++;
+               break;
+       case 0x111d7608: /* 5 Port with Analog Mixer */
+               if ((codec->core.revision_id & 0xf) == 0 ||
+                   (codec->core.revision_id & 0xf) == 1)
+                       spec->stream_delay = 40; /* 40 milliseconds */
+
+               /* disable VSW */
+               unmute_nids++;
+               snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
+               snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
+               break;
+       case 0x111d7603: /* 6 Port with Analog Mixer */
+               if ((codec->core.revision_id & 0xf) == 1)
+                       spec->stream_delay = 40; /* 40 milliseconds */
+
+               break;
+       }
+
+       if (get_wcaps_type(get_wcaps(codec, 0x28)) == AC_WID_VOL_KNB)
+               snd_hda_add_verbs(codec, stac92hd71bxx_core_init);
+
+       if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) {
+               const hda_nid_t *p;
+               for (p = unmute_nids; *p; p++)
+                       snd_hda_codec_amp_init_stereo(codec, *p, HDA_INPUT, 0,
+                                                     0xff, 0x00);
+       }
+
+       spec->aloopback_ctl = &stac92hd71bxx_loopback;
+       spec->aloopback_mask = 0x50;
+       spec->aloopback_shift = 0;
+
+       spec->powerdown_adcs = 1;
+       spec->gen.beep_nid = 0x26; /* digital beep */
+       spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
+       spec->pwr_nids = stac92hd71bxx_pwr_nids;
+
+       snd_hda_pick_fixup(codec, stac92hd71bxx_models, stac92hd71bxx_fixup_tbl,
+                          stac92hd71bxx_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       stac_setup_gpio(codec);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       codec->proc_widget_hook = stac92hd7x_proc_hook;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+static int patch_stac922x(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->linear_tone_beep = 1;
+       spec->gen.own_eapd_ctl = 1;
+
+       snd_hda_add_verbs(codec, stac922x_core_init);
+
+       /* Fix Mux capture level; max to 2 */
+       snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
+                                 (0 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (0 << AC_AMPCAP_MUTE_SHIFT));
+
+       snd_hda_pick_fixup(codec, stac922x_models, stac922x_fixup_tbl,
+                          stac922x_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+static const char * const stac927x_spdif_labels[] = {
+       "Digital Playback", "ADAT", "Analog Mux 1",
+       "Analog Mux 2", "Analog Mux 3", NULL
+};
+
+static int patch_stac927x(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->linear_tone_beep = 1;
+       spec->gen.own_eapd_ctl = 1;
+       spec->have_spdif_mux = 1;
+       spec->spdif_labels = stac927x_spdif_labels;
+
+       spec->gen.beep_nid = 0x23; /* digital beep */
+
+       /* GPIO0 High = Enable EAPD */
+       spec->eapd_mask = spec->gpio_mask = 0x01;
+       spec->gpio_dir = spec->gpio_data = 0x01;
+
+       spec->aloopback_ctl = &stac927x_loopback;
+       spec->aloopback_mask = 0x40;
+       spec->aloopback_shift = 0;
+       spec->eapd_switch = 1;
+
+       snd_hda_pick_fixup(codec, stac927x_models, stac927x_fixup_tbl,
+                          stac927x_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       if (!spec->volknob_init)
+               snd_hda_add_verbs(codec, stac927x_core_init);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       codec->proc_widget_hook = stac927x_proc_hook;
+
+       /*
+        * !!FIXME!!
+        * The STAC927x seem to require fairly long delays for certain
+        * command sequences.  With too short delays (even if the answer
+        * is set to RIRB properly), it results in the silence output
+        * on some hardwares like Dell.
+        *
+        * The below flag enables the longer delay (see get_response
+        * in hda_intel.c).
+        */
+       codec->bus->core.needs_damn_long_delay = 1;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+static int patch_stac9205(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->linear_tone_beep = 1;
+       spec->gen.own_eapd_ctl = 1;
+       spec->have_spdif_mux = 1;
+
+       spec->gen.beep_nid = 0x23; /* digital beep */
+
+       snd_hda_add_verbs(codec, stac9205_core_init);
+       spec->aloopback_ctl = &stac9205_loopback;
+
+       spec->aloopback_mask = 0x40;
+       spec->aloopback_shift = 0;
+       
+       /* GPIO0 High = EAPD */
+       spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
+       spec->gpio_data = 0x01;
+
+       /* Turn on/off EAPD per HP plugging */
+       spec->eapd_switch = 1;
+
+       snd_hda_pick_fixup(codec, stac9205_models, stac9205_fixup_tbl,
+                          stac9205_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return err;
+       }
+
+       codec->proc_widget_hook = stac9205_proc_hook;
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+/*
+ * STAC9872 hack
+ */
+
+static const struct hda_verb stac9872_core_init[] = {
+       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
+       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
+       {}
+};
+
+static const struct hda_pintbl stac9872_vaio_pin_configs[] = {
+       { 0x0a, 0x03211020 },
+       { 0x0b, 0x411111f0 },
+       { 0x0c, 0x411111f0 },
+       { 0x0d, 0x03a15030 },
+       { 0x0e, 0x411111f0 },
+       { 0x0f, 0x90170110 },
+       { 0x11, 0x411111f0 },
+       { 0x13, 0x411111f0 },
+       { 0x14, 0x90a7013e },
+       {}
+};
+
+static const struct hda_model_fixup stac9872_models[] = {
+       { .id = STAC_9872_VAIO, .name = "vaio" },
+       {}
+};
+
+static const struct hda_fixup stac9872_fixups[] = {
+       [STAC_9872_VAIO] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = stac9872_vaio_pin_configs,
+       },
+};
+
+static const struct hda_quirk stac9872_fixup_tbl[] = {
+       SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
+                          "Sony VAIO F/S", STAC_9872_VAIO),
+       {} /* terminator */
+};
+
+static int patch_stac9872(struct hda_codec *codec)
+{
+       struct sigmatel_spec *spec;
+       int err;
+
+       err = alloc_stac_spec(codec);
+       if (err < 0)
+               return err;
+
+       spec = codec->spec;
+       spec->linear_tone_beep = 1;
+       spec->gen.own_eapd_ctl = 1;
+
+       snd_hda_add_verbs(codec, stac9872_core_init);
+
+       snd_hda_pick_fixup(codec, stac9872_models, stac9872_fixup_tbl,
+                          stac9872_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       err = stac_parse_auto_config(codec);
+       if (err < 0) {
+               stac_free(codec);
+               return -EINVAL;
+       }
+
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
+
+       return 0;
+}
+
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_sigmatel[] = {
+       HDA_CODEC_ENTRY(0x83847690, "STAC9200", patch_stac9200),
+       HDA_CODEC_ENTRY(0x83847882, "STAC9220 A1", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847680, "STAC9221 A1", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847880, "STAC9220 A2", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847681, "STAC9220D/9223D A2", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847682, "STAC9221 A2", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x),
+       HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847615, "STAC9229", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847620, "STAC9274", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847621, "STAC9274D", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847622, "STAC9273X", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847623, "STAC9273D", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847624, "STAC9272X", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847625, "STAC9272D", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847626, "STAC9271X", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847627, "STAC9271D", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847628, "STAC9274X5NH", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847629, "STAC9274D5NH", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847632, "STAC9202",  patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847633, "STAC9202D", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847634, "STAC9250", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847635, "STAC9250D", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847636, "STAC9251", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847637, "STAC9250D", patch_stac925x),
+       HDA_CODEC_ENTRY(0x83847645, "92HD206X", patch_stac927x),
+       HDA_CODEC_ENTRY(0x83847646, "92HD206D", patch_stac927x),
+       /* The following does not take into account .id=0x83847661 when subsys =
+        * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
+        * currently not fully supported.
+        */
+       HDA_CODEC_ENTRY(0x83847661, "CXD9872RD/K", patch_stac9872),
+       HDA_CODEC_ENTRY(0x83847662, "STAC9872AK", patch_stac9872),
+       HDA_CODEC_ENTRY(0x83847664, "CXD9872AKD", patch_stac9872),
+       HDA_CODEC_ENTRY(0x83847698, "STAC9205", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a0, "STAC9205", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a1, "STAC9205D", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a2, "STAC9204", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a3, "STAC9204D", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a4, "STAC9255", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a5, "STAC9255D", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a6, "STAC9254", patch_stac9205),
+       HDA_CODEC_ENTRY(0x838476a7, "STAC9254D", patch_stac9205),
+       HDA_CODEC_ENTRY(0x111d7603, "92HD75B3X5", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d7604, "92HD83C1X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76d4, "92HD83C1C5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7605, "92HD81B1X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76d5, "92HD81B1C5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76d1, "92HD87B1/3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76d9, "92HD87B2/4", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7666, "92HD88B3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7667, "92HD88B1", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7668, "92HD88B2", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7669, "92HD88B4", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d7608, "92HD75B2X5", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d7674, "92HD73D1X5", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d7675, "92HD73C1X5", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d7676, "92HD73E1X5", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d7695, "92HD95", patch_stac92hd95),
+       HDA_CODEC_ENTRY(0x111d76b0, "92HD71B8X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b1, "92HD71B8X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b2, "92HD71B7X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b3, "92HD71B7X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b4, "92HD71B6X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b5, "92HD71B6X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b6, "92HD71B5X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76b7, "92HD71B5X", patch_stac92hd71bxx),
+       HDA_CODEC_ENTRY(0x111d76c0, "92HD89C3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c1, "92HD89C2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c2, "92HD89C1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c3, "92HD89B3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c4, "92HD89B2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c5, "92HD89B1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c6, "92HD89E3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c7, "92HD89E2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c8, "92HD89E1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76c9, "92HD89D3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76ca, "92HD89D2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76cb, "92HD89D1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76cc, "92HD89F3", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76cd, "92HD89F2", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76ce, "92HD89F1", patch_stac92hd73xx),
+       HDA_CODEC_ENTRY(0x111d76df, "92HD93BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e0, "92HD91BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e3, "92HD98BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e5, "92HD99BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e7, "92HD90BXX", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e8, "92HD66B1X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76e9, "92HD66B2X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ea, "92HD66B3X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76eb, "92HD66C1X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ec, "92HD66C2X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ed, "92HD66C3X5", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ee, "92HD66B1X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76ef, "92HD66B2X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76f0, "92HD66B3X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76f1, "92HD66C1X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76f2, "92HD66C2X3", patch_stac92hd83xxx),
+       HDA_CODEC_ENTRY(0x111d76f3, "92HD66C3/65", patch_stac92hd83xxx),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_sigmatel);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
+
+static struct hda_codec_driver sigmatel_driver = {
+       .id = snd_hda_id_sigmatel,
+};
+
+module_hda_codec_driver(sigmatel_driver);
diff --git a/sound/hda/codecs/via.c b/sound/hda/codecs/via.c
new file mode 100644 (file)
index 0000000..e3ce563
--- /dev/null
@@ -0,0 +1,1247 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Universal Interface for Intel High Definition Audio Codec
+ *
+ * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec
+ *
+ *  (C) 2006-2009 VIA Technology, Inc.
+ *  (C) 2006-2008 Takashi Iwai <tiwai@suse.de>
+ */
+
+/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
+/*                                                                          */
+/* 2006-03-03  Lydia Wang  Create the basic patch to support VT1708 codec    */
+/* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid         */
+/* 2006-08-02  Lydia Wang  Add support to VT1709 codec                      */
+/* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
+/* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization             */
+/* 2007-09-17  Lydia Wang  Add VT1708B codec support                       */
+/* 2007-11-14  Lydia Wang  Add VT1708A codec HP and CD pin connect config    */
+/* 2008-02-03  Lydia Wang  Fix Rear channels and Back channels inverse issue */
+/* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support       */
+/* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin            */
+/* 2008-04-09  Lydia Wang  Add Independent HP feature                       */
+/* 2008-05-28  Lydia Wang  Add second S/PDIF Out support for VT1702         */
+/* 2008-09-15  Logan Li           Add VT1708S Mic Boost workaround/backdoor         */
+/* 2009-02-16  Logan Li           Add support for VT1718S                           */
+/* 2009-03-13  Logan Li           Add support for VT1716S                           */
+/* 2009-04-14  Lydai Wang  Add support for VT1828S and VT2020               */
+/* 2009-07-08  Lydia Wang  Add support for VT2002P                          */
+/* 2009-07-21  Lydia Wang  Add support for VT1812                           */
+/* 2009-09-19  Lydia Wang  Add support for VT1818S                          */
+/*                                                                          */
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
+#include <sound/asoundef.h>
+#include <sound/hda_codec.h>
+#include "hda_local.h"
+#include "hda_auto_parser.h"
+#include "hda_jack.h"
+#include "generic.h"
+
+/* Pin Widget NID */
+#define VT1708_HP_PIN_NID      0x20
+#define VT1708_CD_PIN_NID      0x24
+
+enum VIA_HDA_CODEC {
+       UNKNOWN = -1,
+       VT1708,
+       VT1709_10CH,
+       VT1709_6CH,
+       VT1708B_8CH,
+       VT1708B_4CH,
+       VT1708S,
+       VT1708BCE,
+       VT1702,
+       VT1718S,
+       VT1716S,
+       VT2002P,
+       VT1812,
+       VT1802,
+       VT1705CF,
+       VT1808,
+       CODEC_TYPES,
+};
+
+#define VT2002P_COMPATIBLE(spec) \
+       ((spec)->codec_type == VT2002P ||\
+        (spec)->codec_type == VT1812 ||\
+        (spec)->codec_type == VT1802)
+
+struct via_spec {
+       struct hda_gen_spec gen;
+
+       /* HP mode source */
+       unsigned int dmic_enabled;
+       enum VIA_HDA_CODEC codec_type;
+
+       /* analog low-power control */
+       bool alc_mode;
+
+       /* work to check hp jack state */
+       int hp_work_active;
+       int vt1708_jack_detect;
+};
+
+static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
+static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream,
+                                 int action);
+
+static const struct hda_codec_ops via_patch_ops; /* defined below */
+
+static struct via_spec *via_new_spec(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+
+       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
+       if (spec == NULL)
+               return NULL;
+
+       codec->spec = spec;
+       snd_hda_gen_spec_init(&spec->gen);
+       spec->codec_type = get_codec_type(codec);
+       /* VT1708BCE & VT1708S are almost same */
+       if (spec->codec_type == VT1708BCE)
+               spec->codec_type = VT1708S;
+       spec->gen.indep_hp = 1;
+       spec->gen.keep_eapd_on = 1;
+       spec->gen.dac_min_mute = 1;
+       spec->gen.pcm_playback_hook = via_playback_pcm_hook;
+       spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
+       codec->power_save_node = 1;
+       spec->gen.power_down_unused = 1;
+       codec->patch_ops = via_patch_ops;
+       return spec;
+}
+
+static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
+{
+       u32 vendor_id = codec->core.vendor_id;
+       u16 ven_id = vendor_id >> 16;
+       u16 dev_id = vendor_id & 0xffff;
+       enum VIA_HDA_CODEC codec_type;
+
+       /* get codec type */
+       if (ven_id != 0x1106)
+               codec_type = UNKNOWN;
+       else if (dev_id >= 0x1708 && dev_id <= 0x170b)
+               codec_type = VT1708;
+       else if (dev_id >= 0xe710 && dev_id <= 0xe713)
+               codec_type = VT1709_10CH;
+       else if (dev_id >= 0xe714 && dev_id <= 0xe717)
+               codec_type = VT1709_6CH;
+       else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
+               codec_type = VT1708B_8CH;
+               if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
+                       codec_type = VT1708BCE;
+       } else if (dev_id >= 0xe724 && dev_id <= 0xe727)
+               codec_type = VT1708B_4CH;
+       else if ((dev_id & 0xfff) == 0x397
+                && (dev_id >> 12) < 8)
+               codec_type = VT1708S;
+       else if ((dev_id & 0xfff) == 0x398
+                && (dev_id >> 12) < 8)
+               codec_type = VT1702;
+       else if ((dev_id & 0xfff) == 0x428
+                && (dev_id >> 12) < 8)
+               codec_type = VT1718S;
+       else if (dev_id == 0x0433 || dev_id == 0xa721)
+               codec_type = VT1716S;
+       else if (dev_id == 0x0441 || dev_id == 0x4441)
+               codec_type = VT1718S;
+       else if (dev_id == 0x0438 || dev_id == 0x4438)
+               codec_type = VT2002P;
+       else if (dev_id == 0x0448)
+               codec_type = VT1812;
+       else if (dev_id == 0x0440)
+               codec_type = VT1708S;
+       else if ((dev_id & 0xfff) == 0x446)
+               codec_type = VT1802;
+       else if (dev_id == 0x4760)
+               codec_type = VT1705CF;
+       else if (dev_id == 0x4761 || dev_id == 0x4762)
+               codec_type = VT1808;
+       else
+               codec_type = UNKNOWN;
+       return codec_type;
+};
+
+static void analog_low_current_mode(struct hda_codec *codec);
+static bool is_aa_path_mute(struct hda_codec *codec);
+
+#define hp_detect_with_aa(codec) \
+       (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1 && \
+        !is_aa_path_mute(codec))
+
+static void vt1708_stop_hp_work(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs)
+               return;
+       if (spec->hp_work_active) {
+               snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1);
+               codec->jackpoll_interval = 0;
+               cancel_delayed_work_sync(&codec->jackpoll_work);
+               spec->hp_work_active = false;
+       }
+}
+
+static void vt1708_update_hp_work(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs)
+               return;
+       if (spec->vt1708_jack_detect) {
+               if (!spec->hp_work_active) {
+                       codec->jackpoll_interval = msecs_to_jiffies(100);
+                       snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0);
+                       schedule_delayed_work(&codec->jackpoll_work, 0);
+                       spec->hp_work_active = true;
+               }
+       } else if (!hp_detect_with_aa(codec))
+               vt1708_stop_hp_work(codec);
+}
+
+static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol,
+                                 struct snd_ctl_elem_info *uinfo)
+{
+       return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
+}
+
+static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+
+       ucontrol->value.enumerated.item[0] = spec->gen.power_down_unused;
+       return 0;
+}
+
+static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
+                                struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       bool val = !!ucontrol->value.enumerated.item[0];
+
+       if (val == spec->gen.power_down_unused)
+               return 0;
+       /* codec->power_save_node = val; */ /* widget PM seems yet broken */
+       spec->gen.power_down_unused = val;
+       analog_low_current_mode(codec);
+       return 1;
+}
+
+static const struct snd_kcontrol_new via_pin_power_ctl_enum = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Dynamic Power-Control",
+       .info = via_pin_power_ctl_info,
+       .get = via_pin_power_ctl_get,
+       .put = via_pin_power_ctl_put,
+};
+
+#ifdef CONFIG_SND_HDA_INPUT_BEEP
+/* additional beep mixers; the actual parameters are overwritten at build */
+static const struct snd_kcontrol_new via_beep_mixer[] = {
+       HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
+       HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
+};
+
+static int set_beep_amp(struct via_spec *spec, hda_nid_t nid,
+                       int idx, int dir)
+{
+       struct snd_kcontrol_new *knew;
+       unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
+       int i;
+
+       spec->gen.beep_nid = nid;
+       for (i = 0; i < ARRAY_SIZE(via_beep_mixer); i++) {
+               knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
+                                           &via_beep_mixer[i]);
+               if (!knew)
+                       return -ENOMEM;
+               knew->private_value = beep_amp;
+       }
+       return 0;
+}
+
+static int auto_parse_beep(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       hda_nid_t nid;
+
+       for_each_hda_codec_node(nid, codec)
+               if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
+                       return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
+       return 0;
+}
+#else
+#define auto_parse_beep(codec) 0
+#endif
+
+/* check AA path's mute status */
+static bool is_aa_path_mute(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       const struct hda_amp_list *p;
+       int ch, v;
+
+       p = spec->gen.loopback.amplist;
+       if (!p)
+               return true;
+       for (; p->nid; p++) {
+               for (ch = 0; ch < 2; ch++) {
+                       v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir,
+                                                  p->idx);
+                       if (!(v & HDA_AMP_MUTE) && v > 0)
+                               return false;
+               }
+       }
+       return true;
+}
+
+/* enter/exit analog low-current mode */
+static void __analog_low_current_mode(struct hda_codec *codec, bool force)
+{
+       struct via_spec *spec = codec->spec;
+       bool enable;
+       unsigned int verb, parm;
+
+       if (!codec->power_save_node)
+               enable = false;
+       else
+               enable = is_aa_path_mute(codec) && !spec->gen.active_streams;
+       if (enable == spec->alc_mode && !force)
+               return;
+       spec->alc_mode = enable;
+
+       /* decide low current mode's verb & parameter */
+       switch (spec->codec_type) {
+       case VT1708B_8CH:
+       case VT1708B_4CH:
+               verb = 0xf70;
+               parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
+               break;
+       case VT1708S:
+       case VT1718S:
+       case VT1716S:
+               verb = 0xf73;
+               parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
+               break;
+       case VT1702:
+               verb = 0xf73;
+               parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
+               break;
+       case VT2002P:
+       case VT1812:
+       case VT1802:
+               verb = 0xf93;
+               parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
+               break;
+       case VT1705CF:
+       case VT1808:
+               verb = 0xf82;
+               parm = enable ? 0x00 : 0xe0;  /* 0x00: 4/40x, 0xe0: 1x */
+               break;
+       default:
+               return;         /* other codecs are not supported */
+       }
+       /* send verb */
+       snd_hda_codec_write(codec, codec->core.afg, 0, verb, parm);
+}
+
+static void analog_low_current_mode(struct hda_codec *codec)
+{
+       return __analog_low_current_mode(codec, false);
+}
+
+static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+                                 struct hda_codec *codec,
+                                 struct snd_pcm_substream *substream,
+                                 int action)
+{
+       analog_low_current_mode(codec);
+       vt1708_update_hp_work(codec);
+}
+
+static void via_free(struct hda_codec *codec)
+{
+       vt1708_stop_hp_work(codec);
+       snd_hda_gen_free(codec);
+}
+
+static int via_suspend(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       vt1708_stop_hp_work(codec);
+
+       /* Fix pop noise on headphones */
+       if (spec->codec_type == VT1802)
+               snd_hda_shutup_pins(codec);
+
+       return 0;
+}
+
+static int via_resume(struct hda_codec *codec)
+{
+       /* some delay here to make jack detection working (bko#98921) */
+       msleep(10);
+       codec->patch_ops.init(codec);
+       snd_hda_regmap_sync(codec);
+       return 0;
+}
+
+static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
+{
+       struct via_spec *spec = codec->spec;
+       analog_low_current_mode(codec);
+       vt1708_update_hp_work(codec);
+       return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid);
+}
+
+/*
+ */
+
+static int via_init(struct hda_codec *codec);
+
+static const struct hda_codec_ops via_patch_ops = {
+       .build_controls = snd_hda_gen_build_controls,
+       .build_pcms = snd_hda_gen_build_pcms,
+       .init = via_init,
+       .free = via_free,
+       .unsol_event = snd_hda_jack_unsol_event,
+       .suspend = via_suspend,
+       .resume = via_resume,
+       .check_power_status = via_check_power_status,
+};
+
+
+static const struct hda_verb vt1708_init_verbs[] = {
+       /* power down jack detect function */
+       {0x1, 0xf81, 0x1},
+       { }
+};
+static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
+{
+       unsigned int def_conf;
+       unsigned char seqassoc;
+
+       def_conf = snd_hda_codec_get_pincfg(codec, nid);
+       seqassoc = (unsigned char) get_defcfg_association(def_conf);
+       seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
+       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
+           && (seqassoc == 0xf0 || seqassoc == 0xff)) {
+               def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
+               snd_hda_codec_set_pincfg(codec, nid, def_conf);
+       }
+}
+
+static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+
+       if (spec->codec_type != VT1708)
+               return 0;
+       ucontrol->value.integer.value[0] = spec->vt1708_jack_detect;
+       return 0;
+}
+
+static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol,
+                                    struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       int val;
+
+       if (spec->codec_type != VT1708)
+               return 0;
+       val = !!ucontrol->value.integer.value[0];
+       if (spec->vt1708_jack_detect == val)
+               return 0;
+       spec->vt1708_jack_detect = val;
+       vt1708_update_hp_work(codec);
+       return 1;
+}
+
+static const struct snd_kcontrol_new vt1708_jack_detect_ctl = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Jack Detect",
+       .count = 1,
+       .info = snd_ctl_boolean_mono_info,
+       .get = vt1708_jack_detect_get,
+       .put = vt1708_jack_detect_put,
+};
+
+static const struct badness_table via_main_out_badness = {
+       .no_primary_dac = 0x10000,
+       .no_dac = 0x4000,
+       .shared_primary = 0x10000,
+       .shared_surr = 0x20,
+       .shared_clfe = 0x20,
+       .shared_surr_main = 0x20,
+};
+static const struct badness_table via_extra_out_badness = {
+       .no_primary_dac = 0x4000,
+       .no_dac = 0x4000,
+       .shared_primary = 0x12,
+       .shared_surr = 0x20,
+       .shared_clfe = 0x20,
+       .shared_surr_main = 0x10,
+};
+
+static int via_parse_auto_config(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int err;
+
+       spec->gen.main_out_badness = &via_main_out_badness;
+       spec->gen.extra_out_badness = &via_extra_out_badness;
+
+       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
+       if (err < 0)
+               return err;
+
+       err = auto_parse_beep(codec);
+       if (err < 0)
+               return err;
+
+       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
+       if (err < 0)
+               return err;
+
+       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &via_pin_power_ctl_enum))
+               return -ENOMEM;
+
+       /* disable widget PM at start for compatibility */
+       codec->power_save_node = 0;
+       spec->gen.power_down_unused = 0;
+       return 0;
+}
+
+static int via_init(struct hda_codec *codec)
+{
+       /* init power states */
+       __analog_low_current_mode(codec, true);
+
+       snd_hda_gen_init(codec);
+
+       vt1708_update_hp_work(codec);
+
+       return 0;
+}
+
+static int vt1708_build_controls(struct hda_codec *codec)
+{
+       /* In order not to create "Phantom Jack" controls,
+          temporary enable jackpoll */
+       int err;
+       int old_interval = codec->jackpoll_interval;
+       codec->jackpoll_interval = msecs_to_jiffies(100);
+       err = snd_hda_gen_build_controls(codec);
+       codec->jackpoll_interval = old_interval;
+       return err;
+}
+
+static int vt1708_build_pcms(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int i, err;
+
+       err = snd_hda_gen_build_pcms(codec);
+       if (err < 0 || codec->core.vendor_id != 0x11061708)
+               return err;
+
+       /* We got noisy outputs on the right channel on VT1708 when
+        * 24bit samples are used.  Until any workaround is found,
+        * disable the 24bit format, so far.
+        */
+       for (i = 0; i < ARRAY_SIZE(spec->gen.pcm_rec); i++) {
+               struct hda_pcm *info = spec->gen.pcm_rec[i];
+               if (!info)
+                       continue;
+               if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams ||
+                   info->pcm_type != HDA_PCM_TYPE_AUDIO)
+                       continue;
+               info->stream[SNDRV_PCM_STREAM_PLAYBACK].formats =
+                       SNDRV_PCM_FMTBIT_S16_LE;
+       }
+
+       return 0;
+}
+
+static int patch_vt1708(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       /* override some patch_ops */
+       codec->patch_ops.build_controls = vt1708_build_controls;
+       codec->patch_ops.build_pcms = vt1708_build_pcms;
+       spec->gen.mixer_nid = 0x17;
+
+       /* set jackpoll_interval while parsing the codec */
+       codec->jackpoll_interval = msecs_to_jiffies(100);
+       spec->vt1708_jack_detect = 1;
+
+       /* don't support the input jack switching due to lack of unsol event */
+       /* (it may work with polling, though, but it needs testing) */
+       spec->gen.suppress_auto_mic = 1;
+       /* Some machines show the broken speaker mute */
+       spec->gen.auto_mute_via_amp = 1;
+
+       /* Add HP and CD pin config connect bit re-config action */
+       vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
+       vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
+
+       err = snd_hda_add_verbs(codec, vt1708_init_verbs);
+       if (err < 0)
+               goto error;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       /* add jack detect on/off control */
+       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       /* clear jackpoll_interval again; it's set dynamically */
+       codec->jackpoll_interval = 0;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+static int patch_vt1709(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x18;
+
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+static int patch_vt1708S(struct hda_codec *codec);
+static int patch_vt1708B(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       if (get_codec_type(codec) == VT1708BCE)
+               return patch_vt1708S(codec);
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x16;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+/* Patch for VT1708S */
+static const struct hda_verb vt1708S_init_verbs[] = {
+       /* Enable Mic Boost Volume backdoor */
+       {0x1, 0xf98, 0x1},
+       /* don't bybass mixer */
+       {0x1, 0xf88, 0xc0},
+       { }
+};
+
+static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
+                              int offset, int num_steps, int step_size)
+{
+       snd_hda_override_wcaps(codec, pin,
+                              get_wcaps(codec, pin) | AC_WCAP_IN_AMP);
+       snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
+                                 (offset << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (0 << AC_AMPCAP_MUTE_SHIFT));
+}
+
+static int patch_vt1708S(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x16;
+       override_mic_boost(codec, 0x1a, 0, 3, 40);
+       override_mic_boost(codec, 0x1e, 0, 3, 40);
+
+       /* correct names for VT1708BCE */
+       if (get_codec_type(codec) == VT1708BCE)
+               snd_hda_codec_set_name(codec, "VT1708BCE");
+       /* correct names for VT1705 */
+       if (codec->core.vendor_id == 0x11064397)
+               snd_hda_codec_set_name(codec, "VT1705");
+
+       err = snd_hda_add_verbs(codec, vt1708S_init_verbs);
+       if (err < 0)
+               goto error;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+/* Patch for VT1702 */
+
+static const struct hda_verb vt1702_init_verbs[] = {
+       /* mixer enable */
+       {0x1, 0xF88, 0x3},
+       /* GPIO 0~2 */
+       {0x1, 0xF82, 0x3F},
+       { }
+};
+
+static int patch_vt1702(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x1a;
+
+       /* limit AA path volume to 0 dB */
+       snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
+                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
+                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
+                                 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
+                                 (1 << AC_AMPCAP_MUTE_SHIFT));
+
+       err = snd_hda_add_verbs(codec, vt1702_init_verbs);
+       if (err < 0)
+               goto error;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+/* Patch for VT1718S */
+
+static const struct hda_verb vt1718S_init_verbs[] = {
+       /* Enable MW0 adjust Gain 5 */
+       {0x1, 0xfb2, 0x10},
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xf88, 0x8},
+
+       { }
+};
+
+/* Add a connection to the primary DAC from AA-mixer for some codecs
+ * This isn't listed from the raw info, but the chip has a secret connection.
+ */
+static int add_secret_dac_path(struct hda_codec *codec)
+{
+       struct via_spec *spec = codec->spec;
+       int i, nums;
+       hda_nid_t conn[8];
+       hda_nid_t nid;
+
+       if (!spec->gen.mixer_nid)
+               return 0;
+       nums = snd_hda_get_connections(codec, spec->gen.mixer_nid, conn,
+                                      ARRAY_SIZE(conn) - 1);
+       if (nums < 0)
+               return nums;
+
+       for (i = 0; i < nums; i++) {
+               if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT)
+                       return 0;
+       }
+
+       /* find the primary DAC and add to the connection list */
+       for_each_hda_codec_node(nid, codec) {
+               unsigned int caps = get_wcaps(codec, nid);
+               if (get_wcaps_type(caps) == AC_WID_AUD_OUT &&
+                   !(caps & AC_WCAP_DIGITAL)) {
+                       conn[nums++] = nid;
+                       return snd_hda_override_conn_list(codec,
+                                                         spec->gen.mixer_nid,
+                                                         nums, conn);
+               }
+       }
+       return 0;
+}
+
+
+static int patch_vt1718S(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x21;
+       override_mic_boost(codec, 0x2b, 0, 3, 40);
+       override_mic_boost(codec, 0x29, 0, 3, 40);
+       add_secret_dac_path(codec);
+
+       err = snd_hda_add_verbs(codec, vt1718S_init_verbs);
+       if (err < 0)
+               goto error;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+/* Patch for VT1716S */
+
+static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
+                           struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 1;
+       return 0;
+}
+
+static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       int index = 0;
+
+       index = snd_hda_codec_read(codec, 0x26, 0,
+                                              AC_VERB_GET_CONNECT_SEL, 0);
+       if (index != -1)
+               *ucontrol->value.integer.value = index;
+
+       return 0;
+}
+
+static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
+                          struct snd_ctl_elem_value *ucontrol)
+{
+       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+       struct via_spec *spec = codec->spec;
+       int index = *ucontrol->value.integer.value;
+
+       snd_hda_codec_write(codec, 0x26, 0,
+                                              AC_VERB_SET_CONNECT_SEL, index);
+       spec->dmic_enabled = index;
+       return 1;
+}
+
+static const struct snd_kcontrol_new vt1716s_dmic_mixer_vol =
+       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT);
+static const struct snd_kcontrol_new vt1716s_dmic_mixer_sw = {
+        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+        .name = "Digital Mic Capture Switch",
+        .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
+        .count = 1,
+        .info = vt1716s_dmic_info,
+        .get = vt1716s_dmic_get,
+        .put = vt1716s_dmic_put,
+};
+
+
+/* mono-out mixer elements */
+static const struct snd_kcontrol_new vt1716S_mono_out_mixer =
+       HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT);
+
+static const struct hda_verb vt1716S_init_verbs[] = {
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xf8a, 0x80},
+       /* don't bybass mixer */
+       {0x1, 0xf88, 0xc0},
+       /* Enable mono output */
+       {0x1, 0xf90, 0x08},
+       { }
+};
+
+static int patch_vt1716S(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x16;
+       override_mic_boost(codec, 0x1a, 0, 3, 40);
+       override_mic_boost(codec, 0x1e, 0, 3, 40);
+
+       err = snd_hda_add_verbs(codec, vt1716S_init_verbs);
+       if (err < 0)
+               goto error;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) ||
+           !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) ||
+           !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) {
+               err = -ENOMEM;
+               goto error;
+       }
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+/* for vt2002P */
+
+static const struct hda_verb vt2002P_init_verbs[] = {
+       /* Class-D speaker related verbs */
+       {0x1, 0xfe0, 0x4},
+       {0x1, 0xfe9, 0x80},
+       {0x1, 0xfe2, 0x22},
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xfb9, 0x24},
+       /* Enable AOW0 to MW9 */
+       {0x1, 0xfb8, 0x88},
+       { }
+};
+
+static const struct hda_verb vt1802_init_verbs[] = {
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xfb9, 0x24},
+       /* Enable AOW0 to MW9 */
+       {0x1, 0xfb8, 0x88},
+       { }
+};
+
+/*
+ * pin fix-up
+ */
+enum {
+       VIA_FIXUP_INTMIC_BOOST,
+       VIA_FIXUP_ASUS_G75,
+       VIA_FIXUP_POWER_SAVE,
+};
+
+static void via_fixup_intmic_boost(struct hda_codec *codec,
+                                 const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               override_mic_boost(codec, 0x30, 0, 2, 40);
+}
+
+static void via_fixup_power_save(struct hda_codec *codec,
+                                const struct hda_fixup *fix, int action)
+{
+       if (action == HDA_FIXUP_ACT_PRE_PROBE)
+               codec->power_save_node = 0;
+}
+
+static const struct hda_fixup via_fixups[] = {
+       [VIA_FIXUP_INTMIC_BOOST] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = via_fixup_intmic_boost,
+       },
+       [VIA_FIXUP_ASUS_G75] = {
+               .type = HDA_FIXUP_PINS,
+               .v.pins = (const struct hda_pintbl[]) {
+                       /* set 0x24 and 0x33 as speakers */
+                       { 0x24, 0x991301f0 },
+                       { 0x33, 0x991301f1 }, /* subwoofer */
+                       { }
+               }
+       },
+       [VIA_FIXUP_POWER_SAVE] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = via_fixup_power_save,
+       },
+};
+
+static const struct hda_quirk vt2002p_fixups[] = {
+       SND_PCI_QUIRK(0x1043, 0x13f7, "Asus B23E", VIA_FIXUP_POWER_SAVE),
+       SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75),
+       SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),
+       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", VIA_FIXUP_POWER_SAVE),
+       {}
+};
+
+/* NIDs 0x24 and 0x33 on VT1802 have connections to non-existing NID 0x3e
+ * Replace this with mixer NID 0x1c
+ */
+static void fix_vt1802_connections(struct hda_codec *codec)
+{
+       static const hda_nid_t conn_24[] = { 0x14, 0x1c };
+       static const hda_nid_t conn_33[] = { 0x1c };
+
+       snd_hda_override_conn_list(codec, 0x24, ARRAY_SIZE(conn_24), conn_24);
+       snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33);
+}
+
+/* patch for vt2002P */
+static int patch_vt2002P(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x21;
+       override_mic_boost(codec, 0x2b, 0, 3, 40);
+       override_mic_boost(codec, 0x29, 0, 3, 40);
+       if (spec->codec_type == VT1802)
+               fix_vt1802_connections(codec);
+       add_secret_dac_path(codec);
+
+       snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);
+       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
+
+       if (spec->codec_type == VT1802)
+               err = snd_hda_add_verbs(codec, vt1802_init_verbs);
+       else
+               err = snd_hda_add_verbs(codec, vt2002P_init_verbs);
+       if (err < 0)
+               goto error;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+/* for vt1812 */
+
+static const struct hda_verb vt1812_init_verbs[] = {
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xfb9, 0x24},
+       /* Enable AOW0 to MW9 */
+       {0x1, 0xfb8, 0xa8},
+       { }
+};
+
+/* patch for vt1812 */
+static int patch_vt1812(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x21;
+       override_mic_boost(codec, 0x2b, 0, 3, 40);
+       override_mic_boost(codec, 0x29, 0, 3, 40);
+       add_secret_dac_path(codec);
+
+       err = snd_hda_add_verbs(codec, vt1812_init_verbs);
+       if (err < 0)
+               goto error;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+/* patch for vt3476 */
+
+static const struct hda_verb vt3476_init_verbs[] = {
+       /* Enable DMic 8/16/32K */
+       {0x1, 0xF7B, 0x30},
+       /* Enable Boost Volume backdoor */
+       {0x1, 0xFB9, 0x20},
+       /* Enable AOW-MW9 path */
+       {0x1, 0xFB8, 0x10},
+       { }
+};
+
+static int patch_vt3476(struct hda_codec *codec)
+{
+       struct via_spec *spec;
+       int err;
+
+       /* create a codec specific record */
+       spec = via_new_spec(codec);
+       if (spec == NULL)
+               return -ENOMEM;
+
+       spec->gen.mixer_nid = 0x3f;
+       add_secret_dac_path(codec);
+
+       err = snd_hda_add_verbs(codec, vt3476_init_verbs);
+       if (err < 0)
+               goto error;
+
+       /* automatic parse from the BIOS config */
+       err = via_parse_auto_config(codec);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+ error:
+       via_free(codec);
+       return err;
+}
+
+/*
+ * patch entries
+ */
+static const struct hda_device_id snd_hda_id_via[] = {
+       HDA_CODEC_ENTRY(0x11061708, "VT1708", patch_vt1708),
+       HDA_CODEC_ENTRY(0x11061709, "VT1708", patch_vt1708),
+       HDA_CODEC_ENTRY(0x1106170a, "VT1708", patch_vt1708),
+       HDA_CODEC_ENTRY(0x1106170b, "VT1708", patch_vt1708),
+       HDA_CODEC_ENTRY(0x1106e710, "VT1709 10-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e711, "VT1709 10-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e712, "VT1709 10-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e713, "VT1709 10-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e714, "VT1709 6-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e715, "VT1709 6-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e716, "VT1709 6-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e717, "VT1709 6-Ch", patch_vt1709),
+       HDA_CODEC_ENTRY(0x1106e720, "VT1708B 8-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e721, "VT1708B 8-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e722, "VT1708B 8-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e723, "VT1708B 8-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e724, "VT1708B 4-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e725, "VT1708B 4-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e726, "VT1708B 4-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x1106e727, "VT1708B 4-Ch", patch_vt1708B),
+       HDA_CODEC_ENTRY(0x11060397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11061397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11062397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11063397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11064397, "VT1705", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11065397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11066397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11067397, "VT1708S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11060398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11061398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11062398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11063398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11064398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11065398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11066398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11067398, "VT1702", patch_vt1702),
+       HDA_CODEC_ENTRY(0x11060428, "VT1718S", patch_vt1718S),
+       HDA_CODEC_ENTRY(0x11064428, "VT1718S", patch_vt1718S),
+       HDA_CODEC_ENTRY(0x11060441, "VT2020", patch_vt1718S),
+       HDA_CODEC_ENTRY(0x11064441, "VT1828S", patch_vt1718S),
+       HDA_CODEC_ENTRY(0x11060433, "VT1716S", patch_vt1716S),
+       HDA_CODEC_ENTRY(0x1106a721, "VT1716S", patch_vt1716S),
+       HDA_CODEC_ENTRY(0x11060438, "VT2002P", patch_vt2002P),
+       HDA_CODEC_ENTRY(0x11064438, "VT2002P", patch_vt2002P),
+       HDA_CODEC_ENTRY(0x11060448, "VT1812", patch_vt1812),
+       HDA_CODEC_ENTRY(0x11060440, "VT1818S", patch_vt1708S),
+       HDA_CODEC_ENTRY(0x11060446, "VT1802", patch_vt2002P),
+       HDA_CODEC_ENTRY(0x11068446, "VT1802", patch_vt2002P),
+       HDA_CODEC_ENTRY(0x11064760, "VT1705CF", patch_vt3476),
+       HDA_CODEC_ENTRY(0x11064761, "VT1708SCE", patch_vt3476),
+       HDA_CODEC_ENTRY(0x11064762, "VT1808", patch_vt3476),
+       {} /* terminator */
+};
+MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_via);
+
+static struct hda_codec_driver via_driver = {
+       .id = snd_hda_id_via,
+};
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("VIA HD-audio codec");
+
+module_hda_codec_driver(via_driver);
index 787868c9e91b0c1648088439e7c956b8649fd1ea..e0996a9d90b033ed758cdbfd7698a12de40c31ac 100644 (file)
@@ -933,5 +933,3 @@ config SND_YMFPCI
          will be called snd-ymfpci.
 
 endif  # SND_PCI
-
-source "sound/pci/hda/Kconfig"
index 18b673018dfd609f82c5526a017d60e825e4c9eb..9d5e8e12ae73808e00a5270e1ff85990ac3d46e0 100644 (file)
@@ -69,7 +69,6 @@ obj-$(CONFIG_SND) += \
        lx6464es/ \
        echoaudio/ \
        emu10k1/ \
-       hda/ \
        ice1712/ \
        korg1212/ \
        mixart/ \
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
deleted file mode 100644 (file)
index a5d3455..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-menu "HD-Audio"
-
-config SND_HDA_GENERIC_LEDS
-       bool
-
-if SND_HDA
-
-config SND_HDA_CIRRUS_SCODEC
-       tristate
-
-config SND_HDA_CIRRUS_SCODEC_KUNIT_TEST
-       tristate "KUnit test for Cirrus side-codec library" if !KUNIT_ALL_TESTS
-       depends on SND_HDA_CIRRUS_SCODEC && GPIOLIB && KUNIT
-       default KUNIT_ALL_TESTS
-       help
-         This builds KUnit tests for the cirrus side-codec library.
-         For more information on KUnit and unit tests in general,
-         please refer to the KUnit documentation in
-         Documentation/dev-tools/kunit/.
-         If in doubt, say "N".
-
-config SND_HDA_SCODEC_CS35L41
-       tristate
-       select SND_HDA_GENERIC
-       select REGMAP_IRQ
-       select FW_CS_DSP
-
-config SND_HDA_SCODEC_COMPONENT
-       tristate
-
-config SND_HDA_SCODEC_CS35L41_I2C
-       tristate "Build CS35L41 HD-audio side codec support for I2C Bus"
-       depends on I2C
-       depends on ACPI
-       depends on EFI
-       depends on SND_SOC
-       select SND_SOC_CS35L41_LIB
-       select SND_HDA_SCODEC_CS35L41
-       select SND_SOC_CS_AMP_LIB
-       help
-         Say Y or M here to include CS35L41 I2C HD-audio side codec support
-         in snd-hda-intel driver, such as ALC287.
-
-comment "Set to Y if you want auto-loading the side codec driver"
-       depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_I2C=m
-
-config SND_HDA_SCODEC_CS35L41_SPI
-       tristate "Build CS35L41 HD-audio codec support for SPI Bus"
-       depends on SPI_MASTER
-       depends on ACPI
-       depends on EFI
-       depends on SND_SOC
-       select SND_SOC_CS35L41_LIB
-       select SND_HDA_SCODEC_CS35L41
-       select SND_SOC_CS_AMP_LIB
-       help
-         Say Y or M here to include CS35L41 SPI HD-audio side codec support
-         in snd-hda-intel driver, such as ALC287.
-
-comment "Set to Y if you want auto-loading the side codec driver"
-       depends on SND_HDA=y && SND_HDA_SCODEC_CS35L41_SPI=m
-
-config SND_HDA_SCODEC_CS35L56
-       tristate
-
-config SND_HDA_SCODEC_CS35L56_I2C
-       tristate "Build CS35L56 HD-audio side codec support for I2C Bus"
-       depends on I2C
-       depends on ACPI
-       depends on SND_SOC
-       select FW_CS_DSP
-       imply SERIAL_MULTI_INSTANTIATE
-       select SND_HDA_GENERIC
-       select SND_SOC_CS35L56_SHARED
-       select SND_HDA_SCODEC_CS35L56
-       select SND_HDA_CIRRUS_SCODEC
-       select SND_SOC_CS_AMP_LIB
-       help
-         Say Y or M here to include CS35L56 amplifier support with
-         I2C control.
-
-config SND_HDA_SCODEC_CS35L56_SPI
-       tristate "Build CS35L56 HD-audio side codec support for SPI Bus"
-       depends on SPI_MASTER
-       depends on ACPI
-       depends on SND_SOC
-       select FW_CS_DSP
-       imply SERIAL_MULTI_INSTANTIATE
-       select SND_HDA_GENERIC
-       select SND_SOC_CS35L56_SHARED
-       select SND_HDA_SCODEC_CS35L56
-       select SND_HDA_CIRRUS_SCODEC
-       select SND_SOC_CS_AMP_LIB
-       help
-         Say Y or M here to include CS35L56 amplifier support with
-         SPI control.
-
-config SND_HDA_SCODEC_TAS2781
-       tristate
-       select SND_HDA_GENERIC
-
-config SND_HDA_SCODEC_TAS2781_I2C
-       tristate "Build TAS2781 HD-audio side codec support for I2C Bus"
-       depends on I2C
-       depends on ACPI
-       depends on EFI
-       depends on SND_SOC
-       select SND_HDA_SCODEC_TAS2781
-       select SND_SOC_TAS2781_COMLIB_I2C
-       select SND_SOC_TAS2781_FMWLIB
-       select CRC32
-       help
-         Say Y or M here to include TAS2781 I2C HD-audio side codec support
-         in snd-hda-intel driver, such as ALC287.
-
-comment "Set to Y if you want auto-loading the side codec driver"
-       depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m
-
-config SND_HDA_SCODEC_TAS2781_SPI
-       tristate "Build TAS2781 HD-audio side codec support for SPI Bus"
-       depends on SPI_MASTER
-       depends on ACPI
-       depends on EFI
-       depends on SND_SOC
-       select SND_HDA_SCODEC_TAS2781
-       select SND_SOC_TAS2781_COMLIB
-       select SND_SOC_TAS2781_FMWLIB
-       select CRC8
-       select CRC32
-       help
-         Say Y or M here to include TAS2781 SPI HD-audio side codec support
-         in snd-hda-intel driver, such as ALC287.
-
-comment "Set to Y if you want auto-loading the side codec driver"
-       depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m
-
-config SND_HDA_CODEC_REALTEK
-       tristate "Build Realtek HD-audio codec support"
-       depends on INPUT
-       select SND_HDA_GENERIC
-       select SND_HDA_GENERIC_LEDS
-       select SND_HDA_SCODEC_COMPONENT
-       help
-         Say Y or M here to include Realtek HD-audio codec support in
-         snd-hda-intel driver, such as ALC880.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m
-
-config SND_HDA_CODEC_ANALOG
-       tristate "Build Analog Devices HD-audio codec support"
-       select SND_HDA_GENERIC
-       help
-         Say Y or M here to include Analog Devices HD-audio codec support in
-         snd-hda-intel driver, such as AD1986A.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_ANALOG=m
-
-config SND_HDA_CODEC_SIGMATEL
-       tristate "Build IDT/Sigmatel HD-audio codec support"
-       select SND_HDA_GENERIC
-       select SND_HDA_GENERIC_LEDS
-       help
-         Say Y or M here to include IDT (Sigmatel) HD-audio codec support in
-         snd-hda-intel driver, such as STAC9200.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_SIGMATEL=m
-
-config SND_HDA_CODEC_VIA
-       tristate "Build VIA HD-audio codec support"
-       select SND_HDA_GENERIC
-       help
-         Say Y or M here to include VIA HD-audio codec support in
-         snd-hda-intel driver, such as VT1708.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_VIA=m
-
-config SND_HDA_CODEC_HDMI
-       tristate "Build HDMI/DisplayPort HD-audio codec support"
-       select SND_DYNAMIC_MINORS
-       select SND_PCM_ELD
-       help
-         Say Y or M here to include HDMI and DisplayPort HD-audio codec
-         support in snd-hda-intel driver.  This includes all AMD/ATI,
-         Intel and Nvidia HDMI/DisplayPort codecs.
-
-         Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS
-         to assure the multiple streams for DP-MST support.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m
-
-config SND_HDA_CODEC_CIRRUS
-       tristate "Build Cirrus Logic codec support"
-       select SND_HDA_GENERIC
-       help
-         Say Y or M here to include Cirrus Logic codec support in
-         snd-hda-intel driver, such as CS4206.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m
-
-config SND_HDA_CODEC_CS8409
-       tristate "Build Cirrus Logic HDA bridge support"
-       select SND_HDA_GENERIC
-       help
-         Say Y or M here to include Cirrus Logic HDA bridge support in
-         snd-hda-intel driver, such as CS8409.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_CS8409=m
-
-config SND_HDA_CODEC_CONEXANT
-       tristate "Build Conexant HD-audio codec support"
-       select SND_HDA_GENERIC
-       select SND_HDA_GENERIC_LEDS
-       help
-         Say Y or M here to include Conexant HD-audio codec support in
-         snd-hda-intel driver, such as CX20549.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m
-
-config SND_HDA_CODEC_SENARYTECH
-       tristate "Build Senarytech HD-audio codec support"
-       select SND_HDA_GENERIC
-       select SND_HDA_GENERIC_LEDS
-       help
-         Say Y or M here to include Senarytech HD-audio codec support in
-         snd-hda-intel driver, such as SN6186.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_SENARYTECH=m
-
-config SND_HDA_CODEC_CA0110
-       tristate "Build Creative CA0110-IBG codec support"
-       select SND_HDA_GENERIC
-       help
-         Say Y or M here to include Creative CA0110-IBG codec support in
-         snd-hda-intel driver, found on some Creative X-Fi cards.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_CA0110=m
-
-config SND_HDA_CODEC_CA0132
-       tristate "Build Creative CA0132 codec support"
-       help
-         Say Y or M here to include Creative CA0132 codec support in
-         snd-hda-intel driver.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_CA0132=m
-
-config SND_HDA_CODEC_CA0132_DSP
-       bool "Support new DSP code for CA0132 codec"
-       depends on SND_HDA_CODEC_CA0132
-       default y
-       select SND_HDA_DSP_LOADER
-       select FW_LOADER
-       help
-         Say Y here to enable the DSP for Creative CA0132 for extended
-         features like equalizer or echo cancellation.
-
-         Note that this option requires the external firmware file
-         (ctefx.bin).
-
-config SND_HDA_CODEC_CMEDIA
-       tristate "Build C-Media HD-audio codec support"
-       select SND_HDA_GENERIC
-       help
-         Say Y or M here to include C-Media HD-audio codec support in
-         snd-hda-intel driver, such as CMI9880.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m
-
-config SND_HDA_CODEC_SI3054
-       tristate "Build Silicon Labs 3054 HD-modem codec support"
-       help
-         Say Y or M here to include Silicon Labs 3054 HD-modem codec
-         (and compatibles) support in snd-hda-intel driver.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_CODEC_SI3054=m
-
-config SND_HDA_GENERIC
-       tristate "Enable generic HD-audio codec parser"
-       select SND_CTL_LED if SND_HDA_GENERIC_LEDS
-       select LEDS_CLASS if SND_HDA_GENERIC_LEDS
-       help
-         Say Y or M here to enable the generic HD-audio codec parser
-         in snd-hda-intel driver.
-
-comment "Set to Y if you want auto-loading the codec driver"
-       depends on SND_HDA=y && SND_HDA_GENERIC=m
-
-config SND_HDA_INTEL_HDMI_SILENT_STREAM
-       bool "Enable Silent Stream always for HDMI"
-       depends on SND_HDA_INTEL
-       help
-         Say Y to enable HD-Audio Keep Alive (KAE) aka Silent Stream
-         for HDMI on hardware that supports the feature.
-
-         When enabled, the HDMI/DisplayPort codec will continue to provide
-         a continuous clock and a valid but silent data stream to
-         any connected external receiver. This allows to avoid gaps
-         at start of playback. Many receivers require multiple seconds
-         to start playing audio after the clock has been stopped.
-         This feature can impact power consumption as resources
-         are kept reserved both at transmitter and receiver.
-
-endif
-
-endmenu
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
deleted file mode 100644 (file)
index 79de0af..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-subdir-ccflags-y += -I$(src)/../../hda/common
-
-snd-hda-codec-generic-y :=     hda_generic.o
-snd-hda-codec-realtek-y :=     patch_realtek.o
-snd-hda-codec-cmedia-y :=      patch_cmedia.o
-snd-hda-codec-analog-y :=      patch_analog.o
-snd-hda-codec-idt-y :=         patch_sigmatel.o
-snd-hda-codec-si3054-y :=      patch_si3054.o
-snd-hda-codec-cirrus-y :=      patch_cirrus.o
-snd-hda-codec-cs8409-y :=      patch_cs8409.o patch_cs8409-tables.o
-snd-hda-codec-ca0110-y :=      patch_ca0110.o
-snd-hda-codec-ca0132-y :=      patch_ca0132.o
-snd-hda-codec-conexant-y :=    patch_conexant.o
-snd-hda-codec-senarytech-y :=patch_senarytech.o
-snd-hda-codec-via-y :=         patch_via.o
-snd-hda-codec-hdmi-y :=                patch_hdmi.o hda_eld.o
-
-# side codecs
-snd-hda-cirrus-scodec-y :=     cirrus_scodec.o
-snd-hda-cirrus-scodec-test-y :=        cirrus_scodec_test.o
-snd-hda-scodec-cs35l41-y :=    cs35l41_hda.o cs35l41_hda_property.o
-snd-hda-scodec-cs35l41-i2c-y :=        cs35l41_hda_i2c.o
-snd-hda-scodec-cs35l41-spi-y :=        cs35l41_hda_spi.o
-snd-hda-scodec-cs35l56-y :=    cs35l56_hda.o
-snd-hda-scodec-cs35l56-i2c-y :=        cs35l56_hda_i2c.o
-snd-hda-scodec-cs35l56-spi-y :=        cs35l56_hda_spi.o
-snd-hda-scodec-component-y :=  hda_component.o
-snd-hda-scodec-tas2781-y :=    tas2781_hda.o
-snd-hda-scodec-tas2781-i2c-y :=        tas2781_hda_i2c.o
-snd-hda-scodec-tas2781-spi-y :=        tas2781_hda_spi.o
-
-# codec drivers
-obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o
-obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o
-obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o
-obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o
-obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o
-obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o
-obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o
-obj-$(CONFIG_SND_HDA_CODEC_CS8409) += snd-hda-codec-cs8409.o
-obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o
-obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o
-obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o
-obj-$(CONFIG_SND_HDA_CODEC_SENARYTECH) += snd-hda-codec-senarytech.o
-obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o
-obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o
-
-# side codecs
-obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC) += snd-hda-cirrus-scodec.o
-obj-$(CONFIG_SND_HDA_CIRRUS_SCODEC_KUNIT_TEST) += snd-hda-cirrus-scodec-test.o
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L41) += snd-hda-scodec-cs35l41.o
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_I2C) += snd-hda-scodec-cs35l41-i2c.o
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L41_SPI) += snd-hda-scodec-cs35l41-spi.o
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
-obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
-obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
-obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o
-obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
-obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
diff --git a/sound/pci/hda/ca0132_regs.h b/sound/pci/hda/ca0132_regs.h
deleted file mode 100644 (file)
index 0ead571..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * HD audio interface patch for Creative CA0132 chip.
- * CA0132 registers defines.
- *
- * Copyright (c) 2011, Creative Technology Ltd.
- */
-
-#ifndef __CA0132_REGS_H
-#define __CA0132_REGS_H
-
-#define DSP_CHIP_OFFSET                0x100000
-#define DSP_DBGCNTL_MODULE_OFFSET      0xE30
-#define DSP_DBGCNTL_INST_OFFSET \
-       (DSP_CHIP_OFFSET + DSP_DBGCNTL_MODULE_OFFSET)
-
-#define DSP_DBGCNTL_EXEC_LOBIT         0x0
-#define DSP_DBGCNTL_EXEC_HIBIT         0x3
-#define DSP_DBGCNTL_EXEC_MASK          0xF
-
-#define DSP_DBGCNTL_SS_LOBIT           0x4
-#define DSP_DBGCNTL_SS_HIBIT           0x7
-#define DSP_DBGCNTL_SS_MASK            0xF0
-
-#define DSP_DBGCNTL_STATE_LOBIT        0xA
-#define DSP_DBGCNTL_STATE_HIBIT        0xD
-#define DSP_DBGCNTL_STATE_MASK         0x3C00
-
-#define XRAM_CHIP_OFFSET               0x0
-#define XRAM_XRAM_CHANNEL_COUNT        0xE000
-#define XRAM_XRAM_MODULE_OFFSET        0x0
-#define XRAM_XRAM_CHAN_INCR            4
-#define XRAM_XRAM_INST_OFFSET(_chan) \
-       (XRAM_CHIP_OFFSET + XRAM_XRAM_MODULE_OFFSET + \
-       (_chan * XRAM_XRAM_CHAN_INCR))
-
-#define YRAM_CHIP_OFFSET               0x40000
-#define YRAM_YRAM_CHANNEL_COUNT        0x8000
-#define YRAM_YRAM_MODULE_OFFSET        0x0
-#define YRAM_YRAM_CHAN_INCR            4
-#define YRAM_YRAM_INST_OFFSET(_chan) \
-       (YRAM_CHIP_OFFSET + YRAM_YRAM_MODULE_OFFSET + \
-       (_chan * YRAM_YRAM_CHAN_INCR))
-
-#define UC_CHIP_OFFSET                 0x80000
-#define UC_UC_CHANNEL_COUNT            0x10000
-#define UC_UC_MODULE_OFFSET            0x0
-#define UC_UC_CHAN_INCR                4
-#define UC_UC_INST_OFFSET(_chan) \
-       (UC_CHIP_OFFSET + UC_UC_MODULE_OFFSET + \
-       (_chan * UC_UC_CHAN_INCR))
-
-#define AXRAM_CHIP_OFFSET              0x3C000
-#define AXRAM_AXRAM_CHANNEL_COUNT      0x1000
-#define AXRAM_AXRAM_MODULE_OFFSET      0x0
-#define AXRAM_AXRAM_CHAN_INCR          4
-#define AXRAM_AXRAM_INST_OFFSET(_chan) \
-       (AXRAM_CHIP_OFFSET + AXRAM_AXRAM_MODULE_OFFSET + \
-       (_chan * AXRAM_AXRAM_CHAN_INCR))
-
-#define AYRAM_CHIP_OFFSET              0x78000
-#define AYRAM_AYRAM_CHANNEL_COUNT      0x1000
-#define AYRAM_AYRAM_MODULE_OFFSET      0x0
-#define AYRAM_AYRAM_CHAN_INCR          4
-#define AYRAM_AYRAM_INST_OFFSET(_chan) \
-       (AYRAM_CHIP_OFFSET + AYRAM_AYRAM_MODULE_OFFSET + \
-       (_chan * AYRAM_AYRAM_CHAN_INCR))
-
-#define DSPDMAC_CHIP_OFFSET            0x110000
-#define DSPDMAC_DMA_CFG_CHANNEL_COUNT  12
-#define DSPDMAC_DMACFG_MODULE_OFFSET   0xF00
-#define DSPDMAC_DMACFG_CHAN_INCR       0x10
-#define DSPDMAC_DMACFG_INST_OFFSET(_chan) \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DMACFG_MODULE_OFFSET + \
-       (_chan * DSPDMAC_DMACFG_CHAN_INCR))
-
-#define DSPDMAC_DMACFG_DBADR_LOBIT     0x0
-#define DSPDMAC_DMACFG_DBADR_HIBIT     0x10
-#define DSPDMAC_DMACFG_DBADR_MASK      0x1FFFF
-#define DSPDMAC_DMACFG_LP_LOBIT        0x11
-#define DSPDMAC_DMACFG_LP_HIBIT        0x11
-#define DSPDMAC_DMACFG_LP_MASK         0x20000
-
-#define DSPDMAC_DMACFG_AINCR_LOBIT     0x12
-#define DSPDMAC_DMACFG_AINCR_HIBIT     0x12
-#define DSPDMAC_DMACFG_AINCR_MASK      0x40000
-
-#define DSPDMAC_DMACFG_DWR_LOBIT       0x13
-#define DSPDMAC_DMACFG_DWR_HIBIT       0x13
-#define DSPDMAC_DMACFG_DWR_MASK        0x80000
-
-#define DSPDMAC_DMACFG_AJUMP_LOBIT     0x14
-#define DSPDMAC_DMACFG_AJUMP_HIBIT     0x17
-#define DSPDMAC_DMACFG_AJUMP_MASK      0xF00000
-
-#define DSPDMAC_DMACFG_AMODE_LOBIT     0x18
-#define DSPDMAC_DMACFG_AMODE_HIBIT     0x19
-#define DSPDMAC_DMACFG_AMODE_MASK      0x3000000
-
-#define DSPDMAC_DMACFG_LK_LOBIT        0x1A
-#define DSPDMAC_DMACFG_LK_HIBIT        0x1A
-#define DSPDMAC_DMACFG_LK_MASK         0x4000000
-
-#define DSPDMAC_DMACFG_AICS_LOBIT      0x1B
-#define DSPDMAC_DMACFG_AICS_HIBIT      0x1F
-#define DSPDMAC_DMACFG_AICS_MASK       0xF8000000
-
-#define DSPDMAC_DMACFG_LP_SINGLE                 0
-#define DSPDMAC_DMACFG_LP_LOOPING                1
-
-#define DSPDMAC_DMACFG_AINCR_XANDY               0
-#define DSPDMAC_DMACFG_AINCR_XORY                1
-
-#define DSPDMAC_DMACFG_DWR_DMA_RD                0
-#define DSPDMAC_DMACFG_DWR_DMA_WR                1
-
-#define DSPDMAC_DMACFG_AMODE_LINEAR              0
-#define DSPDMAC_DMACFG_AMODE_RSV1                1
-#define DSPDMAC_DMACFG_AMODE_WINTLV              2
-#define DSPDMAC_DMACFG_AMODE_GINTLV              3
-
-#define DSPDMAC_DSP_ADR_OFS_CHANNEL_COUNT 12
-#define DSPDMAC_DSPADROFS_MODULE_OFFSET 0xF04
-#define DSPDMAC_DSPADROFS_CHAN_INCR    0x10
-#define DSPDMAC_DSPADROFS_INST_OFFSET(_chan) \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADROFS_MODULE_OFFSET + \
-       (_chan * DSPDMAC_DSPADROFS_CHAN_INCR))
-
-#define DSPDMAC_DSPADROFS_COFS_LOBIT   0x0
-#define DSPDMAC_DSPADROFS_COFS_HIBIT   0xF
-#define DSPDMAC_DSPADROFS_COFS_MASK    0xFFFF
-
-#define DSPDMAC_DSPADROFS_BOFS_LOBIT   0x10
-#define DSPDMAC_DSPADROFS_BOFS_HIBIT   0x1F
-#define DSPDMAC_DSPADROFS_BOFS_MASK    0xFFFF0000
-
-#define DSPDMAC_DSP_ADR_WOFS_CHANNEL_COUNT 12
-#define DSPDMAC_DSPADRWOFS_MODULE_OFFSET 0xF04
-#define DSPDMAC_DSPADRWOFS_CHAN_INCR   0x10
-
-#define DSPDMAC_DSPADRWOFS_INST_OFFSET(_chan) \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRWOFS_MODULE_OFFSET + \
-       (_chan * DSPDMAC_DSPADRWOFS_CHAN_INCR))
-
-#define DSPDMAC_DSPADRWOFS_WCOFS_LOBIT 0x0
-#define DSPDMAC_DSPADRWOFS_WCOFS_HIBIT 0xA
-#define DSPDMAC_DSPADRWOFS_WCOFS_MASK  0x7FF
-
-#define DSPDMAC_DSPADRWOFS_WCBFR_LOBIT 0xB
-#define DSPDMAC_DSPADRWOFS_WCBFR_HIBIT 0xF
-#define DSPDMAC_DSPADRWOFS_WCBFR_MASK  0xF800
-
-#define DSPDMAC_DSPADRWOFS_WBOFS_LOBIT 0x10
-#define DSPDMAC_DSPADRWOFS_WBOFS_HIBIT 0x1A
-#define DSPDMAC_DSPADRWOFS_WBOFS_MASK  0x7FF0000
-
-#define DSPDMAC_DSPADRWOFS_WBBFR_LOBIT 0x1B
-#define DSPDMAC_DSPADRWOFS_WBBFR_HIBIT 0x1F
-#define DSPDMAC_DSPADRWOFS_WBBFR_MASK  0xF8000000
-
-#define DSPDMAC_DSP_ADR_GOFS_CHANNEL_COUNT 12
-#define DSPDMAC_DSPADRGOFS_MODULE_OFFSET 0xF04
-#define DSPDMAC_DSPADRGOFS_CHAN_INCR   0x10
-#define DSPDMAC_DSPADRGOFS_INST_OFFSET(_chan) \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRGOFS_MODULE_OFFSET + \
-       (_chan * DSPDMAC_DSPADRGOFS_CHAN_INCR))
-
-#define DSPDMAC_DSPADRGOFS_GCOFS_LOBIT 0x0
-#define DSPDMAC_DSPADRGOFS_GCOFS_HIBIT 0x9
-#define DSPDMAC_DSPADRGOFS_GCOFS_MASK  0x3FF
-
-#define DSPDMAC_DSPADRGOFS_GCS_LOBIT   0xA
-#define DSPDMAC_DSPADRGOFS_GCS_HIBIT   0xC
-#define DSPDMAC_DSPADRGOFS_GCS_MASK    0x1C00
-
-#define DSPDMAC_DSPADRGOFS_GCBFR_LOBIT 0xD
-#define DSPDMAC_DSPADRGOFS_GCBFR_HIBIT 0xF
-#define DSPDMAC_DSPADRGOFS_GCBFR_MASK  0xE000
-
-#define DSPDMAC_DSPADRGOFS_GBOFS_LOBIT 0x10
-#define DSPDMAC_DSPADRGOFS_GBOFS_HIBIT 0x19
-#define DSPDMAC_DSPADRGOFS_GBOFS_MASK  0x3FF0000
-
-#define DSPDMAC_DSPADRGOFS_GBS_LOBIT   0x1A
-#define DSPDMAC_DSPADRGOFS_GBS_HIBIT   0x1C
-#define DSPDMAC_DSPADRGOFS_GBS_MASK    0x1C000000
-
-#define DSPDMAC_DSPADRGOFS_GBBFR_LOBIT 0x1D
-#define DSPDMAC_DSPADRGOFS_GBBFR_HIBIT 0x1F
-#define DSPDMAC_DSPADRGOFS_GBBFR_MASK  0xE0000000
-
-#define DSPDMAC_XFR_CNT_CHANNEL_COUNT  12
-#define DSPDMAC_XFRCNT_MODULE_OFFSET   0xF08
-#define DSPDMAC_XFRCNT_CHAN_INCR       0x10
-
-#define DSPDMAC_XFRCNT_INST_OFFSET(_chan) \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_XFRCNT_MODULE_OFFSET + \
-       (_chan * DSPDMAC_XFRCNT_CHAN_INCR))
-
-#define DSPDMAC_XFRCNT_CCNT_LOBIT      0x0
-#define DSPDMAC_XFRCNT_CCNT_HIBIT      0xF
-#define DSPDMAC_XFRCNT_CCNT_MASK       0xFFFF
-
-#define DSPDMAC_XFRCNT_BCNT_LOBIT      0x10
-#define DSPDMAC_XFRCNT_BCNT_HIBIT      0x1F
-#define DSPDMAC_XFRCNT_BCNT_MASK       0xFFFF0000
-
-#define DSPDMAC_IRQ_CNT_CHANNEL_COUNT  12
-#define DSPDMAC_IRQCNT_MODULE_OFFSET   0xF0C
-#define DSPDMAC_IRQCNT_CHAN_INCR       0x10
-#define DSPDMAC_IRQCNT_INST_OFFSET(_chan) \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_IRQCNT_MODULE_OFFSET + \
-       (_chan * DSPDMAC_IRQCNT_CHAN_INCR))
-
-#define DSPDMAC_IRQCNT_CICNT_LOBIT     0x0
-#define DSPDMAC_IRQCNT_CICNT_HIBIT     0xF
-#define DSPDMAC_IRQCNT_CICNT_MASK      0xFFFF
-
-#define DSPDMAC_IRQCNT_BICNT_LOBIT     0x10
-#define DSPDMAC_IRQCNT_BICNT_HIBIT     0x1F
-#define DSPDMAC_IRQCNT_BICNT_MASK      0xFFFF0000
-
-#define DSPDMAC_AUD_CHSEL_CHANNEL_COUNT 12
-#define DSPDMAC_AUDCHSEL_MODULE_OFFSET 0xFC0
-#define DSPDMAC_AUDCHSEL_CHAN_INCR     0x4
-#define DSPDMAC_AUDCHSEL_INST_OFFSET(_chan) \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_AUDCHSEL_MODULE_OFFSET + \
-       (_chan * DSPDMAC_AUDCHSEL_CHAN_INCR))
-
-#define DSPDMAC_AUDCHSEL_ACS_LOBIT     0x0
-#define DSPDMAC_AUDCHSEL_ACS_HIBIT     0x1F
-#define DSPDMAC_AUDCHSEL_ACS_MASK      0xFFFFFFFF
-
-#define DSPDMAC_CHNLSTART_MODULE_OFFSET 0xFF0
-#define DSPDMAC_CHNLSTART_INST_OFFSET \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTART_MODULE_OFFSET)
-
-#define DSPDMAC_CHNLSTART_EN_LOBIT     0x0
-#define DSPDMAC_CHNLSTART_EN_HIBIT     0xB
-#define DSPDMAC_CHNLSTART_EN_MASK      0xFFF
-
-#define DSPDMAC_CHNLSTART_VAI1_LOBIT   0xC
-#define DSPDMAC_CHNLSTART_VAI1_HIBIT   0xF
-#define DSPDMAC_CHNLSTART_VAI1_MASK    0xF000
-
-#define DSPDMAC_CHNLSTART_DIS_LOBIT    0x10
-#define DSPDMAC_CHNLSTART_DIS_HIBIT    0x1B
-#define DSPDMAC_CHNLSTART_DIS_MASK     0xFFF0000
-
-#define DSPDMAC_CHNLSTART_VAI2_LOBIT   0x1C
-#define DSPDMAC_CHNLSTART_VAI2_HIBIT   0x1F
-#define DSPDMAC_CHNLSTART_VAI2_MASK    0xF0000000
-
-#define DSPDMAC_CHNLSTATUS_MODULE_OFFSET 0xFF4
-#define DSPDMAC_CHNLSTATUS_INST_OFFSET \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTATUS_MODULE_OFFSET)
-
-#define DSPDMAC_CHNLSTATUS_ISC_LOBIT   0x0
-#define DSPDMAC_CHNLSTATUS_ISC_HIBIT   0xB
-#define DSPDMAC_CHNLSTATUS_ISC_MASK    0xFFF
-
-#define DSPDMAC_CHNLSTATUS_AOO_LOBIT   0xC
-#define DSPDMAC_CHNLSTATUS_AOO_HIBIT   0xC
-#define DSPDMAC_CHNLSTATUS_AOO_MASK    0x1000
-
-#define DSPDMAC_CHNLSTATUS_AOU_LOBIT   0xD
-#define DSPDMAC_CHNLSTATUS_AOU_HIBIT   0xD
-#define DSPDMAC_CHNLSTATUS_AOU_MASK    0x2000
-
-#define DSPDMAC_CHNLSTATUS_AIO_LOBIT   0xE
-#define DSPDMAC_CHNLSTATUS_AIO_HIBIT   0xE
-#define DSPDMAC_CHNLSTATUS_AIO_MASK    0x4000
-
-#define DSPDMAC_CHNLSTATUS_AIU_LOBIT   0xF
-#define DSPDMAC_CHNLSTATUS_AIU_HIBIT   0xF
-#define DSPDMAC_CHNLSTATUS_AIU_MASK    0x8000
-
-#define DSPDMAC_CHNLSTATUS_IEN_LOBIT   0x10
-#define DSPDMAC_CHNLSTATUS_IEN_HIBIT   0x1B
-#define DSPDMAC_CHNLSTATUS_IEN_MASK    0xFFF0000
-
-#define DSPDMAC_CHNLSTATUS_VAI0_LOBIT  0x1C
-#define DSPDMAC_CHNLSTATUS_VAI0_HIBIT  0x1F
-#define DSPDMAC_CHNLSTATUS_VAI0_MASK   0xF0000000
-
-#define DSPDMAC_CHNLPROP_MODULE_OFFSET 0xFF8
-#define DSPDMAC_CHNLPROP_INST_OFFSET \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLPROP_MODULE_OFFSET)
-
-#define DSPDMAC_CHNLPROP_DCON_LOBIT    0x0
-#define DSPDMAC_CHNLPROP_DCON_HIBIT    0xB
-#define DSPDMAC_CHNLPROP_DCON_MASK     0xFFF
-
-#define DSPDMAC_CHNLPROP_FFS_LOBIT     0xC
-#define DSPDMAC_CHNLPROP_FFS_HIBIT     0xC
-#define DSPDMAC_CHNLPROP_FFS_MASK      0x1000
-
-#define DSPDMAC_CHNLPROP_NAJ_LOBIT     0xD
-#define DSPDMAC_CHNLPROP_NAJ_HIBIT     0xD
-#define DSPDMAC_CHNLPROP_NAJ_MASK      0x2000
-
-#define DSPDMAC_CHNLPROP_ENH_LOBIT     0xE
-#define DSPDMAC_CHNLPROP_ENH_HIBIT     0xE
-#define DSPDMAC_CHNLPROP_ENH_MASK      0x4000
-
-#define DSPDMAC_CHNLPROP_MSPCE_LOBIT   0x10
-#define DSPDMAC_CHNLPROP_MSPCE_HIBIT   0x1B
-#define DSPDMAC_CHNLPROP_MSPCE_MASK    0xFFF0000
-
-#define DSPDMAC_CHNLPROP_AC_LOBIT      0x1C
-#define DSPDMAC_CHNLPROP_AC_HIBIT      0x1F
-#define DSPDMAC_CHNLPROP_AC_MASK       0xF0000000
-
-#define DSPDMAC_ACTIVE_MODULE_OFFSET   0xFFC
-#define DSPDMAC_ACTIVE_INST_OFFSET \
-       (DSPDMAC_CHIP_OFFSET + DSPDMAC_ACTIVE_MODULE_OFFSET)
-
-#define DSPDMAC_ACTIVE_AAR_LOBIT       0x0
-#define DSPDMAC_ACTIVE_AAR_HIBIT       0xB
-#define DSPDMAC_ACTIVE_AAR_MASK        0xFFF
-
-#define DSPDMAC_ACTIVE_WFR_LOBIT       0xC
-#define DSPDMAC_ACTIVE_WFR_HIBIT       0x17
-#define DSPDMAC_ACTIVE_WFR_MASK        0xFFF000
-
-#define DSP_AUX_MEM_BASE            0xE000
-#define INVALID_CHIP_ADDRESS        (~0U)
-
-#define X_SIZE  (XRAM_XRAM_CHANNEL_COUNT   * XRAM_XRAM_CHAN_INCR)
-#define Y_SIZE  (YRAM_YRAM_CHANNEL_COUNT   * YRAM_YRAM_CHAN_INCR)
-#define AX_SIZE (AXRAM_AXRAM_CHANNEL_COUNT * AXRAM_AXRAM_CHAN_INCR)
-#define AY_SIZE (AYRAM_AYRAM_CHANNEL_COUNT * AYRAM_AYRAM_CHAN_INCR)
-#define UC_SIZE (UC_UC_CHANNEL_COUNT       * UC_UC_CHAN_INCR)
-
-#define XEXT_SIZE (X_SIZE + AX_SIZE)
-#define YEXT_SIZE (Y_SIZE + AY_SIZE)
-
-#define U64K 0x10000UL
-
-#define X_END  (XRAM_CHIP_OFFSET  + X_SIZE)
-#define X_EXT  (XRAM_CHIP_OFFSET  + XEXT_SIZE)
-#define AX_END (XRAM_CHIP_OFFSET  + U64K*4)
-
-#define Y_END  (YRAM_CHIP_OFFSET  + Y_SIZE)
-#define Y_EXT  (YRAM_CHIP_OFFSET  + YEXT_SIZE)
-#define AY_END (YRAM_CHIP_OFFSET  + U64K*4)
-
-#define UC_END (UC_CHIP_OFFSET    + UC_SIZE)
-
-#define X_RANGE_MAIN(a, s) \
-       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR <  X_END))
-#define X_RANGE_AUX(a, s)  \
-       (((a) >= X_END) && ((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
-#define X_RANGE_EXT(a, s)  \
-       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR <  X_EXT))
-#define X_RANGE_ALL(a, s)  \
-       (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END))
-
-#define Y_RANGE_MAIN(a, s) \
-       (((a) >= YRAM_CHIP_OFFSET) && \
-       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR <  Y_END))
-#define Y_RANGE_AUX(a, s)  \
-       (((a) >= Y_END) && \
-       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
-#define Y_RANGE_EXT(a, s)  \
-       (((a) >= YRAM_CHIP_OFFSET) && \
-       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR <  Y_EXT))
-#define Y_RANGE_ALL(a, s)  \
-       (((a) >= YRAM_CHIP_OFFSET) && \
-       ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END))
-
-#define UC_RANGE(a, s) \
-       (((a) >= UC_CHIP_OFFSET) && \
-       ((a)+((s)-1)*UC_UC_CHAN_INCR     < UC_END))
-
-#define X_OFF(a) \
-       (((a) - XRAM_CHIP_OFFSET) / XRAM_XRAM_CHAN_INCR)
-#define AX_OFF(a) \
-       (((a) % (AXRAM_AXRAM_CHANNEL_COUNT * \
-       AXRAM_AXRAM_CHAN_INCR)) / AXRAM_AXRAM_CHAN_INCR)
-
-#define Y_OFF(a) \
-       (((a) - YRAM_CHIP_OFFSET) / YRAM_YRAM_CHAN_INCR)
-#define AY_OFF(a) \
-       (((a) % (AYRAM_AYRAM_CHANNEL_COUNT * \
-       AYRAM_AYRAM_CHAN_INCR)) / AYRAM_AYRAM_CHAN_INCR)
-
-#define UC_OFF(a)  (((a) - UC_CHIP_OFFSET) / UC_UC_CHAN_INCR)
-
-#define X_EXT_MAIN_SIZE(a)  (XRAM_XRAM_CHANNEL_COUNT - X_OFF(a))
-#define X_EXT_AUX_SIZE(a, s) ((s) - X_EXT_MAIN_SIZE(a))
-
-#define Y_EXT_MAIN_SIZE(a)  (YRAM_YRAM_CHANNEL_COUNT - Y_OFF(a))
-#define Y_EXT_AUX_SIZE(a, s) ((s) - Y_EXT_MAIN_SIZE(a))
-
-#endif
diff --git a/sound/pci/hda/cirrus_scodec.c b/sound/pci/hda/cirrus_scodec.c
deleted file mode 100644 (file)
index 3c67020..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-//
-// Common code for Cirrus side-codecs.
-//
-// Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
-//               Cirrus Logic International Semiconductor Ltd.
-
-#include <linux/dev_printk.h>
-#include <linux/gpio/consumer.h>
-#include <linux/module.h>
-
-#include "cirrus_scodec.h"
-
-int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index,
-                                int num_amps, int fixed_gpio_id)
-{
-       struct gpio_desc *speaker_id_desc;
-       int speaker_id = -ENOENT;
-
-       if (fixed_gpio_id >= 0) {
-               dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id);
-               speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN);
-               if (IS_ERR(speaker_id_desc)) {
-                       speaker_id = PTR_ERR(speaker_id_desc);
-                       return speaker_id;
-               }
-               speaker_id = gpiod_get_value_cansleep(speaker_id_desc);
-               gpiod_put(speaker_id_desc);
-       } else {
-               int base_index;
-               int gpios_per_amp;
-               int count;
-               int tmp;
-               int i;
-
-               count = gpiod_count(dev, "spk-id");
-               if (count > 0) {
-                       speaker_id = 0;
-                       gpios_per_amp = count / num_amps;
-                       base_index = gpios_per_amp * amp_index;
-
-                       if (count % num_amps)
-                               return -EINVAL;
-
-                       dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp);
-
-                       for (i = 0; i < gpios_per_amp; i++) {
-                               speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index,
-                                                                 GPIOD_IN);
-                               if (IS_ERR(speaker_id_desc)) {
-                                       speaker_id = PTR_ERR(speaker_id_desc);
-                                       break;
-                               }
-                               tmp = gpiod_get_value_cansleep(speaker_id_desc);
-                               gpiod_put(speaker_id_desc);
-                               if (tmp < 0) {
-                                       speaker_id = tmp;
-                                       break;
-                               }
-                               speaker_id |= tmp << i;
-                       }
-               }
-       }
-
-       dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
-
-       return speaker_id;
-}
-EXPORT_SYMBOL_NS_GPL(cirrus_scodec_get_speaker_id, "SND_HDA_CIRRUS_SCODEC");
-
-MODULE_DESCRIPTION("HDA Cirrus side-codec library");
-MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/cirrus_scodec.h b/sound/pci/hda/cirrus_scodec.h
deleted file mode 100644 (file)
index ba2041d..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * Copyright (C) 2023 Cirrus Logic, Inc. and
- *                    Cirrus Logic International Semiconductor Ltd.
- */
-
-#ifndef CIRRUS_SCODEC_H
-#define CIRRUS_SCODEC_H
-
-int cirrus_scodec_get_speaker_id(struct device *dev, int amp_index,
-                                int num_amps, int fixed_gpio_id);
-
-#endif /* CIRRUS_SCODEC_H */
diff --git a/sound/pci/hda/cirrus_scodec_test.c b/sound/pci/hda/cirrus_scodec_test.c
deleted file mode 100644 (file)
index 93b9cbf..0000000
+++ /dev/null
@@ -1,332 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-//
-// KUnit test for the Cirrus side-codec library.
-//
-// Copyright (C) 2023 Cirrus Logic, Inc. and
-//                    Cirrus Logic International Semiconductor Ltd.
-
-#include <kunit/platform_device.h>
-#include <kunit/resource.h>
-#include <kunit/test.h>
-#include <linux/device.h>
-#include <linux/device/faux.h>
-#include <linux/gpio/driver.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include "cirrus_scodec.h"
-
-KUNIT_DEFINE_ACTION_WRAPPER(faux_device_destroy_wrapper, faux_device_destroy,
-                           struct faux_device *)
-KUNIT_DEFINE_ACTION_WRAPPER(device_remove_software_node_wrapper,
-                           device_remove_software_node,
-                           struct device *)
-
-struct cirrus_scodec_test_gpio {
-       unsigned int pin_state;
-       struct gpio_chip chip;
-};
-
-struct cirrus_scodec_test_priv {
-       struct faux_device *amp_dev;
-       struct platform_device *gpio_pdev;
-       struct cirrus_scodec_test_gpio *gpio_priv;
-};
-
-static int cirrus_scodec_test_gpio_get_direction(struct gpio_chip *chip,
-                                                unsigned int offset)
-{
-       return GPIO_LINE_DIRECTION_IN;
-}
-
-static int cirrus_scodec_test_gpio_direction_in(struct gpio_chip *chip,
-                                               unsigned int offset)
-{
-       return 0;
-}
-
-static int cirrus_scodec_test_gpio_get(struct gpio_chip *chip, unsigned int offset)
-{
-       struct cirrus_scodec_test_gpio *gpio_priv = gpiochip_get_data(chip);
-
-       return !!(gpio_priv->pin_state & BIT(offset));
-}
-
-static int cirrus_scodec_test_gpio_direction_out(struct gpio_chip *chip,
-                                                unsigned int offset, int value)
-{
-       return -EOPNOTSUPP;
-}
-
-static int cirrus_scodec_test_gpio_set(struct gpio_chip *chip,
-                                      unsigned int offset, int value)
-{
-       return -EOPNOTSUPP;
-}
-
-static int cirrus_scodec_test_gpio_set_config(struct gpio_chip *gc,
-                                             unsigned int offset,
-                                             unsigned long config)
-{
-       switch (pinconf_to_config_param(config)) {
-       case PIN_CONFIG_OUTPUT:
-       case PIN_CONFIG_OUTPUT_ENABLE:
-               return -EOPNOTSUPP;
-       default:
-               return 0;
-       }
-}
-
-static const struct gpio_chip cirrus_scodec_test_gpio_chip = {
-       .label                  = "cirrus_scodec_test_gpio",
-       .owner                  = THIS_MODULE,
-       .request                = gpiochip_generic_request,
-       .free                   = gpiochip_generic_free,
-       .get_direction          = cirrus_scodec_test_gpio_get_direction,
-       .direction_input        = cirrus_scodec_test_gpio_direction_in,
-       .get                    = cirrus_scodec_test_gpio_get,
-       .direction_output       = cirrus_scodec_test_gpio_direction_out,
-       .set_rv                 = cirrus_scodec_test_gpio_set,
-       .set_config             = cirrus_scodec_test_gpio_set_config,
-       .base                   = -1,
-       .ngpio                  = 32,
-};
-
-static int cirrus_scodec_test_gpio_probe(struct platform_device *pdev)
-{
-       struct cirrus_scodec_test_gpio *gpio_priv;
-       int ret;
-
-       gpio_priv = devm_kzalloc(&pdev->dev, sizeof(*gpio_priv), GFP_KERNEL);
-       if (!gpio_priv)
-               return -ENOMEM;
-
-       /* GPIO core modifies our struct gpio_chip so use a copy */
-       gpio_priv->chip = cirrus_scodec_test_gpio_chip;
-       ret = devm_gpiochip_add_data(&pdev->dev, &gpio_priv->chip, gpio_priv);
-       if (ret)
-               return dev_err_probe(&pdev->dev, ret, "Failed to add gpiochip\n");
-
-       dev_set_drvdata(&pdev->dev, gpio_priv);
-
-       return 0;
-}
-
-static struct platform_driver cirrus_scodec_test_gpio_driver = {
-       .driver.name    = "cirrus_scodec_test_gpio_drv",
-       .driver.owner   = THIS_MODULE,
-       .probe          = cirrus_scodec_test_gpio_probe,
-};
-
-/* software_node referencing the gpio driver */
-static const struct software_node cirrus_scodec_test_gpio_swnode = {
-       .name = "cirrus_scodec_test_gpio",
-};
-
-static void cirrus_scodec_test_create_gpio(struct kunit *test)
-{
-       struct cirrus_scodec_test_priv *priv = test->priv;
-
-       KUNIT_ASSERT_EQ(test, 0,
-                       kunit_platform_driver_register(test, &cirrus_scodec_test_gpio_driver));
-
-       priv->gpio_pdev = kunit_platform_device_alloc(test,
-                                                     cirrus_scodec_test_gpio_driver.driver.name,
-                                                     PLATFORM_DEVID_NONE);
-       KUNIT_ASSERT_NOT_NULL(test, priv->gpio_pdev);
-
-       KUNIT_ASSERT_EQ(test, 0, device_add_software_node(&priv->gpio_pdev->dev,
-                                                         &cirrus_scodec_test_gpio_swnode));
-       KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test,
-                                                          device_remove_software_node_wrapper,
-                                                          &priv->gpio_pdev->dev));
-
-       KUNIT_ASSERT_EQ(test, 0, kunit_platform_device_add(test, priv->gpio_pdev));
-
-       priv->gpio_priv = dev_get_drvdata(&priv->gpio_pdev->dev);
-       KUNIT_ASSERT_NOT_NULL(test, priv->gpio_priv);
-}
-
-static void cirrus_scodec_test_set_gpio_ref_arg(struct software_node_ref_args *arg,
-                                               int gpio_num)
-{
-       struct software_node_ref_args template =
-               SOFTWARE_NODE_REFERENCE(&cirrus_scodec_test_gpio_swnode, gpio_num, 0);
-
-       *arg = template;
-}
-
-static int cirrus_scodec_test_set_spkid_swnode(struct kunit *test,
-                                              struct device *dev,
-                                              struct software_node_ref_args *args,
-                                              int num_args)
-{
-       const struct property_entry props_template[] = {
-               PROPERTY_ENTRY_REF_ARRAY_LEN("spk-id-gpios", args, num_args),
-               { }
-       };
-       struct property_entry *props;
-       struct software_node *node;
-
-       node = kunit_kzalloc(test, sizeof(*node), GFP_KERNEL);
-       if (!node)
-               return -ENOMEM;
-
-       props = kunit_kzalloc(test, sizeof(props_template), GFP_KERNEL);
-       if (!props)
-               return -ENOMEM;
-
-       memcpy(props, props_template, sizeof(props_template));
-       node->properties = props;
-
-       return device_add_software_node(dev, node);
-}
-
-struct cirrus_scodec_test_spkid_param {
-       int num_amps;
-       int gpios_per_amp;
-       int num_amps_sharing;
-};
-
-static void cirrus_scodec_test_spkid_parse(struct kunit *test)
-{
-       struct cirrus_scodec_test_priv *priv = test->priv;
-       const struct cirrus_scodec_test_spkid_param *param = test->param_value;
-       int num_spk_id_refs = param->num_amps * param->gpios_per_amp;
-       struct software_node_ref_args *refs;
-       struct device *dev = &priv->amp_dev->dev;
-       unsigned int v;
-       int i, ret;
-
-       refs = kunit_kcalloc(test, num_spk_id_refs, sizeof(*refs), GFP_KERNEL);
-       KUNIT_ASSERT_NOT_NULL(test, refs);
-
-       for (i = 0, v = 0; i < num_spk_id_refs; ) {
-               cirrus_scodec_test_set_gpio_ref_arg(&refs[i++], v++);
-
-               /*
-                * If amps are sharing GPIOs repeat the last set of
-                * GPIOs until we've done that number of amps.
-                * We have done all GPIOs for an amp when i is a multiple
-                * of gpios_per_amp.
-                * We have done all amps sharing the same GPIOs when i is
-                * a multiple of (gpios_per_amp * num_amps_sharing).
-                */
-               if (!(i % param->gpios_per_amp) &&
-                   (i % (param->gpios_per_amp * param->num_amps_sharing)))
-                       v -= param->gpios_per_amp;
-       }
-
-       ret = cirrus_scodec_test_set_spkid_swnode(test, dev, refs, num_spk_id_refs);
-       KUNIT_EXPECT_EQ_MSG(test, ret, 0, "Failed to add swnode\n");
-
-       for (i = 0; i < param->num_amps; ++i) {
-               for (v = 0; v < (1 << param->gpios_per_amp); ++v) {
-                       /* Set only the GPIO bits used by this amp */
-                       priv->gpio_priv->pin_state =
-                               v << (param->gpios_per_amp * (i / param->num_amps_sharing));
-
-                       ret = cirrus_scodec_get_speaker_id(dev, i, param->num_amps, -1);
-                       KUNIT_EXPECT_EQ_MSG(test, ret, v,
-                                           "get_speaker_id failed amp:%d pin_state:%#x\n",
-                                           i, priv->gpio_priv->pin_state);
-               }
-       }
-}
-
-static void cirrus_scodec_test_no_spkid(struct kunit *test)
-{
-       struct cirrus_scodec_test_priv *priv = test->priv;
-       struct device *dev = &priv->amp_dev->dev;
-       int ret;
-
-       ret = cirrus_scodec_get_speaker_id(dev, 0, 4, -1);
-       KUNIT_EXPECT_EQ(test, ret, -ENOENT);
-}
-
-static int cirrus_scodec_test_case_init(struct kunit *test)
-{
-       struct cirrus_scodec_test_priv *priv;
-
-       priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
-       if (!priv)
-               return -ENOMEM;
-
-       test->priv = priv;
-
-       /* Create dummy GPIO */
-       cirrus_scodec_test_create_gpio(test);
-
-       /* Create dummy amp driver dev */
-       priv->amp_dev = faux_device_create("cirrus_scodec_test_amp_drv", NULL, NULL);
-       KUNIT_ASSERT_NOT_NULL(test, priv->amp_dev);
-       KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test,
-                                                          faux_device_destroy_wrapper,
-                                                          priv->amp_dev));
-
-       return 0;
-}
-
-static const struct cirrus_scodec_test_spkid_param cirrus_scodec_test_spkid_param_cases[] = {
-       { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 1 },
-       { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 1 },
-       { .num_amps = 2, .gpios_per_amp = 3, .num_amps_sharing = 1 },
-       { .num_amps = 2, .gpios_per_amp = 4, .num_amps_sharing = 1 },
-       { .num_amps = 3, .gpios_per_amp = 1, .num_amps_sharing = 1 },
-       { .num_amps = 3, .gpios_per_amp = 2, .num_amps_sharing = 1 },
-       { .num_amps = 3, .gpios_per_amp = 3, .num_amps_sharing = 1 },
-       { .num_amps = 3, .gpios_per_amp = 4, .num_amps_sharing = 1 },
-       { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 1 },
-       { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 1 },
-       { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 1 },
-       { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 1 },
-
-       /* Same GPIO shared by all amps */
-       { .num_amps = 2, .gpios_per_amp = 1, .num_amps_sharing = 2 },
-       { .num_amps = 2, .gpios_per_amp = 2, .num_amps_sharing = 2 },
-       { .num_amps = 2, .gpios_per_amp = 3, .num_amps_sharing = 2 },
-       { .num_amps = 2, .gpios_per_amp = 4, .num_amps_sharing = 2 },
-       { .num_amps = 3, .gpios_per_amp = 1, .num_amps_sharing = 3 },
-       { .num_amps = 3, .gpios_per_amp = 2, .num_amps_sharing = 3 },
-       { .num_amps = 3, .gpios_per_amp = 3, .num_amps_sharing = 3 },
-       { .num_amps = 3, .gpios_per_amp = 4, .num_amps_sharing = 3 },
-       { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 4 },
-       { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 4 },
-       { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 4 },
-       { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 4 },
-
-       /* Two sets of shared GPIOs */
-       { .num_amps = 4, .gpios_per_amp = 1, .num_amps_sharing = 2 },
-       { .num_amps = 4, .gpios_per_amp = 2, .num_amps_sharing = 2 },
-       { .num_amps = 4, .gpios_per_amp = 3, .num_amps_sharing = 2 },
-       { .num_amps = 4, .gpios_per_amp = 4, .num_amps_sharing = 2 },
-};
-
-static void cirrus_scodec_test_spkid_param_desc(const struct cirrus_scodec_test_spkid_param *param,
-                                               char *desc)
-{
-       snprintf(desc, KUNIT_PARAM_DESC_SIZE, "amps:%d gpios_per_amp:%d num_amps_sharing:%d",
-                param->num_amps, param->gpios_per_amp, param->num_amps_sharing);
-}
-
-KUNIT_ARRAY_PARAM(cirrus_scodec_test_spkid, cirrus_scodec_test_spkid_param_cases,
-                 cirrus_scodec_test_spkid_param_desc);
-
-static struct kunit_case cirrus_scodec_test_cases[] = {
-       KUNIT_CASE_PARAM(cirrus_scodec_test_spkid_parse, cirrus_scodec_test_spkid_gen_params),
-       KUNIT_CASE(cirrus_scodec_test_no_spkid),
-       { } /* terminator */
-};
-
-static struct kunit_suite cirrus_scodec_test_suite = {
-       .name = "snd-hda-scodec-cs35l56-test",
-       .init = cirrus_scodec_test_case_init,
-       .test_cases = cirrus_scodec_test_cases,
-};
-
-kunit_test_suite(cirrus_scodec_test_suite);
-
-MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC");
-MODULE_DESCRIPTION("KUnit test for the Cirrus side-codec library");
-MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/cs35l41_hda.c b/sound/pci/hda/cs35l41_hda.c
deleted file mode 100644 (file)
index 2d7ee12..0000000
+++ /dev/null
@@ -1,2112 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// CS35l41 ALSA HDA audio driver
-//
-// Copyright 2021 Cirrus Logic, Inc.
-//
-// Author: Lucas Tanure <tanureal@opensource.cirrus.com>
-
-#include <linux/acpi.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <sound/hda_codec.h>
-#include <sound/soc.h>
-#include <linux/pm_runtime.h>
-#include <linux/spi/spi.h>
-#include <linux/vmalloc.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-#include "hda_component.h"
-#include "cs35l41_hda.h"
-#include "cs35l41_hda_property.h"
-
-#define CS35L41_PART "cs35l41"
-
-#define HALO_STATE_DSP_CTL_NAME                "HALO_STATE"
-#define HALO_STATE_DSP_CTL_TYPE                5
-#define HALO_STATE_DSP_CTL_ALG         262308
-#define CAL_R_DSP_CTL_NAME             "CAL_R"
-#define CAL_STATUS_DSP_CTL_NAME                "CAL_STATUS"
-#define CAL_CHECKSUM_DSP_CTL_NAME      "CAL_CHECKSUM"
-#define CAL_AMBIENT_DSP_CTL_NAME       "CAL_AMBIENT"
-#define CAL_DSP_CTL_TYPE               5
-#define CAL_DSP_CTL_ALG                        205
-#define CS35L41_UUID                   "50d90cdc-3de4-4f18-b528-c7fe3b71f40d"
-#define CS35L41_DSM_GET_MUTE           5
-#define CS35L41_NOTIFY_EVENT           0x91
-#define CS35L41_TUNING_SIG             0x109A4A35
-
-enum cs35l41_tuning_param_types {
-       TUNING_PARAM_GAIN,
-};
-
-struct cs35l41_tuning_param_hdr {
-       __le32 tuning_index;
-       __le32 type;
-       __le32 size;
-} __packed;
-
-struct cs35l41_tuning_param {
-       struct cs35l41_tuning_param_hdr hdr;
-       union {
-               __le32 gain;
-       };
-} __packed;
-
-struct cs35l41_tuning_params {
-       __le32 signature;
-       __le32 version;
-       __le32 size;
-       __le32 num_entries;
-       u8 data[];
-} __packed;
-
-/* Firmware calibration controls */
-static const struct cirrus_amp_cal_controls cs35l41_calibration_controls = {
-       .alg_id =       CAL_DSP_CTL_ALG,
-       .mem_region =   CAL_DSP_CTL_TYPE,
-       .ambient =      CAL_AMBIENT_DSP_CTL_NAME,
-       .calr =         CAL_R_DSP_CTL_NAME,
-       .status =       CAL_STATUS_DSP_CTL_NAME,
-       .checksum =     CAL_CHECKSUM_DSP_CTL_NAME,
-};
-
-enum cs35l41_hda_fw_id {
-       CS35L41_HDA_FW_SPK_PROT,
-       CS35L41_HDA_FW_SPK_CALI,
-       CS35L41_HDA_FW_SPK_DIAG,
-       CS35L41_HDA_FW_MISC,
-       CS35L41_HDA_NUM_FW
-};
-
-static const char * const cs35l41_hda_fw_ids[CS35L41_HDA_NUM_FW] = {
-       [CS35L41_HDA_FW_SPK_PROT] = "spk-prot",
-       [CS35L41_HDA_FW_SPK_CALI] = "spk-cali",
-       [CS35L41_HDA_FW_SPK_DIAG] = "spk-diag",
-       [CS35L41_HDA_FW_MISC] =     "misc",
-};
-
-static bool firmware_autostart = 1;
-module_param(firmware_autostart, bool, 0444);
-MODULE_PARM_DESC(firmware_autostart, "Allow automatic firmware download on boot"
-                            "(0=Disable, 1=Enable) (default=1); ");
-
-static const char channel_name[3] = { 'L', 'R', 'C' };
-
-static const struct reg_sequence cs35l41_hda_config[] = {
-       { CS35L41_PLL_CLK_CTRL,         0x00000430 }, // 3072000Hz, BCLK Input, PLL_REFCLK_EN = 1
-       { CS35L41_DSP_CLK_CTRL,         0x00000003 }, // DSP CLK EN
-       { CS35L41_GLOBAL_CLK_CTRL,      0x00000003 }, // GLOBAL_FS = 48 kHz
-       { CS35L41_SP_RATE_CTRL,         0x00000021 }, // ASP_BCLK_FREQ = 3.072 MHz
-       { CS35L41_SP_FORMAT,            0x20200200 }, // 32 bits RX/TX slots, I2S, clk consumer
-       { CS35L41_SP_TX_WL,             0x00000018 }, // 24 cycles/slot
-       { CS35L41_SP_RX_WL,             0x00000018 }, // 24 cycles/slot
-       { CS35L41_ASP_TX1_SRC,          0x00000018 }, // ASPTX1 SRC = VMON
-       { CS35L41_ASP_TX2_SRC,          0x00000019 }, // ASPTX2 SRC = IMON
-       { CS35L41_DSP1_RX3_SRC,         0x00000018 }, // DSP1RX3 SRC = VMON
-       { CS35L41_DSP1_RX4_SRC,         0x00000019 }, // DSP1RX4 SRC = IMON
-};
-
-static const struct reg_sequence cs35l41_hda_config_no_dsp[] = {
-       { CS35L41_SP_HIZ_CTRL,          0x00000002 }, // Hi-Z unused
-       { CS35L41_DAC_PCM1_SRC,         0x00000008 }, // DACPCM1_SRC = ASPRX1
-       { CS35L41_ASP_TX3_SRC,          0x00000000 }, // ASPTX3 SRC = ZERO FILL
-       { CS35L41_ASP_TX4_SRC,          0x00000000 }, // ASPTX4 SRC = ZERO FILL
-       { CS35L41_DSP1_RX5_SRC,         0x00000020 }, // DSP1RX5 SRC = ERRVOL
-       { CS35L41_DSP1_RX6_SRC,         0x00000021 }, // DSP1RX6 SRC = CLASSH_TGT
-};
-
-static const struct reg_sequence cs35l41_hda_config_dsp[] = {
-       { CS35L41_SP_HIZ_CTRL,          0x00000003 }, // Hi-Z unused/disabled
-       { CS35L41_DAC_PCM1_SRC,         0x00000032 }, // DACPCM1_SRC = DSP1TX1
-       { CS35L41_ASP_TX3_SRC,          0x00000028 }, // ASPTX3 SRC = VPMON
-       { CS35L41_ASP_TX4_SRC,          0x00000029 }, // ASPTX4 SRC = VBSTMON
-       { CS35L41_DSP1_RX6_SRC,         0x00000029 }, // DSP1RX6 SRC = VBSTMON
-};
-
-static const struct reg_sequence cs35l41_hda_unmute[] = {
-       { CS35L41_AMP_DIG_VOL_CTRL,     0x00008000 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM  0.0 dB
-       { CS35L41_AMP_GAIN_CTRL,        0x00000084 }, // AMP_GAIN_PCM 4.5 dB
-};
-
-static const struct reg_sequence cs35l41_hda_mute[] = {
-       { CS35L41_AMP_GAIN_CTRL,        0x00000000 }, // AMP_GAIN_PCM 0.5 dB
-       { CS35L41_AMP_DIG_VOL_CTRL,     0x0000A678 }, // AMP_HPF_PCM_EN = 1, AMP_VOL_PCM Mute
-};
-
-static const struct cs_dsp_client_ops client_ops = {
-       /* cs_dsp requires the client to provide this even if it is empty */
-};
-
-static int cs35l41_request_tuning_param_file(struct cs35l41_hda *cs35l41, char *tuning_filename,
-                                            const struct firmware **firmware, char **filename,
-                                            const char *ssid)
-{
-       int ret = 0;
-
-       /* Filename is the same as the tuning file with "cfg" suffix */
-       *filename = kasprintf(GFP_KERNEL, "%scfg", tuning_filename);
-       if (*filename == NULL)
-               return -ENOMEM;
-
-       ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev);
-       if (ret != 0) {
-               dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename);
-               kfree(*filename);
-               *filename = NULL;
-       }
-
-       return ret;
-}
-
-static int cs35l41_request_firmware_file(struct cs35l41_hda *cs35l41,
-                                        const struct firmware **firmware, char **filename,
-                                        const char *ssid, const char *amp_name,
-                                        int spkid, const char *filetype)
-{
-       const char * const dsp_name = cs35l41->cs_dsp.name;
-       char *s, c;
-       int ret = 0;
-
-       if (spkid > -1 && ssid && amp_name)
-               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d-%s.%s", CS35L41_PART,
-                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
-                                     ssid, spkid, amp_name, filetype);
-       else if (spkid > -1 && ssid)
-               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-spkid%d.%s", CS35L41_PART,
-                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
-                                     ssid, spkid, filetype);
-       else if (ssid && amp_name)
-               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s-%s.%s", CS35L41_PART,
-                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
-                                     ssid, amp_name, filetype);
-       else if (ssid)
-               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s-%s.%s", CS35L41_PART,
-                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
-                                     ssid, filetype);
-       else
-               *filename = kasprintf(GFP_KERNEL, "cirrus/%s-%s-%s.%s", CS35L41_PART,
-                                     dsp_name, cs35l41_hda_fw_ids[cs35l41->firmware_type],
-                                     filetype);
-
-       if (*filename == NULL)
-               return -ENOMEM;
-
-       /*
-        * Make sure that filename is lower-case and any non alpha-numeric
-        * characters except full stop and '/' are replaced with hyphens.
-        */
-       s = *filename;
-       while (*s) {
-               c = *s;
-               if (isalnum(c))
-                       *s = tolower(c);
-               else if (c != '.' && c != '/')
-                       *s = '-';
-               s++;
-       }
-
-       ret = firmware_request_nowarn(firmware, *filename, cs35l41->dev);
-       if (ret != 0) {
-               dev_dbg(cs35l41->dev, "Failed to request '%s'\n", *filename);
-               kfree(*filename);
-               *filename = NULL;
-       }
-
-       return ret;
-}
-
-static int cs35l41_request_firmware_files_spkid(struct cs35l41_hda *cs35l41,
-                                               const struct firmware **wmfw_firmware,
-                                               char **wmfw_filename,
-                                               const struct firmware **coeff_firmware,
-                                               char **coeff_filename)
-{
-       int ret;
-
-       /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.wmfw */
-       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                           cs35l41->acpi_subsystem_id, cs35l41->amp_name,
-                                           cs35l41->speaker_id, "wmfw");
-       if (!ret) {
-               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
-               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
-                                                   cs35l41->speaker_id, "bin");
-               if (ret)
-                       goto coeff_err;
-
-               return 0;
-       }
-
-       /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
-       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                           cs35l41->acpi_subsystem_id,
-                                           cs35l41->amp_name, -1, "wmfw");
-       if (!ret) {
-               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
-               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
-                                                   cs35l41->speaker_id, "bin");
-               if (ret)
-                       goto coeff_err;
-
-               return 0;
-       }
-
-       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.wmfw */
-       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                           cs35l41->acpi_subsystem_id,
-                                           NULL, cs35l41->speaker_id, "wmfw");
-       if (!ret) {
-               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
-               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                   cs35l41->acpi_subsystem_id,
-                                                   cs35l41->amp_name, cs35l41->speaker_id, "bin");
-               if (ret)
-                       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
-                       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
-                                                           coeff_filename,
-                                                           cs35l41->acpi_subsystem_id, NULL,
-                                                           cs35l41->speaker_id, "bin");
-               if (ret)
-                       goto coeff_err;
-
-               return 0;
-       }
-
-       /* try cirrus/part-dspN-fwtype-sub.wmfw */
-       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                           cs35l41->acpi_subsystem_id,
-                                           NULL, -1, "wmfw");
-       if (!ret) {
-               /* try cirrus/part-dspN-fwtype-sub<-spkidN><-ampname>.bin */
-               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
-                                                   cs35l41->speaker_id, "bin");
-               if (ret)
-                       /* try cirrus/part-dspN-fwtype-sub<-spkidN>.bin */
-                       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware,
-                                                           coeff_filename,
-                                                           cs35l41->acpi_subsystem_id, NULL,
-                                                           cs35l41->speaker_id, "bin");
-               if (ret)
-                       goto coeff_err;
-       }
-
-       return ret;
-coeff_err:
-       release_firmware(*wmfw_firmware);
-       kfree(*wmfw_filename);
-       return ret;
-}
-
-static int cs35l41_fallback_firmware_file(struct cs35l41_hda *cs35l41,
-                                         const struct firmware **wmfw_firmware,
-                                         char **wmfw_filename,
-                                         const struct firmware **coeff_firmware,
-                                         char **coeff_filename)
-{
-       int ret;
-
-       /* Handle fallback */
-       dev_warn(cs35l41->dev, "Falling back to default firmware.\n");
-
-       /* fallback try cirrus/part-dspN-fwtype.wmfw */
-       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                           NULL, NULL, -1, "wmfw");
-       if (ret)
-               goto err;
-
-       /* fallback try cirrus/part-dspN-fwtype.bin */
-       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                           NULL, NULL, -1, "bin");
-       if (ret) {
-               release_firmware(*wmfw_firmware);
-               kfree(*wmfw_filename);
-               goto err;
-       }
-       return 0;
-
-err:
-       dev_warn(cs35l41->dev, "Unable to find firmware and tuning\n");
-       return ret;
-}
-
-static int cs35l41_request_firmware_files(struct cs35l41_hda *cs35l41,
-                                         const struct firmware **wmfw_firmware,
-                                         char **wmfw_filename,
-                                         const struct firmware **coeff_firmware,
-                                         char **coeff_filename)
-{
-       int ret;
-
-       if (cs35l41->speaker_id > -1) {
-               ret = cs35l41_request_firmware_files_spkid(cs35l41, wmfw_firmware, wmfw_filename,
-                                                          coeff_firmware, coeff_filename);
-               goto out;
-       }
-
-       /* try cirrus/part-dspN-fwtype-sub<-ampname>.wmfw */
-       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                           cs35l41->acpi_subsystem_id,
-                                           cs35l41->amp_name, -1, "wmfw");
-       if (!ret) {
-               /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
-               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                   cs35l41->acpi_subsystem_id, cs35l41->amp_name,
-                                                   -1, "bin");
-               if (ret)
-                       goto coeff_err;
-
-               goto out;
-       }
-
-       /* try cirrus/part-dspN-fwtype-sub.wmfw */
-       ret = cs35l41_request_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                           cs35l41->acpi_subsystem_id,
-                                           NULL, -1, "wmfw");
-       if (!ret) {
-               /* try cirrus/part-dspN-fwtype-sub<-ampname>.bin */
-               ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                   cs35l41->acpi_subsystem_id,
-                                                   cs35l41->amp_name, -1, "bin");
-               if (ret)
-                       /* try cirrus/part-dspN-fwtype-sub.bin */
-                       ret = cs35l41_request_firmware_file(cs35l41, coeff_firmware, coeff_filename,
-                                                           cs35l41->acpi_subsystem_id, NULL, -1,
-                                                           "bin");
-               if (ret)
-                       goto coeff_err;
-       }
-
-out:
-       if (ret)
-               /* if all attempts at finding firmware fail, try fallback */
-               goto fallback;
-
-       return 0;
-
-coeff_err:
-       release_firmware(*wmfw_firmware);
-       kfree(*wmfw_filename);
-fallback:
-       return cs35l41_fallback_firmware_file(cs35l41, wmfw_firmware, wmfw_filename,
-                                             coeff_firmware, coeff_filename);
-}
-
-
-static void cs35l41_hda_apply_calibration(struct cs35l41_hda *cs35l41)
-{
-       int ret;
-
-       if (!cs35l41->cal_data_valid)
-               return;
-
-       ret = cs_amp_write_cal_coeffs(&cs35l41->cs_dsp, &cs35l41_calibration_controls,
-                                     &cs35l41->cal_data);
-       if (ret < 0)
-               dev_warn(cs35l41->dev, "Failed to apply calibration: %d\n", ret);
-       else
-               dev_info(cs35l41->dev, "Calibration applied: R0=%d\n", cs35l41->cal_data.calR);
-}
-
-static int cs35l41_read_silicon_uid(struct cs35l41_hda *cs35l41, u64 *uid)
-{
-       u32 tmp;
-       int ret;
-
-       ret = regmap_read(cs35l41->regmap, CS35L41_DIE_STS2, &tmp);
-       if (ret) {
-               dev_err(cs35l41->dev, "Cannot obtain CS35L41_DIE_STS2: %d\n", ret);
-               return ret;
-       }
-
-       *uid = tmp;
-       *uid <<= 32;
-
-       ret = regmap_read(cs35l41->regmap, CS35L41_DIE_STS1, &tmp);
-       if (ret) {
-               dev_err(cs35l41->dev, "Cannot obtain CS35L41_DIE_STS1: %d\n", ret);
-               return ret;
-       }
-
-       *uid |= tmp;
-
-       dev_dbg(cs35l41->dev, "UniqueID = %#llx\n", *uid);
-
-       return 0;
-}
-
-static int cs35l41_get_calibration(struct cs35l41_hda *cs35l41)
-{
-       u64 silicon_uid;
-       int ret;
-
-       ret = cs35l41_read_silicon_uid(cs35l41, &silicon_uid);
-       if (ret < 0)
-               return ret;
-
-       ret = cs_amp_get_efi_calibration_data(cs35l41->dev, silicon_uid,
-                                             cs35l41->index,
-                                             &cs35l41->cal_data);
-
-       /* Only return an error status if probe should be aborted */
-       if ((ret == -ENOENT) || (ret == -EOVERFLOW))
-               return 0;
-
-       if (ret < 0)
-               return ret;
-
-       cs35l41->cal_data_valid = true;
-
-       return 0;
-}
-
-
-static void cs35l41_set_default_tuning_params(struct cs35l41_hda *cs35l41)
-{
-       cs35l41->tuning_gain = DEFAULT_AMP_GAIN_PCM;
-}
-
-static int cs35l41_read_tuning_params(struct cs35l41_hda *cs35l41, const struct firmware *firmware)
-{
-       struct cs35l41_tuning_params *params;
-       unsigned int offset = 0;
-       unsigned int end;
-       int i;
-
-       params = (void *)&firmware->data[0];
-
-       if (le32_to_cpu(params->size) != firmware->size) {
-               dev_err(cs35l41->dev, "Wrong Size for Tuning Param file. Expected %d got %zu\n",
-                       le32_to_cpu(params->size), firmware->size);
-               return -EINVAL;
-       }
-
-       if (le32_to_cpu(params->version) != 1) {
-               dev_err(cs35l41->dev, "Unsupported Tuning Param Version: %d\n",
-                       le32_to_cpu(params->version));
-               return -EINVAL;
-       }
-
-       if (le32_to_cpu(params->signature) != CS35L41_TUNING_SIG) {
-               dev_err(cs35l41->dev,
-                       "Mismatched Signature for Tuning Param file. Expected %#x got %#x\n",
-                       CS35L41_TUNING_SIG, le32_to_cpu(params->signature));
-               return -EINVAL;
-       }
-
-       end = firmware->size - sizeof(struct cs35l41_tuning_params);
-
-       for (i = 0; i < le32_to_cpu(params->num_entries); i++) {
-               struct cs35l41_tuning_param *param;
-
-               if ((offset >= end) || ((offset + sizeof(struct cs35l41_tuning_param_hdr)) >= end))
-                       return -EFAULT;
-
-               param = (void *)&params->data[offset];
-               offset += le32_to_cpu(param->hdr.size);
-
-               if (offset > end)
-                       return -EFAULT;
-
-               switch (le32_to_cpu(param->hdr.type)) {
-               case TUNING_PARAM_GAIN:
-                       cs35l41->tuning_gain = le32_to_cpu(param->gain);
-                       dev_dbg(cs35l41->dev, "Applying Gain: %d\n", cs35l41->tuning_gain);
-                       break;
-               default:
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int cs35l41_load_tuning_params(struct cs35l41_hda *cs35l41, char *tuning_filename)
-{
-       const struct firmware *tuning_param_file = NULL;
-       char *tuning_param_filename = NULL;
-       int ret;
-
-       ret = cs35l41_request_tuning_param_file(cs35l41, tuning_filename, &tuning_param_file,
-                                               &tuning_param_filename, cs35l41->acpi_subsystem_id);
-       if (ret) {
-               dev_dbg(cs35l41->dev, "Missing Tuning Param for file: %s: %d\n", tuning_filename,
-                       ret);
-               return 0;
-       }
-
-       ret = cs35l41_read_tuning_params(cs35l41, tuning_param_file);
-       if (ret) {
-               dev_err(cs35l41->dev, "Error reading Tuning Params from file: %s: %d\n",
-                       tuning_param_filename, ret);
-               /* Reset to default Tuning Parameters */
-               cs35l41_set_default_tuning_params(cs35l41);
-       }
-
-       release_firmware(tuning_param_file);
-       kfree(tuning_param_filename);
-
-       return ret;
-}
-
-static int cs35l41_init_dsp(struct cs35l41_hda *cs35l41)
-{
-       const struct firmware *coeff_firmware = NULL;
-       const struct firmware *wmfw_firmware = NULL;
-       struct cs_dsp *dsp = &cs35l41->cs_dsp;
-       char *coeff_filename = NULL;
-       char *wmfw_filename = NULL;
-       int ret;
-
-       if (!cs35l41->halo_initialized) {
-               cs35l41_configure_cs_dsp(cs35l41->dev, cs35l41->regmap, dsp);
-               dsp->client_ops = &client_ops;
-
-               ret = cs_dsp_halo_init(&cs35l41->cs_dsp);
-               if (ret)
-                       return ret;
-               cs35l41->halo_initialized = true;
-       }
-
-       cs35l41_set_default_tuning_params(cs35l41);
-
-       ret = cs35l41_request_firmware_files(cs35l41, &wmfw_firmware, &wmfw_filename,
-                                            &coeff_firmware, &coeff_filename);
-       if (ret < 0)
-               return ret;
-
-       dev_dbg(cs35l41->dev, "Loading WMFW Firmware: %s\n", wmfw_filename);
-       if (coeff_filename) {
-               dev_dbg(cs35l41->dev, "Loading Coefficient File: %s\n", coeff_filename);
-               ret = cs35l41_load_tuning_params(cs35l41, coeff_filename);
-               if (ret)
-                       dev_warn(cs35l41->dev, "Unable to load Tuning Parameters: %d\n", ret);
-       } else {
-               dev_warn(cs35l41->dev, "No Coefficient File available.\n");
-       }
-
-       ret = cs_dsp_power_up(dsp, wmfw_firmware, wmfw_filename, coeff_firmware, coeff_filename,
-                             cs35l41_hda_fw_ids[cs35l41->firmware_type]);
-       if (ret)
-               goto err;
-
-       cs35l41_hda_apply_calibration(cs35l41);
-
-err:
-       if (ret)
-               cs35l41_set_default_tuning_params(cs35l41);
-       release_firmware(wmfw_firmware);
-       release_firmware(coeff_firmware);
-       kfree(wmfw_filename);
-       kfree(coeff_filename);
-
-       return ret;
-}
-
-static void cs35l41_shutdown_dsp(struct cs35l41_hda *cs35l41)
-{
-       struct cs_dsp *dsp = &cs35l41->cs_dsp;
-
-       cs35l41_set_default_tuning_params(cs35l41);
-       cs_dsp_stop(dsp);
-       cs_dsp_power_down(dsp);
-       dev_dbg(cs35l41->dev, "Unloaded Firmware\n");
-}
-
-static void cs35l41_remove_dsp(struct cs35l41_hda *cs35l41)
-{
-       struct cs_dsp *dsp = &cs35l41->cs_dsp;
-
-       cancel_work_sync(&cs35l41->fw_load_work);
-
-       mutex_lock(&cs35l41->fw_mutex);
-       cs35l41_shutdown_dsp(cs35l41);
-       cs_dsp_remove(dsp);
-       cs35l41->halo_initialized = false;
-       mutex_unlock(&cs35l41->fw_mutex);
-}
-
-/* Protection release cycle to get the speaker out of Safe-Mode */
-static void cs35l41_error_release(struct device *dev, struct regmap *regmap, unsigned int mask)
-{
-       regmap_write(regmap, CS35L41_PROTECT_REL_ERR_IGN, 0);
-       regmap_set_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
-       regmap_clear_bits(regmap, CS35L41_PROTECT_REL_ERR_IGN, mask);
-}
-
-/* Clear all errors to release safe mode. Global Enable must be cleared first. */
-static void cs35l41_irq_release(struct cs35l41_hda *cs35l41)
-{
-       cs35l41_error_release(cs35l41->dev, cs35l41->regmap, cs35l41->irq_errors);
-       cs35l41->irq_errors = 0;
-}
-
-static void cs35l41_update_mixer(struct cs35l41_hda *cs35l41)
-{
-       struct regmap *reg = cs35l41->regmap;
-       unsigned int asp_en = 0;
-       unsigned int dsp1rx2_src = 0;
-
-       regmap_multi_reg_write(reg, cs35l41_hda_config, ARRAY_SIZE(cs35l41_hda_config));
-
-       if (cs35l41->cs_dsp.running) {
-               asp_en |= CS35L41_ASP_TX1_EN_MASK; // ASP_TX1_EN = 1
-               regmap_multi_reg_write(reg, cs35l41_hda_config_dsp,
-                                      ARRAY_SIZE(cs35l41_hda_config_dsp));
-               if (cs35l41->hw_cfg.bst_type == CS35L41_INT_BOOST)
-                       regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VPMON);
-               else
-                       regmap_write(reg, CS35L41_DSP1_RX5_SRC, CS35L41_INPUT_SRC_VBSTMON);
-       } else {
-               regmap_multi_reg_write(reg, cs35l41_hda_config_no_dsp,
-                                      ARRAY_SIZE(cs35l41_hda_config_no_dsp));
-       }
-
-       if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER) {
-               asp_en |= CS35L41_ASP_RX2_EN_MASK; // ASP_RX2_EN = 1
-               dsp1rx2_src = 0x00000009; // DSP1RX2 SRC = ASPRX2
-       } else {
-               dsp1rx2_src = 0x00000008; // DSP1RX2 SRC = ASPRX1
-       }
-
-       asp_en |= CS35L41_ASP_RX1_EN_MASK; // ASP_RX1_EN = 1
-
-       regmap_write(reg, CS35L41_SP_ENABLES, asp_en);
-       regmap_write(reg, CS35L41_DSP1_RX1_SRC, 0x00000008); // DSP1RX1 SRC = ASPRX1
-       regmap_write(reg, CS35L41_DSP1_RX2_SRC, dsp1rx2_src);
-}
-
-static void cs35l41_hda_play_start(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       struct regmap *reg = cs35l41->regmap;
-
-       dev_dbg(dev, "Play (Start)\n");
-
-       if (cs35l41->playback_started) {
-               dev_dbg(dev, "Playback already started.");
-               return;
-       }
-
-       cs35l41->playback_started = true;
-
-       cs35l41_update_mixer(cs35l41);
-
-       if (cs35l41->cs_dsp.running) {
-               regmap_update_bits(reg, CS35L41_PWR_CTRL2,
-                                  CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
-                                  1 << CS35L41_VMON_EN_SHIFT | 1 << CS35L41_IMON_EN_SHIFT);
-               cs35l41_set_cspl_mbox_cmd(cs35l41->dev, reg, CSPL_MBOX_CMD_RESUME);
-       }
-       regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 1 << CS35L41_AMP_EN_SHIFT);
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
-               regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00008001);
-
-}
-
-static void cs35l41_mute(struct device *dev, bool mute)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       struct regmap *reg = cs35l41->regmap;
-       unsigned int amp_gain;
-
-       dev_dbg(dev, "Mute(%d:%d) Playback Started: %d\n", mute, cs35l41->mute_override,
-               cs35l41->playback_started);
-
-       if (cs35l41->playback_started) {
-               if (mute || cs35l41->mute_override) {
-                       dev_dbg(dev, "Muting\n");
-                       regmap_multi_reg_write(reg, cs35l41_hda_mute, ARRAY_SIZE(cs35l41_hda_mute));
-               } else {
-                       dev_dbg(dev, "Unmuting\n");
-                       if (cs35l41->cs_dsp.running) {
-                               dev_dbg(dev, "Using Tuned Gain: %d\n", cs35l41->tuning_gain);
-                               amp_gain = (cs35l41->tuning_gain << CS35L41_AMP_GAIN_PCM_SHIFT) |
-                                       (DEFAULT_AMP_GAIN_PDM << CS35L41_AMP_GAIN_PDM_SHIFT);
-
-                               /* AMP_HPF_PCM_EN = 1, AMP_VOL_PCM  0.0 dB */
-                               regmap_write(reg, CS35L41_AMP_DIG_VOL_CTRL, 0x00008000);
-                               regmap_write(reg, CS35L41_AMP_GAIN_CTRL, amp_gain);
-                       } else {
-                               regmap_multi_reg_write(reg, cs35l41_hda_unmute,
-                                               ARRAY_SIZE(cs35l41_hda_unmute));
-                       }
-               }
-       }
-}
-
-static void cs35l41_hda_play_done(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       struct regmap *reg = cs35l41->regmap;
-
-       dev_dbg(dev, "Play (Complete)\n");
-
-       cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 1,
-                             &cs35l41->cs_dsp);
-       cs35l41_mute(dev, false);
-}
-
-static void cs35l41_hda_pause_start(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       struct regmap *reg = cs35l41->regmap;
-
-       dev_dbg(dev, "Pause (Start)\n");
-
-       cs35l41_mute(dev, true);
-       cs35l41_global_enable(dev, reg, cs35l41->hw_cfg.bst_type, 0,
-                             &cs35l41->cs_dsp);
-}
-
-static void cs35l41_hda_pause_done(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       struct regmap *reg = cs35l41->regmap;
-
-       dev_dbg(dev, "Pause (Complete)\n");
-
-       regmap_update_bits(reg, CS35L41_PWR_CTRL2, CS35L41_AMP_EN_MASK, 0 << CS35L41_AMP_EN_SHIFT);
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
-               regmap_write(reg, CS35L41_GPIO1_CTRL1, 0x00000001);
-       if (cs35l41->cs_dsp.running) {
-               cs35l41_set_cspl_mbox_cmd(dev, reg, CSPL_MBOX_CMD_PAUSE);
-               regmap_update_bits(reg, CS35L41_PWR_CTRL2,
-                                  CS35L41_VMON_EN_MASK | CS35L41_IMON_EN_MASK,
-                                  0 << CS35L41_VMON_EN_SHIFT | 0 << CS35L41_IMON_EN_SHIFT);
-       }
-       cs35l41_irq_release(cs35l41);
-       cs35l41->playback_started = false;
-}
-
-static void cs35l41_hda_pre_playback_hook(struct device *dev, int action)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-
-       switch (action) {
-       case HDA_GEN_PCM_ACT_CLEANUP:
-               mutex_lock(&cs35l41->fw_mutex);
-               cs35l41_hda_pause_start(dev);
-               mutex_unlock(&cs35l41->fw_mutex);
-               break;
-       default:
-               break;
-       }
-}
-static void cs35l41_hda_playback_hook(struct device *dev, int action)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-
-       switch (action) {
-       case HDA_GEN_PCM_ACT_OPEN:
-               /*
-                * All amps must be resumed before we can start playing back.
-                * This ensures, for external boost, that all amps are in AMP_SAFE mode.
-                * Do this in HDA_GEN_PCM_ACT_OPEN, since this is run prior to any of the
-                * other actions.
-                */
-               pm_runtime_get_sync(dev);
-               break;
-       case HDA_GEN_PCM_ACT_PREPARE:
-               mutex_lock(&cs35l41->fw_mutex);
-               cs35l41_hda_play_start(dev);
-               mutex_unlock(&cs35l41->fw_mutex);
-               break;
-       case HDA_GEN_PCM_ACT_CLEANUP:
-               mutex_lock(&cs35l41->fw_mutex);
-               cs35l41_hda_pause_done(dev);
-               mutex_unlock(&cs35l41->fw_mutex);
-               break;
-       case HDA_GEN_PCM_ACT_CLOSE:
-               mutex_lock(&cs35l41->fw_mutex);
-               if (!cs35l41->cs_dsp.running && cs35l41->request_fw_load &&
-                   !cs35l41->fw_request_ongoing) {
-                       dev_info(dev, "Requesting Firmware Load after HDA_GEN_PCM_ACT_CLOSE\n");
-                       cs35l41->fw_request_ongoing = true;
-                       schedule_work(&cs35l41->fw_load_work);
-               }
-               mutex_unlock(&cs35l41->fw_mutex);
-
-               /*
-                * Playback must be finished for all amps before we start runtime suspend.
-                * This ensures no amps are playing back when we start putting them to sleep.
-                */
-               pm_runtime_put_autosuspend(dev);
-               break;
-       default:
-               break;
-       }
-}
-
-static void cs35l41_hda_post_playback_hook(struct device *dev, int action)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-
-       switch (action) {
-       case HDA_GEN_PCM_ACT_PREPARE:
-               mutex_lock(&cs35l41->fw_mutex);
-               cs35l41_hda_play_done(dev);
-               mutex_unlock(&cs35l41->fw_mutex);
-               break;
-       default:
-               break;
-       }
-}
-
-static int cs35l41_hda_channel_map(struct cs35l41_hda *cs35l41)
-{
-       unsigned int tx_num = 0;
-       unsigned int *tx_slot = NULL;
-       unsigned int rx_num;
-       unsigned int *rx_slot;
-       unsigned int mono = 0;
-
-       if (!cs35l41->amp_name) {
-               if (cs35l41->hw_cfg.spk_pos >= ARRAY_SIZE(channel_name))
-                       return -EINVAL;
-
-               cs35l41->amp_name = devm_kasprintf(cs35l41->dev, GFP_KERNEL, "%c%d",
-                                                  channel_name[cs35l41->hw_cfg.spk_pos],
-                                                  cs35l41->channel_index);
-               if (!cs35l41->amp_name)
-                       return -ENOMEM;
-       }
-
-       rx_num = 1;
-       if (cs35l41->hw_cfg.spk_pos == CS35L41_CENTER)
-               rx_slot = &mono;
-       else
-               rx_slot = &cs35l41->hw_cfg.spk_pos;
-
-       return cs35l41_set_channels(cs35l41->dev, cs35l41->regmap, tx_num, tx_slot, rx_num,
-                                   rx_slot);
-}
-
-static int cs35l41_verify_id(struct cs35l41_hda *cs35l41, unsigned int *regid, unsigned int *reg_revid)
-{
-       unsigned int mtl_revid, chipid;
-       int ret;
-
-       ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, regid);
-       if (ret) {
-               dev_err_probe(cs35l41->dev, ret, "Get Device ID failed\n");
-               return ret;
-       }
-
-       ret = regmap_read(cs35l41->regmap, CS35L41_REVID, reg_revid);
-       if (ret) {
-               dev_err_probe(cs35l41->dev, ret, "Get Revision ID failed\n");
-               return ret;
-       }
-
-       mtl_revid = *reg_revid & CS35L41_MTLREVID_MASK;
-
-       chipid = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID;
-       if (*regid != chipid) {
-               dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", *regid, chipid);
-               return -ENODEV;
-       }
-
-       return 0;
-}
-
-static int cs35l41_ready_for_reset(struct cs35l41_hda *cs35l41)
-{
-       mutex_lock(&cs35l41->fw_mutex);
-       if (cs35l41->cs_dsp.running) {
-               cs35l41->cs_dsp.running = false;
-               cs35l41->cs_dsp.booted = false;
-       }
-       regcache_mark_dirty(cs35l41->regmap);
-       mutex_unlock(&cs35l41->fw_mutex);
-
-       return 0;
-}
-
-static int cs35l41_system_suspend_prep(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-
-       dev_dbg(cs35l41->dev, "System Suspend Prepare\n");
-
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
-               dev_err_once(cs35l41->dev, "System Suspend not supported\n");
-               return 0; /* don't block the whole system suspend */
-       }
-
-       mutex_lock(&cs35l41->fw_mutex);
-       if (cs35l41->playback_started)
-               cs35l41_hda_pause_start(dev);
-       mutex_unlock(&cs35l41->fw_mutex);
-
-       return 0;
-}
-
-static int cs35l41_system_suspend(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       int ret;
-
-       dev_dbg(cs35l41->dev, "System Suspend\n");
-
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
-               dev_err_once(cs35l41->dev, "System Suspend not supported\n");
-               return 0; /* don't block the whole system suspend */
-       }
-
-       mutex_lock(&cs35l41->fw_mutex);
-       if (cs35l41->playback_started)
-               cs35l41_hda_pause_done(dev);
-       mutex_unlock(&cs35l41->fw_mutex);
-
-       ret = pm_runtime_force_suspend(dev);
-       if (ret) {
-               dev_err(dev, "System Suspend Failed, unable to runtime suspend: %d\n", ret);
-               return ret;
-       }
-
-       /* Shutdown DSP before system suspend */
-       ret = cs35l41_ready_for_reset(cs35l41);
-       if (ret)
-               dev_err(dev, "System Suspend Failed, not ready for Reset: %d\n", ret);
-
-       if (cs35l41->reset_gpio) {
-               dev_info(cs35l41->dev, "Asserting Reset\n");
-               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
-               usleep_range(2000, 2100);
-       }
-
-       dev_dbg(cs35l41->dev, "System Suspended\n");
-
-       return ret;
-}
-
-static int cs35l41_wait_boot_done(struct cs35l41_hda *cs35l41)
-{
-       unsigned int int_status;
-       int ret;
-
-       ret = regmap_read_poll_timeout(cs35l41->regmap, CS35L41_IRQ1_STATUS4, int_status,
-                                      int_status & CS35L41_OTP_BOOT_DONE, 1000, 100000);
-       if (ret) {
-               dev_err(cs35l41->dev, "Failed waiting for OTP_BOOT_DONE\n");
-               return ret;
-       }
-
-       ret = regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_status);
-       if (ret || (int_status & CS35L41_OTP_BOOT_ERR)) {
-               dev_err(cs35l41->dev, "OTP Boot status %x error\n",
-                       int_status & CS35L41_OTP_BOOT_ERR);
-               if (!ret)
-                       ret = -EIO;
-               return ret;
-       }
-
-       return 0;
-}
-
-static int cs35l41_system_resume(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       int ret;
-
-       dev_dbg(cs35l41->dev, "System Resume\n");
-
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
-               dev_err_once(cs35l41->dev, "System Resume not supported\n");
-               return 0; /* don't block the whole system resume */
-       }
-
-       if (cs35l41->reset_gpio) {
-               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
-               usleep_range(2000, 2100);
-               gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
-       }
-
-       usleep_range(2000, 2100);
-
-       regcache_cache_only(cs35l41->regmap, false);
-
-       regmap_write(cs35l41->regmap, CS35L41_SFT_RESET, CS35L41_SOFTWARE_RESET);
-       usleep_range(2000, 2100);
-
-       ret = cs35l41_wait_boot_done(cs35l41);
-       if (ret)
-               return ret;
-
-       regcache_cache_only(cs35l41->regmap, true);
-
-       ret = pm_runtime_force_resume(dev);
-       if (ret) {
-               dev_err(dev, "System Resume Failed: Unable to runtime resume: %d\n", ret);
-               return ret;
-       }
-
-       mutex_lock(&cs35l41->fw_mutex);
-
-       if (cs35l41->request_fw_load && !cs35l41->fw_request_ongoing) {
-               cs35l41->fw_request_ongoing = true;
-               schedule_work(&cs35l41->fw_load_work);
-       }
-       mutex_unlock(&cs35l41->fw_mutex);
-
-       return ret;
-}
-
-static int cs35l41_runtime_idle(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH)
-               return -EBUSY; /* suspend not supported yet on this model */
-       return 0;
-}
-
-static int cs35l41_runtime_suspend(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       int ret = 0;
-
-       dev_dbg(cs35l41->dev, "Runtime Suspend\n");
-
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
-               dev_dbg(cs35l41->dev, "Runtime Suspend not supported\n");
-               return 0;
-       }
-
-       mutex_lock(&cs35l41->fw_mutex);
-
-       if (cs35l41->cs_dsp.running) {
-               ret = cs35l41_enter_hibernate(cs35l41->dev, cs35l41->regmap,
-                                             cs35l41->hw_cfg.bst_type);
-               if (ret)
-                       goto err;
-       } else {
-               cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type);
-       }
-
-       regcache_cache_only(cs35l41->regmap, true);
-       regcache_mark_dirty(cs35l41->regmap);
-
-err:
-       mutex_unlock(&cs35l41->fw_mutex);
-
-       return ret;
-}
-
-static int cs35l41_runtime_resume(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       unsigned int regid, reg_revid;
-       int ret = 0;
-
-       dev_dbg(cs35l41->dev, "Runtime Resume\n");
-
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST_NO_VSPK_SWITCH) {
-               dev_dbg(cs35l41->dev, "Runtime Resume not supported\n");
-               return 0;
-       }
-
-       mutex_lock(&cs35l41->fw_mutex);
-
-       regcache_cache_only(cs35l41->regmap, false);
-
-       if (cs35l41->cs_dsp.running)    {
-               ret = cs35l41_exit_hibernate(cs35l41->dev, cs35l41->regmap);
-               if (ret) {
-                       dev_warn(cs35l41->dev, "Unable to exit Hibernate.");
-                       goto err;
-               }
-       }
-
-       ret = cs35l41_verify_id(cs35l41, &regid, &reg_revid);
-       if (ret)
-               goto err;
-
-       /* Test key needs to be unlocked to allow the OTP settings to re-apply */
-       cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
-       ret = regcache_sync(cs35l41->regmap);
-       cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
-       if (ret) {
-               dev_err(cs35l41->dev, "Failed to restore register cache: %d\n", ret);
-               goto err;
-       }
-
-       if (cs35l41->hw_cfg.bst_type == CS35L41_EXT_BOOST)
-               cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, &cs35l41->hw_cfg);
-
-       dev_dbg(cs35l41->dev, "CS35L41 Resumed (%x), Revision: %02X\n", regid, reg_revid);
-
-err:
-       mutex_unlock(&cs35l41->fw_mutex);
-
-       return ret;
-}
-
-static int cs35l41_hda_read_ctl(struct cs_dsp *dsp, const char *name, int type,
-                               unsigned int alg, void *buf, size_t len)
-{
-       int ret;
-
-       mutex_lock(&dsp->pwr_lock);
-       ret = cs_dsp_coeff_read_ctrl(cs_dsp_get_ctl(dsp, name, type, alg), 0, buf, len);
-       mutex_unlock(&dsp->pwr_lock);
-
-       return ret;
-}
-
-static int cs35l41_smart_amp(struct cs35l41_hda *cs35l41)
-{
-       unsigned int fw_status;
-       __be32 halo_sts;
-       int ret;
-
-       if (cs35l41->bypass_fw) {
-               dev_warn(cs35l41->dev, "Bypassing Firmware.\n");
-               return 0;
-       }
-
-       ret = cs35l41_init_dsp(cs35l41);
-       if (ret) {
-               dev_warn(cs35l41->dev, "Cannot Initialize Firmware. Error: %d\n", ret);
-               goto clean_dsp;
-       }
-
-       ret = cs35l41_write_fs_errata(cs35l41->dev, cs35l41->regmap);
-       if (ret) {
-               dev_err(cs35l41->dev, "Cannot Write FS Errata: %d\n", ret);
-               goto clean_dsp;
-       }
-
-       ret = cs_dsp_run(&cs35l41->cs_dsp);
-       if (ret) {
-               dev_err(cs35l41->dev, "Fail to start dsp: %d\n", ret);
-               goto clean_dsp;
-       }
-
-       ret = read_poll_timeout(cs35l41_hda_read_ctl, ret,
-                               be32_to_cpu(halo_sts) == HALO_STATE_CODE_RUN,
-                               1000, 15000, false, &cs35l41->cs_dsp, HALO_STATE_DSP_CTL_NAME,
-                               HALO_STATE_DSP_CTL_TYPE, HALO_STATE_DSP_CTL_ALG,
-                               &halo_sts, sizeof(halo_sts));
-
-       if (ret) {
-               dev_err(cs35l41->dev, "Timeout waiting for HALO Core to start. State: %u\n",
-                        halo_sts);
-               goto clean_dsp;
-       }
-
-       ret = regmap_read(cs35l41->regmap, CS35L41_DSP_MBOX_2, &fw_status);
-       if (ret < 0) {
-               dev_err(cs35l41->dev,
-                       "Failed to read firmware status: %d\n", ret);
-               goto clean_dsp;
-       }
-
-       switch (fw_status) {
-       case CSPL_MBOX_STS_RUNNING:
-       case CSPL_MBOX_STS_PAUSED:
-               break;
-       default:
-               dev_err(cs35l41->dev, "Firmware status is invalid: %u\n",
-                       fw_status);
-               ret = -EINVAL;
-               goto clean_dsp;
-       }
-
-       ret = cs35l41_set_cspl_mbox_cmd(cs35l41->dev, cs35l41->regmap, CSPL_MBOX_CMD_PAUSE);
-       if (ret) {
-               dev_err(cs35l41->dev, "Error waiting for DSP to pause: %u\n", ret);
-               goto clean_dsp;
-       }
-
-       dev_info(cs35l41->dev, "Firmware Loaded - Type: %s, Gain: %d\n",
-                cs35l41_hda_fw_ids[cs35l41->firmware_type], cs35l41->tuning_gain);
-
-       return 0;
-
-clean_dsp:
-       cs35l41_shutdown_dsp(cs35l41);
-       return ret;
-}
-
-static void cs35l41_load_firmware(struct cs35l41_hda *cs35l41, bool load)
-{
-       if (cs35l41->cs_dsp.running && !load) {
-               dev_dbg(cs35l41->dev, "Unloading Firmware\n");
-               cs35l41_shutdown_dsp(cs35l41);
-       } else if (!cs35l41->cs_dsp.running && load) {
-               dev_dbg(cs35l41->dev, "Loading Firmware\n");
-               cs35l41_smart_amp(cs35l41);
-       } else {
-               dev_dbg(cs35l41->dev, "Unable to Load firmware.\n");
-       }
-}
-
-static int cs35l41_fw_load_ctl_get(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = cs35l41->request_fw_load;
-       return 0;
-}
-
-static int cs35l41_mute_override_ctl_get(struct snd_kcontrol *kcontrol,
-                                        struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = cs35l41->mute_override;
-       return 0;
-}
-
-static void cs35l41_fw_load_work(struct work_struct *work)
-{
-       struct cs35l41_hda *cs35l41 = container_of(work, struct cs35l41_hda, fw_load_work);
-
-       pm_runtime_get_sync(cs35l41->dev);
-
-       mutex_lock(&cs35l41->fw_mutex);
-
-       /* Recheck if playback is ongoing, mutex will block playback during firmware loading */
-       if (cs35l41->playback_started)
-               dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback. Retrying...\n");
-       else
-               cs35l41_load_firmware(cs35l41, cs35l41->request_fw_load);
-
-       cs35l41->fw_request_ongoing = false;
-       mutex_unlock(&cs35l41->fw_mutex);
-
-       pm_runtime_put_autosuspend(cs35l41->dev);
-}
-
-static int cs35l41_fw_load_ctl_put(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
-
-       if (cs35l41->request_fw_load == ucontrol->value.integer.value[0])
-               return 0;
-
-       if (cs35l41->fw_request_ongoing) {
-               dev_dbg(cs35l41->dev, "Existing request not complete\n");
-               return -EBUSY;
-       }
-
-       /* Check if playback is ongoing when initial request is made */
-       if (cs35l41->playback_started) {
-               dev_err(cs35l41->dev, "Cannot Load/Unload firmware during Playback\n");
-               return -EBUSY;
-       }
-
-       cs35l41->fw_request_ongoing = true;
-       cs35l41->request_fw_load = ucontrol->value.integer.value[0];
-       schedule_work(&cs35l41->fw_load_work);
-
-       return 1;
-}
-
-static int cs35l41_fw_type_ctl_get(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.enumerated.item[0] = cs35l41->firmware_type;
-
-       return 0;
-}
-
-static int cs35l41_fw_type_ctl_put(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l41_hda *cs35l41 = snd_kcontrol_chip(kcontrol);
-
-       if (ucontrol->value.enumerated.item[0] < CS35L41_HDA_NUM_FW) {
-               if (cs35l41->firmware_type != ucontrol->value.enumerated.item[0]) {
-                       cs35l41->firmware_type = ucontrol->value.enumerated.item[0];
-                       return 1;
-               } else {
-                       return 0;
-               }
-       }
-
-       return -EINVAL;
-}
-
-static int cs35l41_fw_type_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
-{
-       return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(cs35l41_hda_fw_ids), cs35l41_hda_fw_ids);
-}
-
-static int cs35l41_create_controls(struct cs35l41_hda *cs35l41)
-{
-       char fw_type_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       char fw_load_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       char mute_override_ctl_name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       struct snd_kcontrol_new fw_type_ctl = {
-               .name = fw_type_ctl_name,
-               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-               .info = cs35l41_fw_type_ctl_info,
-               .get = cs35l41_fw_type_ctl_get,
-               .put = cs35l41_fw_type_ctl_put,
-       };
-       struct snd_kcontrol_new fw_load_ctl = {
-               .name = fw_load_ctl_name,
-               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-               .info = snd_ctl_boolean_mono_info,
-               .get = cs35l41_fw_load_ctl_get,
-               .put = cs35l41_fw_load_ctl_put,
-       };
-       struct snd_kcontrol_new mute_override_ctl = {
-               .name = mute_override_ctl_name,
-               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-               .info = snd_ctl_boolean_mono_info,
-               .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
-               .get = cs35l41_mute_override_ctl_get,
-       };
-       int ret;
-
-       scnprintf(fw_type_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Type",
-                 cs35l41->amp_name);
-       scnprintf(fw_load_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s DSP1 Firmware Load",
-                 cs35l41->amp_name);
-       scnprintf(mute_override_ctl_name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "%s Forced Mute Status",
-                 cs35l41->amp_name);
-
-       ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_type_ctl, cs35l41));
-       if (ret) {
-               dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_type_ctl.name, ret);
-               return ret;
-       }
-
-       dev_dbg(cs35l41->dev, "Added Control %s\n", fw_type_ctl.name);
-
-       ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&fw_load_ctl, cs35l41));
-       if (ret) {
-               dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", fw_load_ctl.name, ret);
-               return ret;
-       }
-
-       dev_dbg(cs35l41->dev, "Added Control %s\n", fw_load_ctl.name);
-
-       ret = snd_ctl_add(cs35l41->codec->card, snd_ctl_new1(&mute_override_ctl, cs35l41));
-       if (ret) {
-               dev_err(cs35l41->dev, "Failed to add KControl %s = %d\n", mute_override_ctl.name,
-                       ret);
-               return ret;
-       }
-
-       dev_dbg(cs35l41->dev, "Added Control %s\n", mute_override_ctl.name);
-
-       return 0;
-}
-
-static bool cs35l41_dsm_supported(acpi_handle handle, unsigned int commands)
-{
-       guid_t guid;
-
-       guid_parse(CS35L41_UUID, &guid);
-
-       return acpi_check_dsm(handle, &guid, 0, BIT(commands));
-}
-
-static int cs35l41_get_acpi_mute_state(struct cs35l41_hda *cs35l41, acpi_handle handle)
-{
-       guid_t guid;
-       union acpi_object *ret;
-       int mute = -ENODEV;
-
-       guid_parse(CS35L41_UUID, &guid);
-
-       if (cs35l41_dsm_supported(handle, CS35L41_DSM_GET_MUTE)) {
-               ret = acpi_evaluate_dsm(handle, &guid, 0, CS35L41_DSM_GET_MUTE, NULL);
-               mute = *ret->buffer.pointer;
-               dev_dbg(cs35l41->dev, "CS35L41_DSM_GET_MUTE: %d\n", mute);
-       }
-
-       dev_dbg(cs35l41->dev, "%s: %d\n", __func__, mute);
-
-       return mute;
-}
-
-static void cs35l41_acpi_device_notify(acpi_handle handle, u32 event, struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       int mute;
-
-       if (event != CS35L41_NOTIFY_EVENT)
-               return;
-
-       mute = cs35l41_get_acpi_mute_state(cs35l41, handle);
-       if (mute < 0) {
-               dev_warn(cs35l41->dev, "Unable to retrieve mute state: %d\n", mute);
-               return;
-       }
-
-       dev_dbg(cs35l41->dev, "Requesting mute value: %d\n", mute);
-       cs35l41->mute_override = (mute > 0);
-       cs35l41_mute(cs35l41->dev, cs35l41->mute_override);
-}
-
-static int cs35l41_hda_bind(struct device *dev, struct device *master, void *master_data)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       struct hda_component_parent *parent = master_data;
-       struct hda_component *comp;
-       unsigned int sleep_flags;
-       int ret = 0;
-
-       comp = hda_component_from_index(parent, cs35l41->index);
-       if (!comp)
-               return -EINVAL;
-
-       if (comp->dev)
-               return -EBUSY;
-
-       pm_runtime_get_sync(dev);
-
-       mutex_lock(&cs35l41->fw_mutex);
-
-       comp->dev = dev;
-       cs35l41->codec = parent->codec;
-       if (!cs35l41->acpi_subsystem_id)
-               cs35l41->acpi_subsystem_id = kasprintf(GFP_KERNEL, "%.8x",
-                                                      cs35l41->codec->core.subsystem_id);
-
-       strscpy(comp->name, dev_name(dev), sizeof(comp->name));
-
-       cs35l41->firmware_type = CS35L41_HDA_FW_SPK_PROT;
-
-       if (firmware_autostart) {
-               dev_dbg(cs35l41->dev, "Firmware Autostart.\n");
-               cs35l41->request_fw_load = true;
-               if (cs35l41_smart_amp(cs35l41) < 0)
-                       dev_warn(cs35l41->dev, "Cannot Run Firmware, reverting to dsp bypass...\n");
-       } else {
-               dev_dbg(cs35l41->dev, "Firmware Autostart is disabled.\n");
-       }
-
-       ret = cs35l41_create_controls(cs35l41);
-
-       comp->playback_hook = cs35l41_hda_playback_hook;
-       comp->pre_playback_hook = cs35l41_hda_pre_playback_hook;
-       comp->post_playback_hook = cs35l41_hda_post_playback_hook;
-       comp->acpi_notify = cs35l41_acpi_device_notify;
-       comp->adev = cs35l41->dacpi;
-
-       comp->acpi_notifications_supported = cs35l41_dsm_supported(acpi_device_handle(comp->adev),
-               CS35L41_DSM_GET_MUTE);
-
-       cs35l41->mute_override = cs35l41_get_acpi_mute_state(cs35l41,
-                                               acpi_device_handle(cs35l41->dacpi)) > 0;
-
-       mutex_unlock(&cs35l41->fw_mutex);
-
-       sleep_flags = lock_system_sleep();
-       if (!device_link_add(&cs35l41->codec->core.dev, cs35l41->dev, DL_FLAG_STATELESS))
-               dev_warn(dev, "Unable to create device link\n");
-       unlock_system_sleep(sleep_flags);
-
-       pm_runtime_put_autosuspend(dev);
-
-       dev_info(cs35l41->dev,
-                "CS35L41 Bound - SSID: %s, BST: %d, VSPK: %d, CH: %c, FW EN: %d, SPKID: %d\n",
-                cs35l41->acpi_subsystem_id, cs35l41->hw_cfg.bst_type,
-                cs35l41->hw_cfg.gpio1.func == CS35l41_VSPK_SWITCH,
-                channel_name[cs35l41->hw_cfg.spk_pos],
-                cs35l41->cs_dsp.running, cs35l41->speaker_id);
-
-       return ret;
-}
-
-static void cs35l41_hda_unbind(struct device *dev, struct device *master, void *master_data)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-       struct hda_component_parent *parent = master_data;
-       struct hda_component *comp;
-       unsigned int sleep_flags;
-
-       comp = hda_component_from_index(parent, cs35l41->index);
-       if (!comp)
-               return;
-
-       if (comp->dev == dev) {
-               sleep_flags = lock_system_sleep();
-               device_link_remove(&cs35l41->codec->core.dev, cs35l41->dev);
-               unlock_system_sleep(sleep_flags);
-               memset(comp, 0, sizeof(*comp));
-       }
-}
-
-static const struct component_ops cs35l41_hda_comp_ops = {
-       .bind = cs35l41_hda_bind,
-       .unbind = cs35l41_hda_unbind,
-};
-
-static irqreturn_t cs35l41_bst_short_err(int irq, void *data)
-{
-       struct cs35l41_hda *cs35l41 = data;
-
-       dev_crit_ratelimited(cs35l41->dev, "LBST Error\n");
-       set_bit(CS35L41_BST_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t cs35l41_bst_dcm_uvp_err(int irq, void *data)
-{
-       struct cs35l41_hda *cs35l41 = data;
-
-       dev_crit_ratelimited(cs35l41->dev, "DCM VBST Under Voltage Error\n");
-       set_bit(CS35L41_BST_UVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t cs35l41_bst_ovp_err(int irq, void *data)
-{
-       struct cs35l41_hda *cs35l41 = data;
-
-       dev_crit_ratelimited(cs35l41->dev, "VBST Over Voltage error\n");
-       set_bit(CS35L41_BST_OVP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t cs35l41_temp_err(int irq, void *data)
-{
-       struct cs35l41_hda *cs35l41 = data;
-
-       dev_crit_ratelimited(cs35l41->dev, "Over temperature error\n");
-       set_bit(CS35L41_TEMP_ERR_RLS_SHIFT, &cs35l41->irq_errors);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t cs35l41_temp_warn(int irq, void *data)
-{
-       struct cs35l41_hda *cs35l41 = data;
-
-       dev_crit_ratelimited(cs35l41->dev, "Over temperature warning\n");
-       set_bit(CS35L41_TEMP_WARN_ERR_RLS_SHIFT, &cs35l41->irq_errors);
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t cs35l41_amp_short(int irq, void *data)
-{
-       struct cs35l41_hda *cs35l41 = data;
-
-       dev_crit_ratelimited(cs35l41->dev, "Amp short error\n");
-       set_bit(CS35L41_AMP_SHORT_ERR_RLS_SHIFT, &cs35l41->irq_errors);
-
-       return IRQ_HANDLED;
-}
-
-static const struct cs35l41_irq cs35l41_irqs[] = {
-       CS35L41_IRQ(BST_OVP_ERR, "Boost Overvoltage Error", cs35l41_bst_ovp_err),
-       CS35L41_IRQ(BST_DCM_UVP_ERR, "Boost Undervoltage Error", cs35l41_bst_dcm_uvp_err),
-       CS35L41_IRQ(BST_SHORT_ERR, "Boost Inductor Short Error", cs35l41_bst_short_err),
-       CS35L41_IRQ(TEMP_WARN, "Temperature Warning", cs35l41_temp_warn),
-       CS35L41_IRQ(TEMP_ERR, "Temperature Error", cs35l41_temp_err),
-       CS35L41_IRQ(AMP_SHORT_ERR, "Amp Short", cs35l41_amp_short),
-};
-
-static const struct regmap_irq cs35l41_reg_irqs[] = {
-       CS35L41_REG_IRQ(IRQ1_STATUS1, BST_OVP_ERR),
-       CS35L41_REG_IRQ(IRQ1_STATUS1, BST_DCM_UVP_ERR),
-       CS35L41_REG_IRQ(IRQ1_STATUS1, BST_SHORT_ERR),
-       CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_WARN),
-       CS35L41_REG_IRQ(IRQ1_STATUS1, TEMP_ERR),
-       CS35L41_REG_IRQ(IRQ1_STATUS1, AMP_SHORT_ERR),
-};
-
-static const struct regmap_irq_chip cs35l41_regmap_irq_chip = {
-       .name = "cs35l41 IRQ1 Controller",
-       .status_base = CS35L41_IRQ1_STATUS1,
-       .mask_base = CS35L41_IRQ1_MASK1,
-       .ack_base = CS35L41_IRQ1_STATUS1,
-       .num_regs = 4,
-       .irqs = cs35l41_reg_irqs,
-       .num_irqs = ARRAY_SIZE(cs35l41_reg_irqs),
-       .runtime_pm = true,
-};
-
-static void cs35l41_configure_interrupt(struct cs35l41_hda *cs35l41, int irq_pol)
-{
-       int irq;
-       int ret;
-       int i;
-
-       if (!cs35l41->irq) {
-               dev_warn(cs35l41->dev, "No Interrupt Found");
-               goto err;
-       }
-
-       ret = devm_regmap_add_irq_chip(cs35l41->dev, cs35l41->regmap, cs35l41->irq,
-                                       IRQF_ONESHOT | IRQF_SHARED | irq_pol,
-                                       0, &cs35l41_regmap_irq_chip, &cs35l41->irq_data);
-       if (ret) {
-               dev_dbg(cs35l41->dev, "Unable to add IRQ Chip: %d.", ret);
-               goto err;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(cs35l41_irqs); i++) {
-               irq = regmap_irq_get_virq(cs35l41->irq_data, cs35l41_irqs[i].irq);
-               if (irq < 0) {
-                       ret = irq;
-                       dev_dbg(cs35l41->dev, "Unable to map IRQ %s: %d.", cs35l41_irqs[i].name,
-                               ret);
-                       goto err;
-               }
-
-               ret = devm_request_threaded_irq(cs35l41->dev, irq, NULL,
-                                               cs35l41_irqs[i].handler,
-                                               IRQF_ONESHOT | IRQF_SHARED | irq_pol,
-                                               cs35l41_irqs[i].name, cs35l41);
-               if (ret) {
-                       dev_dbg(cs35l41->dev, "Unable to allocate IRQ %s:: %d.",
-                               cs35l41_irqs[i].name, ret);
-                       goto err;
-               }
-       }
-       return;
-err:
-       dev_warn(cs35l41->dev,
-                "IRQ Config Failed. Amp errors may not be recoverable without reboot.");
-}
-
-static int cs35l41_hda_apply_properties(struct cs35l41_hda *cs35l41)
-{
-       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
-       bool using_irq = false;
-       int irq_pol;
-       int ret;
-
-       if (!cs35l41->hw_cfg.valid)
-               return -EINVAL;
-
-       ret = cs35l41_init_boost(cs35l41->dev, cs35l41->regmap, hw_cfg);
-       if (ret)
-               return ret;
-
-       if (hw_cfg->gpio1.valid) {
-               switch (hw_cfg->gpio1.func) {
-               case CS35L41_NOT_USED:
-                       break;
-               case CS35l41_VSPK_SWITCH:
-                       hw_cfg->gpio1.func = CS35L41_GPIO1_GPIO;
-                       hw_cfg->gpio1.out_en = true;
-                       break;
-               case CS35l41_SYNC:
-                       hw_cfg->gpio1.func = CS35L41_GPIO1_MDSYNC;
-                       break;
-               default:
-                       dev_err(cs35l41->dev, "Invalid function %d for GPIO1\n",
-                               hw_cfg->gpio1.func);
-                       return -EINVAL;
-               }
-       }
-
-       if (hw_cfg->gpio2.valid) {
-               switch (hw_cfg->gpio2.func) {
-               case CS35L41_NOT_USED:
-                       break;
-               case CS35L41_INTERRUPT:
-                       using_irq = true;
-                       hw_cfg->gpio2.func = CS35L41_GPIO2_INT_OPEN_DRAIN;
-                       break;
-               default:
-                       dev_err(cs35l41->dev, "Invalid GPIO2 function %d\n", hw_cfg->gpio2.func);
-                       return -EINVAL;
-               }
-       }
-
-       irq_pol = cs35l41_gpio_config(cs35l41->regmap, hw_cfg);
-
-       if (using_irq)
-               cs35l41_configure_interrupt(cs35l41, irq_pol);
-
-       return cs35l41_hda_channel_map(cs35l41);
-}
-
-int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id)
-{
-       struct gpio_desc *speaker_id_desc;
-       int speaker_id = -ENODEV;
-
-       if (fixed_gpio_id >= 0) {
-               dev_dbg(dev, "Found Fixed Speaker ID GPIO (index = %d)\n", fixed_gpio_id);
-               speaker_id_desc = gpiod_get_index(dev, NULL, fixed_gpio_id, GPIOD_IN);
-               if (IS_ERR(speaker_id_desc)) {
-                       speaker_id = PTR_ERR(speaker_id_desc);
-                       return speaker_id;
-               }
-               speaker_id = gpiod_get_value_cansleep(speaker_id_desc);
-               gpiod_put(speaker_id_desc);
-               dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
-       } else {
-               int base_index;
-               int gpios_per_amp;
-               int count;
-               int tmp;
-               int i;
-
-               count = gpiod_count(dev, "spk-id");
-               if (count > 0) {
-                       speaker_id = 0;
-                       gpios_per_amp = count / num_amps;
-                       base_index = gpios_per_amp * amp_index;
-
-                       if (count % num_amps)
-                               return -EINVAL;
-
-                       dev_dbg(dev, "Found %d Speaker ID GPIOs per Amp\n", gpios_per_amp);
-
-                       for (i = 0; i < gpios_per_amp; i++) {
-                               speaker_id_desc = gpiod_get_index(dev, "spk-id", i + base_index,
-                                                                 GPIOD_IN);
-                               if (IS_ERR(speaker_id_desc)) {
-                                       speaker_id = PTR_ERR(speaker_id_desc);
-                                       break;
-                               }
-                               tmp = gpiod_get_value_cansleep(speaker_id_desc);
-                               gpiod_put(speaker_id_desc);
-                               if (tmp < 0) {
-                                       speaker_id = tmp;
-                                       break;
-                               }
-                               speaker_id |= tmp << i;
-                       }
-                       dev_dbg(dev, "Speaker ID = %d\n", speaker_id);
-               }
-       }
-       return speaker_id;
-}
-
-int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id)
-{
-       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
-       u32 values[HDA_MAX_COMPONENTS];
-       char *property;
-       size_t nval;
-       int i, ret;
-
-       property = "cirrus,dev-index";
-       ret = device_property_count_u32(physdev, property);
-       if (ret <= 0)
-               goto err;
-
-       if (ret > ARRAY_SIZE(values)) {
-               ret = -EINVAL;
-               goto err;
-       }
-       nval = ret;
-
-       ret = device_property_read_u32_array(physdev, property, values, nval);
-       if (ret)
-               goto err;
-
-       cs35l41->index = -1;
-       for (i = 0; i < nval; i++) {
-               if (values[i] == id) {
-                       cs35l41->index = i;
-                       break;
-               }
-       }
-       if (cs35l41->index == -1) {
-               dev_err(cs35l41->dev, "No index found in %s\n", property);
-               ret = -ENODEV;
-               goto err;
-       }
-
-       /* To use the same release code for all laptop variants we can't use devm_ version of
-        * gpiod_get here, as CLSA010* don't have a fully functional bios with an _DSD node
-        */
-       cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
-                                                    cs35l41->index, GPIOD_OUT_LOW,
-                                                    "cs35l41-reset");
-
-       property = "cirrus,speaker-position";
-       ret = device_property_read_u32_array(physdev, property, values, nval);
-       if (ret)
-               goto err;
-       hw_cfg->spk_pos = values[cs35l41->index];
-
-       cs35l41->channel_index = 0;
-       for (i = 0; i < cs35l41->index; i++)
-               if (values[i] == hw_cfg->spk_pos)
-                       cs35l41->channel_index++;
-
-       property = "cirrus,gpio1-func";
-       ret = device_property_read_u32_array(physdev, property, values, nval);
-       if (ret)
-               goto err;
-       hw_cfg->gpio1.func = values[cs35l41->index];
-       hw_cfg->gpio1.valid = true;
-
-       property = "cirrus,gpio2-func";
-       ret = device_property_read_u32_array(physdev, property, values, nval);
-       if (ret)
-               goto err;
-       hw_cfg->gpio2.func = values[cs35l41->index];
-       hw_cfg->gpio2.valid = true;
-
-       property = "cirrus,boost-peak-milliamp";
-       ret = device_property_read_u32_array(physdev, property, values, nval);
-       if (ret == 0)
-               hw_cfg->bst_ipk = values[cs35l41->index];
-       else
-               hw_cfg->bst_ipk = -1;
-
-       property = "cirrus,boost-ind-nanohenry";
-       ret = device_property_read_u32_array(physdev, property, values, nval);
-       if (ret == 0)
-               hw_cfg->bst_ind = values[cs35l41->index];
-       else
-               hw_cfg->bst_ind = -1;
-
-       property = "cirrus,boost-cap-microfarad";
-       ret = device_property_read_u32_array(physdev, property, values, nval);
-       if (ret == 0)
-               hw_cfg->bst_cap = values[cs35l41->index];
-       else
-               hw_cfg->bst_cap = -1;
-
-       cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, nval, -1);
-
-       if (hw_cfg->bst_ind > 0 || hw_cfg->bst_cap > 0 || hw_cfg->bst_ipk > 0)
-               hw_cfg->bst_type = CS35L41_INT_BOOST;
-       else
-               hw_cfg->bst_type = CS35L41_EXT_BOOST;
-
-       hw_cfg->valid = true;
-
-       return 0;
-err:
-       dev_err(cs35l41->dev, "Failed property %s: %d\n", property, ret);
-       hw_cfg->valid = false;
-       hw_cfg->gpio1.valid = false;
-       hw_cfg->gpio2.valid = false;
-       acpi_dev_put(cs35l41->dacpi);
-
-       return ret;
-}
-
-static int cs35l41_hda_read_acpi(struct cs35l41_hda *cs35l41, const char *hid, int id)
-{
-       struct acpi_device *adev;
-       struct device *physdev;
-       struct spi_device *spi;
-       const char *sub;
-       int ret;
-
-       adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
-       if (!adev) {
-               dev_err(cs35l41->dev, "Failed to find an ACPI device for %s\n", hid);
-               return -ENODEV;
-       }
-
-       cs35l41->dacpi = adev;
-       physdev = get_device(acpi_get_first_physical_node(adev));
-
-       sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
-       if (IS_ERR(sub))
-               sub = NULL;
-       cs35l41->acpi_subsystem_id = sub;
-
-       ret = cs35l41_add_dsd_properties(cs35l41, physdev, id, hid);
-       if (!ret) {
-               dev_info(cs35l41->dev, "Using extra _DSD properties, bypassing _DSD in ACPI\n");
-               goto out;
-       }
-
-       ret = cs35l41_hda_parse_acpi(cs35l41, physdev, id);
-       if (ret) {
-               put_device(physdev);
-               return ret;
-       }
-out:
-       put_device(physdev);
-
-       cs35l41->bypass_fw = false;
-       if (cs35l41->control_bus == SPI) {
-               spi = to_spi_device(cs35l41->dev);
-               if (spi->max_speed_hz < CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ) {
-                       dev_warn(cs35l41->dev,
-                                "SPI speed is too slow to support firmware download: %d Hz.\n",
-                                spi->max_speed_hz);
-                       cs35l41->bypass_fw = true;
-               }
-       }
-
-       return 0;
-}
-
-int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
-                     struct regmap *regmap, enum control_bus control_bus)
-{
-       unsigned int regid, reg_revid;
-       struct cs35l41_hda *cs35l41;
-       int ret;
-
-       BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != ARRAY_SIZE(cs35l41_reg_irqs));
-       BUILD_BUG_ON(ARRAY_SIZE(cs35l41_irqs) != CS35L41_NUM_IRQ);
-
-       if (IS_ERR(regmap))
-               return PTR_ERR(regmap);
-
-       cs35l41 = devm_kzalloc(dev, sizeof(*cs35l41), GFP_KERNEL);
-       if (!cs35l41)
-               return -ENOMEM;
-
-       cs35l41->dev = dev;
-       cs35l41->irq = irq;
-       cs35l41->regmap = regmap;
-       cs35l41->control_bus = control_bus;
-       dev_set_drvdata(dev, cs35l41);
-
-       ret = cs35l41_hda_read_acpi(cs35l41, device_name, id);
-       if (ret)
-               return dev_err_probe(cs35l41->dev, ret, "Platform not supported\n");
-
-       if (IS_ERR(cs35l41->reset_gpio)) {
-               ret = PTR_ERR(cs35l41->reset_gpio);
-               cs35l41->reset_gpio = NULL;
-               if (ret == -EBUSY) {
-                       dev_info(cs35l41->dev, "Reset line busy, assuming shared reset\n");
-               } else {
-                       dev_err_probe(cs35l41->dev, ret, "Failed to get reset GPIO\n");
-                       goto err;
-               }
-       }
-       if (cs35l41->reset_gpio) {
-               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
-               usleep_range(2000, 2100);
-               gpiod_set_value_cansleep(cs35l41->reset_gpio, 1);
-       }
-
-       usleep_range(2000, 2100);
-       regmap_write(cs35l41->regmap, CS35L41_SFT_RESET, CS35L41_SOFTWARE_RESET);
-       usleep_range(2000, 2100);
-
-       ret = cs35l41_wait_boot_done(cs35l41);
-       if (ret)
-               goto err;
-
-       ret = cs35l41_verify_id(cs35l41, &regid, &reg_revid);
-       if (ret)
-               goto err;
-
-       ret = cs35l41_test_key_unlock(cs35l41->dev, cs35l41->regmap);
-       if (ret)
-               goto err;
-
-       ret = cs35l41_register_errata_patch(cs35l41->dev, cs35l41->regmap, reg_revid);
-       if (ret)
-               goto err;
-
-       ret = cs35l41_otp_unpack(cs35l41->dev, cs35l41->regmap);
-       if (ret) {
-               dev_err_probe(cs35l41->dev, ret, "OTP Unpack failed\n");
-               goto err;
-       }
-
-       ret = cs35l41_test_key_lock(cs35l41->dev, cs35l41->regmap);
-       if (ret)
-               goto err;
-
-       ret = cs35l41_get_calibration(cs35l41);
-       if (ret && ret != -ENOENT)
-               goto err;
-
-       cs35l41_mute(cs35l41->dev, true);
-
-       INIT_WORK(&cs35l41->fw_load_work, cs35l41_fw_load_work);
-       mutex_init(&cs35l41->fw_mutex);
-
-       pm_runtime_set_autosuspend_delay(cs35l41->dev, 3000);
-       pm_runtime_use_autosuspend(cs35l41->dev);
-       pm_runtime_set_active(cs35l41->dev);
-       pm_runtime_get_noresume(cs35l41->dev);
-       pm_runtime_enable(cs35l41->dev);
-
-       ret = cs35l41_hda_apply_properties(cs35l41);
-       if (ret)
-               goto err_pm;
-
-       pm_runtime_put_autosuspend(cs35l41->dev);
-
-       ret = component_add(cs35l41->dev, &cs35l41_hda_comp_ops);
-       if (ret) {
-               dev_err_probe(cs35l41->dev, ret, "Register component failed\n");
-               goto err_pm;
-       }
-
-       dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", regid, reg_revid);
-
-       return 0;
-
-err_pm:
-       pm_runtime_dont_use_autosuspend(cs35l41->dev);
-       pm_runtime_disable(cs35l41->dev);
-       pm_runtime_put_noidle(cs35l41->dev);
-
-err:
-       if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
-               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
-       gpiod_put(cs35l41->reset_gpio);
-       gpiod_put(cs35l41->cs_gpio);
-       acpi_dev_put(cs35l41->dacpi);
-       kfree(cs35l41->acpi_subsystem_id);
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l41_hda_probe, "SND_HDA_SCODEC_CS35L41");
-
-void cs35l41_hda_remove(struct device *dev)
-{
-       struct cs35l41_hda *cs35l41 = dev_get_drvdata(dev);
-
-       component_del(cs35l41->dev, &cs35l41_hda_comp_ops);
-
-       pm_runtime_get_sync(cs35l41->dev);
-       pm_runtime_dont_use_autosuspend(cs35l41->dev);
-       pm_runtime_disable(cs35l41->dev);
-
-       if (cs35l41->halo_initialized)
-               cs35l41_remove_dsp(cs35l41);
-
-       acpi_dev_put(cs35l41->dacpi);
-
-       pm_runtime_put_noidle(cs35l41->dev);
-
-       if (cs35l41_safe_reset(cs35l41->regmap, cs35l41->hw_cfg.bst_type))
-               gpiod_set_value_cansleep(cs35l41->reset_gpio, 0);
-       gpiod_put(cs35l41->reset_gpio);
-       gpiod_put(cs35l41->cs_gpio);
-       kfree(cs35l41->acpi_subsystem_id);
-}
-EXPORT_SYMBOL_NS_GPL(cs35l41_hda_remove, "SND_HDA_SCODEC_CS35L41");
-
-const struct dev_pm_ops cs35l41_hda_pm_ops = {
-       RUNTIME_PM_OPS(cs35l41_runtime_suspend, cs35l41_runtime_resume,
-                      cs35l41_runtime_idle)
-       .prepare = cs35l41_system_suspend_prep,
-       SYSTEM_SLEEP_PM_OPS(cs35l41_system_suspend, cs35l41_system_resume)
-};
-EXPORT_SYMBOL_NS_GPL(cs35l41_hda_pm_ops, "SND_HDA_SCODEC_CS35L41");
-
-MODULE_DESCRIPTION("CS35L41 HDA Driver");
-MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
-MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS("FW_CS_DSP");
-MODULE_FIRMWARE("cirrus/cs35l41-*.wmfw");
-MODULE_FIRMWARE("cirrus/cs35l41-*.bin");
diff --git a/sound/pci/hda/cs35l41_hda.h b/sound/pci/hda/cs35l41_hda.h
deleted file mode 100644 (file)
index 7d003c5..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * CS35L41 ALSA HDA audio driver
- *
- * Copyright 2021 Cirrus Logic, Inc.
- *
- * Author: Lucas Tanure <tanureal@opensource.cirrus.com>
- */
-
-#ifndef __CS35L41_HDA_H__
-#define __CS35L41_HDA_H__
-
-#include <linux/acpi.h>
-#include <linux/efi.h>
-#include <linux/regulator/consumer.h>
-#include <linux/gpio/consumer.h>
-#include <linux/device.h>
-#include <sound/cs35l41.h>
-#include <sound/cs-amp-lib.h>
-
-#include <linux/firmware/cirrus/cs_dsp.h>
-#include <linux/firmware/cirrus/wmfw.h>
-
-#define CS35L41_MAX_ACCEPTABLE_SPI_SPEED_HZ    1000000
-#define DEFAULT_AMP_GAIN_PCM                   17      /* 17.5dB Gain */
-#define DEFAULT_AMP_GAIN_PDM                   19      /* 19.5dB Gain */
-
-struct cs35l41_amp_cal_data {
-       u32 calTarget[2];
-       u32 calTime[2];
-       s8 calAmbient;
-       u8 calStatus;
-       u16 calR;
-} __packed;
-
-struct cs35l41_amp_efi_data {
-       u32 size;
-       u32 count;
-       struct cs35l41_amp_cal_data data[];
-} __packed;
-
-enum cs35l41_hda_spk_pos {
-       CS35L41_LEFT,
-       CS35L41_RIGHT,
-       CS35L41_CENTER,
-};
-
-enum cs35l41_hda_gpio_function {
-       CS35L41_NOT_USED,
-       CS35l41_VSPK_SWITCH,
-       CS35L41_INTERRUPT,
-       CS35l41_SYNC,
-};
-
-enum control_bus {
-       I2C,
-       SPI
-};
-
-struct cs35l41_hda {
-       struct device *dev;
-       struct regmap *regmap;
-       struct gpio_desc *reset_gpio;
-       struct gpio_desc *cs_gpio;
-       struct cs35l41_hw_cfg hw_cfg;
-       struct hda_codec *codec;
-
-       int irq;
-       int index;
-       int channel_index;
-       unsigned volatile long irq_errors;
-       const char *amp_name;
-       const char *acpi_subsystem_id;
-       int firmware_type;
-       int speaker_id;
-       struct mutex fw_mutex;
-       struct work_struct fw_load_work;
-
-       struct regmap_irq_chip_data *irq_data;
-       bool firmware_running;
-       bool request_fw_load;
-       bool fw_request_ongoing;
-       bool halo_initialized;
-       bool playback_started;
-       struct cs_dsp cs_dsp;
-       struct acpi_device *dacpi;
-       bool mute_override;
-       enum control_bus control_bus;
-       bool bypass_fw;
-       unsigned int tuning_gain;
-       struct cirrus_amp_cal_data cal_data;
-       bool cal_data_valid;
-
-};
-
-enum halo_state {
-       HALO_STATE_CODE_INIT_DOWNLOAD = 0,
-       HALO_STATE_CODE_START,
-       HALO_STATE_CODE_RUN
-};
-
-extern const struct dev_pm_ops cs35l41_hda_pm_ops;
-
-int cs35l41_hda_probe(struct device *dev, const char *device_name, int id, int irq,
-                     struct regmap *regmap, enum control_bus control_bus);
-void cs35l41_hda_remove(struct device *dev);
-int cs35l41_get_speaker_id(struct device *dev, int amp_index, int num_amps, int fixed_gpio_id);
-int cs35l41_hda_parse_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id);
-
-#endif /*__CS35L41_HDA_H__*/
diff --git a/sound/pci/hda/cs35l41_hda_i2c.c b/sound/pci/hda/cs35l41_hda_i2c.c
deleted file mode 100644 (file)
index e774954..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// CS35l41 HDA I2C driver
-//
-// Copyright 2021 Cirrus Logic, Inc.
-//
-// Author: Lucas Tanure <tanureal@opensource.cirrus.com>
-
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-
-#include "cs35l41_hda.h"
-
-static int cs35l41_hda_i2c_probe(struct i2c_client *clt)
-{
-       const char *device_name;
-
-       /*
-        * Compare against the device name so it works for SPI, normal ACPI
-        * and for ACPI by serial-multi-instantiate matching cases.
-        */
-       if (strstr(dev_name(&clt->dev), "CLSA0100"))
-               device_name = "CLSA0100";
-       else if (strstr(dev_name(&clt->dev), "CLSA0101"))
-               device_name = "CLSA0101";
-       else if (strstr(dev_name(&clt->dev), "CSC3551"))
-               device_name = "CSC3551";
-       else
-               return -ENODEV;
-
-       return cs35l41_hda_probe(&clt->dev, device_name, clt->addr, clt->irq,
-                                devm_regmap_init_i2c(clt, &cs35l41_regmap_i2c), I2C);
-}
-
-static void cs35l41_hda_i2c_remove(struct i2c_client *clt)
-{
-       cs35l41_hda_remove(&clt->dev);
-}
-
-static const struct i2c_device_id cs35l41_hda_i2c_id[] = {
-       { "cs35l41-hda" },
-       {}
-};
-
-static const struct acpi_device_id cs35l41_acpi_hda_match[] = {
-       {"CLSA0100", 0 },
-       {"CLSA0101", 0 },
-       {"CSC3551", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_hda_match);
-
-static struct i2c_driver cs35l41_i2c_driver = {
-       .driver = {
-               .name           = "cs35l41-hda",
-               .acpi_match_table = cs35l41_acpi_hda_match,
-               .pm             = &cs35l41_hda_pm_ops,
-       },
-       .id_table       = cs35l41_hda_i2c_id,
-       .probe          = cs35l41_hda_i2c_probe,
-       .remove         = cs35l41_hda_i2c_remove,
-};
-module_i2c_driver(cs35l41_i2c_driver);
-
-MODULE_DESCRIPTION("HDA CS35L41 driver");
-MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41");
-MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/cs35l41_hda_property.c b/sound/pci/hda/cs35l41_hda_property.c
deleted file mode 100644 (file)
index d8249d9..0000000
+++ /dev/null
@@ -1,578 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// CS35L41 ALSA HDA Property driver
-//
-// Copyright 2023 Cirrus Logic, Inc.
-//
-// Author: Stefan Binding <sbinding@opensource.cirrus.com>
-
-#include <linux/acpi.h>
-#include <linux/gpio/consumer.h>
-#include <linux/string.h>
-#include "cs35l41_hda_property.h"
-#include <linux/spi/spi.h>
-
-#define MAX_AMPS 4
-
-struct cs35l41_config {
-       const char *ssid;
-       int num_amps;
-       enum {
-               INTERNAL,
-               EXTERNAL
-       } boost_type;
-       u8 channel[MAX_AMPS];
-       int reset_gpio_index; /* -1 if no reset gpio */
-       int spkid_gpio_index; /* -1 if no spkid gpio */
-       int cs_gpio_index; /* -1 if no cs gpio, or cs-gpios already exists, max num amps == 2 */
-       int boost_ind_nanohenry; /* Required if boost_type == Internal */
-       int boost_peak_milliamp; /* Required if boost_type == Internal */
-       int boost_cap_microfarad; /* Required if boost_type == Internal */
-};
-
-static const struct cs35l41_config cs35l41_config_table[] = {
-       { "10251826", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "1025182C", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "10251844", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "10280B27", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10280B28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10280BEB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
-       { "10280C4D", 4, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT }, 0, 1, -1, 1000, 4500, 24 },
-/*
- * Device 103C89C6 does have _DSD, however it is setup to use the wrong boost type.
- * We can override the _DSD to correct the boost type here.
- * Since this laptop has valid ACPI, we do not need to handle cs-gpios, since that already exists
- * in the ACPI. The Reset GPIO is also valid, so we can use the Reset defined in _DSD.
- */
-       { "103C89C6", 2, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, -1, -1, -1, 1000, 4500, 24 },
-       { "103C8A28", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A29", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A2A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A2B", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A2C", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A2D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A2E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A31", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8A6E", 4, EXTERNAL, { CS35L41_LEFT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_RIGHT }, 0, -1, -1, 0, 0, 0 },
-       { "103C8BB3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BB4", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE0", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE1", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE2", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE5", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE6", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE7", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE8", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8BE9", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8B3A", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8C15", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
-       { "103C8C16", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
-       { "103C8C17", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4000, 24 },
-       { "103C8C4D", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8C4E", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8C4F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8C50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8C51", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8CDD", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4100, 24 },
-       { "103C8CDE", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 3900, 24 },
-       { "104312AF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10431433", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431463", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431473", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
-       { "10431483", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
-       { "10431493", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "104314D3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "104314E3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431503", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431533", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431573", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10431663", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 1000, 4500, 24 },
-       { "10431683", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
-       { "104316A3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
-       { "104316D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
-       { "104316F3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
-       { "104317F3", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431863", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "104318D3", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
-       { "10431A83", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431B93", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10431C9F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10431CAF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10431CCF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10431CDF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10431CEF", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10431D1F", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431DA2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
-       { "10431E02", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
-       { "10431E12", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
-       { "10431EE2", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "10431F12", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 1000, 4500, 24 },
-       { "10431F1F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, -1, 0, 0, 0, 0 },
-       { "10431F62", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 0, 0, 0 },
-       { "10433A20", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10433A30", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10433A40", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10433A50", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "10433A60", 2, INTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 1, 2, 0, 1000, 4500, 24 },
-       { "17AA3865", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "17AA3866", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "17AA386E", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
-       { "17AA386F", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "17AA3877", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "17AA3878", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, -1, -1, 0, 0, 0 },
-       { "17AA38A9", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
-       { "17AA38AB", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
-       { "17AA38B4", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
-       { "17AA38B5", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
-       { "17AA38B6", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
-       { "17AA38B7", 2, EXTERNAL, { CS35L41_LEFT, CS35L41_RIGHT, 0, 0 }, 0, 1, -1, 0, 0, 0 },
-       { "17AA38C7", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },
-       { "17AA38C8", 4, INTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, CS35L41_RIGHT, CS35L41_LEFT }, 0, 2, -1, 1000, 4500, 24 },
-       { "17AA38F9", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
-       { "17AA38FA", 2, EXTERNAL, { CS35L41_RIGHT, CS35L41_LEFT, 0, 0 }, 0, 2, -1, 0, 0, 0 },
-       {}
-};
-
-static int cs35l41_add_gpios(struct cs35l41_hda *cs35l41, struct device *physdev, int reset_gpio,
-                            int spkid_gpio, int cs_gpio_index, int num_amps)
-{
-       struct acpi_gpio_mapping *gpio_mapping = NULL;
-       struct acpi_gpio_params *reset_gpio_params = NULL;
-       struct acpi_gpio_params *spkid_gpio_params = NULL;
-       struct acpi_gpio_params *cs_gpio_params = NULL;
-       unsigned int num_entries = 0;
-       unsigned int reset_index, spkid_index, csgpio_index;
-       int i;
-
-       /*
-        * GPIO Mapping only needs to be done once, since it would be available for subsequent amps
-        */
-       if (cs35l41->dacpi->driver_gpios)
-               return 0;
-
-       if (reset_gpio >= 0) {
-               reset_index = num_entries;
-               num_entries++;
-       }
-
-       if (spkid_gpio >= 0) {
-               spkid_index = num_entries;
-               num_entries++;
-       }
-
-       if ((cs_gpio_index >= 0)  && (num_amps == 2)) {
-               csgpio_index = num_entries;
-               num_entries++;
-       }
-
-       if (!num_entries)
-               return 0;
-
-       /* must include termination entry */
-       num_entries++;
-
-       gpio_mapping = devm_kcalloc(physdev, num_entries, sizeof(struct acpi_gpio_mapping),
-                                   GFP_KERNEL);
-
-       if (!gpio_mapping)
-               goto err;
-
-       if (reset_gpio >= 0) {
-               gpio_mapping[reset_index].name = "reset-gpios";
-               reset_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),
-                                                GFP_KERNEL);
-               if (!reset_gpio_params)
-                       goto err;
-
-               for (i = 0; i < num_amps; i++)
-                       reset_gpio_params[i].crs_entry_index = reset_gpio;
-
-               gpio_mapping[reset_index].data = reset_gpio_params;
-               gpio_mapping[reset_index].size = num_amps;
-       }
-
-       if (spkid_gpio >= 0) {
-               gpio_mapping[spkid_index].name = "spk-id-gpios";
-               spkid_gpio_params = devm_kcalloc(physdev, num_amps, sizeof(struct acpi_gpio_params),
-                                                GFP_KERNEL);
-               if (!spkid_gpio_params)
-                       goto err;
-
-               for (i = 0; i < num_amps; i++)
-                       spkid_gpio_params[i].crs_entry_index = spkid_gpio;
-
-               gpio_mapping[spkid_index].data = spkid_gpio_params;
-               gpio_mapping[spkid_index].size = num_amps;
-       }
-
-       if ((cs_gpio_index >= 0) && (num_amps == 2)) {
-               gpio_mapping[csgpio_index].name = "cs-gpios";
-               /* only one GPIO CS is supported without using _DSD, obtained using index 0 */
-               cs_gpio_params = devm_kzalloc(physdev, sizeof(struct acpi_gpio_params), GFP_KERNEL);
-               if (!cs_gpio_params)
-                       goto err;
-
-               cs_gpio_params->crs_entry_index = cs_gpio_index;
-
-               gpio_mapping[csgpio_index].data = cs_gpio_params;
-               gpio_mapping[csgpio_index].size = 1;
-       }
-
-       return devm_acpi_dev_add_driver_gpios(physdev, gpio_mapping);
-err:
-       devm_kfree(physdev, gpio_mapping);
-       devm_kfree(physdev, reset_gpio_params);
-       devm_kfree(physdev, spkid_gpio_params);
-       devm_kfree(physdev, cs_gpio_params);
-       return -ENOMEM;
-}
-
-static int generic_dsd_config(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
-                             const char *hid)
-{
-       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
-       const struct cs35l41_config *cfg;
-       struct gpio_desc *cs_gpiod;
-       struct spi_device *spi;
-       bool dsd_found;
-       int ret;
-       int i;
-
-       for (cfg = cs35l41_config_table; cfg->ssid; cfg++) {
-               if (!strcasecmp(cfg->ssid, cs35l41->acpi_subsystem_id))
-                       break;
-       }
-
-       if (!cfg->ssid)
-               return -ENOENT;
-
-       if (!cs35l41->dacpi || cs35l41->dacpi != ACPI_COMPANION(physdev)) {
-               dev_err(cs35l41->dev, "ACPI Device does not match, cannot override _DSD.\n");
-               return -ENODEV;
-       }
-
-       dev_info(cs35l41->dev, "Adding DSD properties for %s\n", cs35l41->acpi_subsystem_id);
-
-       dsd_found = acpi_dev_has_props(cs35l41->dacpi);
-
-       if (!dsd_found) {
-               ret = cs35l41_add_gpios(cs35l41, physdev, cfg->reset_gpio_index,
-                                                cfg->spkid_gpio_index, cfg->cs_gpio_index,
-                                                cfg->num_amps);
-               if (ret) {
-                       dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);
-                       return ret;
-               }
-       } else if (cfg->reset_gpio_index >= 0 || cfg->spkid_gpio_index >= 0) {
-               dev_warn(cs35l41->dev, "Cannot add Reset/Speaker ID/SPI CS GPIO Mapping, "
-                        "_DSD already exists.\n");
-       }
-
-       if (cs35l41->control_bus == SPI) {
-               cs35l41->index = id;
-
-               /*
-                * Manually set the Chip Select for the second amp <cs_gpio_index> in the node.
-                * This is only supported for systems with 2 amps, since we cannot expand the
-                * default number of chip selects without using cs-gpios
-                * The CS GPIO must be set high prior to communicating with the first amp (which
-                * uses a native chip select), to ensure the second amp does not clash with the
-                * first.
-                */
-               if (IS_ENABLED(CONFIG_SPI) && cfg->cs_gpio_index >= 0) {
-                       spi = to_spi_device(cs35l41->dev);
-
-                       if (cfg->num_amps != 2) {
-                               dev_warn(cs35l41->dev,
-                                        "Cannot update SPI CS, Number of Amps (%d) != 2\n",
-                                        cfg->num_amps);
-                       } else if (dsd_found) {
-                               dev_warn(cs35l41->dev,
-                                       "Cannot update SPI CS, _DSD already exists.\n");
-                       } else {
-                               /*
-                                * This is obtained using driver_gpios, since only one GPIO for CS
-                                * exists, this can be obtained using index 0.
-                                */
-                               cs_gpiod = gpiod_get_index(physdev, "cs", 0, GPIOD_OUT_LOW);
-                               if (IS_ERR(cs_gpiod)) {
-                                       dev_err(cs35l41->dev,
-                                               "Unable to get Chip Select GPIO descriptor\n");
-                                       return PTR_ERR(cs_gpiod);
-                               }
-                               if (id == 1) {
-                                       spi_set_csgpiod(spi, 0, cs_gpiod);
-                                       cs35l41->cs_gpio = cs_gpiod;
-                               } else {
-                                       gpiod_set_value_cansleep(cs_gpiod, true);
-                                       gpiod_put(cs_gpiod);
-                               }
-                               spi_setup(spi);
-                       }
-               }
-       } else {
-               if (cfg->num_amps > 2)
-                       /*
-                        * i2c addresses for 3/4 amps are used in order: 0x40, 0x41, 0x42, 0x43,
-                        * subtracting 0x40 would give zero-based index
-                        */
-                       cs35l41->index = id - 0x40;
-               else
-                       /* i2c addr 0x40 for first amp (always), 0x41/0x42 for 2nd amp */
-                       cs35l41->index = id == 0x40 ? 0 : 1;
-       }
-
-       cs35l41->reset_gpio = fwnode_gpiod_get_index(acpi_fwnode_handle(cs35l41->dacpi), "reset",
-                                                    cs35l41->index, GPIOD_OUT_LOW,
-                                                    "cs35l41-reset");
-       cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, cs35l41->index, cfg->num_amps, -1);
-
-       hw_cfg->spk_pos = cfg->channel[cs35l41->index];
-
-       cs35l41->channel_index = 0;
-       for (i = 0; i < cs35l41->index; i++)
-               if (cfg->channel[i] == hw_cfg->spk_pos)
-                       cs35l41->channel_index++;
-
-       if (cfg->boost_type == INTERNAL) {
-               hw_cfg->bst_type = CS35L41_INT_BOOST;
-               hw_cfg->bst_ind = cfg->boost_ind_nanohenry;
-               hw_cfg->bst_ipk = cfg->boost_peak_milliamp;
-               hw_cfg->bst_cap = cfg->boost_cap_microfarad;
-               hw_cfg->gpio1.func = CS35L41_NOT_USED;
-               hw_cfg->gpio1.valid = true;
-       } else {
-               hw_cfg->bst_type = CS35L41_EXT_BOOST;
-               hw_cfg->bst_ind = -1;
-               hw_cfg->bst_ipk = -1;
-               hw_cfg->bst_cap = -1;
-               hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
-               hw_cfg->gpio1.valid = true;
-       }
-
-       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
-       hw_cfg->gpio2.valid = true;
-       hw_cfg->valid = true;
-
-       return 0;
-}
-
-/*
- * Systems 103C8C66, 103C8C67, 103C8C68, 103C8C6A use a dual speaker id system - each speaker has
- * its own speaker id.
- */
-static int hp_i2c_int_2amp_dual_spkid(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
-                                     const char *hid)
-{
-       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
-
-       /* If _DSD exists for this laptop, we cannot support it through here */
-       if (acpi_dev_has_props(cs35l41->dacpi))
-               return -ENOENT;
-
-       /* check I2C address to assign the index */
-       cs35l41->index = id == 0x40 ? 0 : 1;
-       cs35l41->channel_index = 0;
-       cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
-       if (cs35l41->index == 0)
-               cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 1);
-       else
-               cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
-       hw_cfg->spk_pos = cs35l41->index;
-       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
-       hw_cfg->gpio2.valid = true;
-       hw_cfg->valid = true;
-
-       hw_cfg->bst_type = CS35L41_INT_BOOST;
-       hw_cfg->bst_ind = 1000;
-       hw_cfg->bst_ipk = 4100;
-       hw_cfg->bst_cap = 24;
-       hw_cfg->gpio1.func = CS35L41_NOT_USED;
-       hw_cfg->gpio1.valid = true;
-
-       return 0;
-}
-
-/*
- * Device CLSA010(0/1) doesn't have _DSD so a gpiod_get by the label reset won't work.
- * And devices created by serial-multi-instantiate don't have their device struct
- * pointing to the correct fwnode, so acpi_dev must be used here.
- * And devm functions expect that the device requesting the resource has the correct
- * fwnode.
- */
-static int lenovo_legion_no_acpi(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
-                                const char *hid)
-{
-       struct cs35l41_hw_cfg *hw_cfg = &cs35l41->hw_cfg;
-
-       /* check I2C address to assign the index */
-       cs35l41->index = id == 0x40 ? 0 : 1;
-       cs35l41->channel_index = 0;
-       cs35l41->reset_gpio = gpiod_get_index(physdev, NULL, 0, GPIOD_OUT_HIGH);
-       cs35l41->speaker_id = cs35l41_get_speaker_id(physdev, 0, 0, 2);
-       hw_cfg->spk_pos = cs35l41->index;
-       hw_cfg->gpio2.func = CS35L41_INTERRUPT;
-       hw_cfg->gpio2.valid = true;
-       hw_cfg->valid = true;
-
-       if (strcmp(hid, "CLSA0100") == 0) {
-               hw_cfg->bst_type = CS35L41_EXT_BOOST_NO_VSPK_SWITCH;
-       } else if (strcmp(hid, "CLSA0101") == 0) {
-               hw_cfg->bst_type = CS35L41_EXT_BOOST;
-               hw_cfg->gpio1.func = CS35l41_VSPK_SWITCH;
-               hw_cfg->gpio1.valid = true;
-       }
-
-       return 0;
-}
-
-static int missing_speaker_id_gpio2(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
-                                   const char *hid)
-{
-       int ret;
-
-       ret = cs35l41_add_gpios(cs35l41, physdev, -1, 2, -1, 2);
-       if (ret) {
-               dev_err(cs35l41->dev, "Error adding GPIO mapping: %d\n", ret);
-               return ret;
-       }
-
-       return cs35l41_hda_parse_acpi(cs35l41, physdev, id);
-}
-
-struct cs35l41_prop_model {
-       const char *hid;
-       const char *ssid;
-       int (*add_prop)(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
-                       const char *hid);
-};
-
-static const struct cs35l41_prop_model cs35l41_prop_model_table[] = {
-       { "CLSA0100", NULL, lenovo_legion_no_acpi },
-       { "CLSA0101", NULL, lenovo_legion_no_acpi },
-       { "CSC3551", "10251826", generic_dsd_config },
-       { "CSC3551", "1025182C", generic_dsd_config },
-       { "CSC3551", "10251844", generic_dsd_config },
-       { "CSC3551", "10280B27", generic_dsd_config },
-       { "CSC3551", "10280B28", generic_dsd_config },
-       { "CSC3551", "10280BEB", generic_dsd_config },
-       { "CSC3551", "10280C4D", generic_dsd_config },
-       { "CSC3551", "103C89C6", generic_dsd_config },
-       { "CSC3551", "103C8A28", generic_dsd_config },
-       { "CSC3551", "103C8A29", generic_dsd_config },
-       { "CSC3551", "103C8A2A", generic_dsd_config },
-       { "CSC3551", "103C8A2B", generic_dsd_config },
-       { "CSC3551", "103C8A2C", generic_dsd_config },
-       { "CSC3551", "103C8A2D", generic_dsd_config },
-       { "CSC3551", "103C8A2E", generic_dsd_config },
-       { "CSC3551", "103C8A30", generic_dsd_config },
-       { "CSC3551", "103C8A31", generic_dsd_config },
-       { "CSC3551", "103C8A6E", generic_dsd_config },
-       { "CSC3551", "103C8BB3", generic_dsd_config },
-       { "CSC3551", "103C8BB4", generic_dsd_config },
-       { "CSC3551", "103C8BDD", generic_dsd_config },
-       { "CSC3551", "103C8BDE", generic_dsd_config },
-       { "CSC3551", "103C8BDF", generic_dsd_config },
-       { "CSC3551", "103C8BE0", generic_dsd_config },
-       { "CSC3551", "103C8BE1", generic_dsd_config },
-       { "CSC3551", "103C8BE2", generic_dsd_config },
-       { "CSC3551", "103C8BE3", generic_dsd_config },
-       { "CSC3551", "103C8BE5", generic_dsd_config },
-       { "CSC3551", "103C8BE6", generic_dsd_config },
-       { "CSC3551", "103C8BE7", generic_dsd_config },
-       { "CSC3551", "103C8BE8", generic_dsd_config },
-       { "CSC3551", "103C8BE9", generic_dsd_config },
-       { "CSC3551", "103C8B3A", generic_dsd_config },
-       { "CSC3551", "103C8C15", generic_dsd_config },
-       { "CSC3551", "103C8C16", generic_dsd_config },
-       { "CSC3551", "103C8C17", generic_dsd_config },
-       { "CSC3551", "103C8C4D", generic_dsd_config },
-       { "CSC3551", "103C8C4E", generic_dsd_config },
-       { "CSC3551", "103C8C4F", generic_dsd_config },
-       { "CSC3551", "103C8C50", generic_dsd_config },
-       { "CSC3551", "103C8C51", generic_dsd_config },
-       { "CSC3551", "103C8C66", hp_i2c_int_2amp_dual_spkid },
-       { "CSC3551", "103C8C67", hp_i2c_int_2amp_dual_spkid },
-       { "CSC3551", "103C8C68", hp_i2c_int_2amp_dual_spkid },
-       { "CSC3551", "103C8C6A", hp_i2c_int_2amp_dual_spkid },
-       { "CSC3551", "103C8CDD", generic_dsd_config },
-       { "CSC3551", "103C8CDE", generic_dsd_config },
-       { "CSC3551", "104312AF", generic_dsd_config },
-       { "CSC3551", "10431433", generic_dsd_config },
-       { "CSC3551", "10431463", generic_dsd_config },
-       { "CSC3551", "10431473", generic_dsd_config },
-       { "CSC3551", "10431483", generic_dsd_config },
-       { "CSC3551", "10431493", generic_dsd_config },
-       { "CSC3551", "104314D3", generic_dsd_config },
-       { "CSC3551", "104314E3", generic_dsd_config },
-       { "CSC3551", "10431503", generic_dsd_config },
-       { "CSC3551", "10431533", generic_dsd_config },
-       { "CSC3551", "10431573", generic_dsd_config },
-       { "CSC3551", "10431663", generic_dsd_config },
-       { "CSC3551", "10431683", generic_dsd_config },
-       { "CSC3551", "104316A3", generic_dsd_config },
-       { "CSC3551", "104316D3", generic_dsd_config },
-       { "CSC3551", "104316F3", generic_dsd_config },
-       { "CSC3551", "104317F3", generic_dsd_config },
-       { "CSC3551", "10431863", generic_dsd_config },
-       { "CSC3551", "104318D3", generic_dsd_config },
-       { "CSC3551", "10431A63", missing_speaker_id_gpio2 },
-       { "CSC3551", "10431A83", generic_dsd_config },
-       { "CSC3551", "10431B93", generic_dsd_config },
-       { "CSC3551", "10431C9F", generic_dsd_config },
-       { "CSC3551", "10431CAF", generic_dsd_config },
-       { "CSC3551", "10431CCF", generic_dsd_config },
-       { "CSC3551", "10431CDF", generic_dsd_config },
-       { "CSC3551", "10431CEF", generic_dsd_config },
-       { "CSC3551", "10431D1F", generic_dsd_config },
-       { "CSC3551", "10431DA2", generic_dsd_config },
-       { "CSC3551", "10431E02", generic_dsd_config },
-       { "CSC3551", "10431E12", generic_dsd_config },
-       { "CSC3551", "10431EE2", generic_dsd_config },
-       { "CSC3551", "10431F12", generic_dsd_config },
-       { "CSC3551", "10431F1F", generic_dsd_config },
-       { "CSC3551", "10431F62", generic_dsd_config },
-       { "CSC3551", "10433A20", generic_dsd_config },
-       { "CSC3551", "10433A30", generic_dsd_config },
-       { "CSC3551", "10433A40", generic_dsd_config },
-       { "CSC3551", "10433A50", generic_dsd_config },
-       { "CSC3551", "10433A60", generic_dsd_config },
-       { "CSC3551", "17AA3865", generic_dsd_config },
-       { "CSC3551", "17AA3866", generic_dsd_config },
-       { "CSC3551", "17AA386E", generic_dsd_config },
-       { "CSC3551", "17AA386F", generic_dsd_config },
-       { "CSC3551", "17AA3877", generic_dsd_config },
-       { "CSC3551", "17AA3878", generic_dsd_config },
-       { "CSC3551", "17AA38A9", generic_dsd_config },
-       { "CSC3551", "17AA38AB", generic_dsd_config },
-       { "CSC3551", "17AA38B4", generic_dsd_config },
-       { "CSC3551", "17AA38B5", generic_dsd_config },
-       { "CSC3551", "17AA38B6", generic_dsd_config },
-       { "CSC3551", "17AA38B7", generic_dsd_config },
-       { "CSC3551", "17AA38C7", generic_dsd_config },
-       { "CSC3551", "17AA38C8", generic_dsd_config },
-       { "CSC3551", "17AA38F9", generic_dsd_config },
-       { "CSC3551", "17AA38FA", generic_dsd_config },
-       {}
-};
-
-int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
-                              const char *hid)
-{
-       const struct cs35l41_prop_model *model;
-
-       for (model = cs35l41_prop_model_table; model->hid; model++) {
-               if (!strcmp(model->hid, hid) &&
-                   (!model->ssid ||
-                    (cs35l41->acpi_subsystem_id &&
-                     !strcasecmp(model->ssid, cs35l41->acpi_subsystem_id))))
-                       return model->add_prop(cs35l41, physdev, id, hid);
-       }
-
-       return -ENOENT;
-}
diff --git a/sound/pci/hda/cs35l41_hda_property.h b/sound/pci/hda/cs35l41_hda_property.h
deleted file mode 100644 (file)
index fd83404..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0
- *
- * CS35L41 ALSA HDA Property driver
- *
- * Copyright 2023 Cirrus Logic, Inc.
- *
- * Author: Stefan Binding <sbinding@opensource.cirrus.com>
- */
-
-#ifndef CS35L41_HDA_PROP_H
-#define CS35L41_HDA_PROP_H
-
-#include <linux/device.h>
-#include "cs35l41_hda.h"
-
-int cs35l41_add_dsd_properties(struct cs35l41_hda *cs35l41, struct device *physdev, int id,
-                              const char *hid);
-#endif /* CS35L41_HDA_PROP_H */
diff --git a/sound/pci/hda/cs35l41_hda_spi.c b/sound/pci/hda/cs35l41_hda_spi.c
deleted file mode 100644 (file)
index 2acbaf8..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// CS35l41 HDA SPI driver
-//
-// Copyright 2021 Cirrus Logic, Inc.
-//
-// Author: Lucas Tanure <tanureal@opensource.cirrus.com>
-
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/spi/spi.h>
-
-#include "cs35l41_hda.h"
-
-static int cs35l41_hda_spi_probe(struct spi_device *spi)
-{
-       const char *device_name;
-
-       /*
-        * Compare against the device name so it works for SPI, normal ACPI
-        * and for ACPI by serial-multi-instantiate matching cases.
-        */
-       if (strstr(dev_name(&spi->dev), "CSC3551"))
-               device_name = "CSC3551";
-       else
-               return -ENODEV;
-
-       return cs35l41_hda_probe(&spi->dev, device_name, spi_get_chipselect(spi, 0), spi->irq,
-                                devm_regmap_init_spi(spi, &cs35l41_regmap_spi), SPI);
-}
-
-static void cs35l41_hda_spi_remove(struct spi_device *spi)
-{
-       cs35l41_hda_remove(&spi->dev);
-}
-
-static const struct spi_device_id cs35l41_hda_spi_id[] = {
-       { "cs35l41-hda", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(spi, cs35l41_hda_spi_id);
-
-static const struct acpi_device_id cs35l41_acpi_hda_match[] = {
-       { "CSC3551", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(acpi, cs35l41_acpi_hda_match);
-
-static struct spi_driver cs35l41_spi_driver = {
-       .driver = {
-               .name           = "cs35l41-hda",
-               .acpi_match_table = cs35l41_acpi_hda_match,
-               .pm             = &cs35l41_hda_pm_ops,
-       },
-       .id_table       = cs35l41_hda_spi_id,
-       .probe          = cs35l41_hda_spi_probe,
-       .remove         = cs35l41_hda_spi_remove,
-};
-module_spi_driver(cs35l41_spi_driver);
-
-MODULE_DESCRIPTION("HDA CS35L41 driver");
-MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L41");
-MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/cs35l56_hda.c b/sound/pci/hda/cs35l56_hda.c
deleted file mode 100644 (file)
index e8b4995..0000000
+++ /dev/null
@@ -1,1127 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-//
-// HDA audio driver for Cirrus Logic CS35L56 smart amp
-//
-// Copyright (C) 2023 Cirrus Logic, Inc. and
-//                    Cirrus Logic International Semiconductor Ltd.
-//
-
-#include <linux/acpi.h>
-#include <linux/debugfs.h>
-#include <linux/gpio/consumer.h>
-#include <linux/module.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <sound/cs-amp-lib.h>
-#include <sound/hda_codec.h>
-#include <sound/tlv.h>
-#include "cirrus_scodec.h"
-#include "cs35l56_hda.h"
-#include "hda_component.h"
-#include "hda_generic.h"
-
- /*
-  * The cs35l56_hda_dai_config[] reg sequence configures the device as
-  *  ASP1_BCLK_FREQ = 3.072 MHz
-  *  ASP1_RX_WIDTH = 32 cycles per slot, ASP1_TX_WIDTH = 32 cycles per slot, ASP1_FMT = I2S
-  *  ASP1_DOUT_HIZ_CONTROL = Hi-Z during unused timeslots
-  *  ASP1_RX_WL = 24 bits per sample
-  *  ASP1_TX_WL = 24 bits per sample
-  *  ASP1_RXn_EN 1..3 and ASP1_TXn_EN 1..4 disabled
-  *
-  * Override any Windows-specific mixer settings applied by the firmware.
-  */
-static const struct reg_sequence cs35l56_hda_dai_config[] = {
-       { CS35L56_ASP1_CONTROL1,        0x00000021 },
-       { CS35L56_ASP1_CONTROL2,        0x20200200 },
-       { CS35L56_ASP1_CONTROL3,        0x00000003 },
-       { CS35L56_ASP1_FRAME_CONTROL1,  0x03020100 },
-       { CS35L56_ASP1_FRAME_CONTROL5,  0x00020100 },
-       { CS35L56_ASP1_DATA_CONTROL5,   0x00000018 },
-       { CS35L56_ASP1_DATA_CONTROL1,   0x00000018 },
-       { CS35L56_ASP1_ENABLES1,        0x00000000 },
-       { CS35L56_ASP1TX1_INPUT,        0x00000018 },
-       { CS35L56_ASP1TX2_INPUT,        0x00000019 },
-       { CS35L56_ASP1TX3_INPUT,        0x00000020 },
-       { CS35L56_ASP1TX4_INPUT,        0x00000028 },
-
-};
-
-static void cs35l56_hda_wait_dsp_ready(struct cs35l56_hda *cs35l56)
-{
-       /* Wait for patching to complete */
-       flush_work(&cs35l56->dsp_work);
-}
-
-static void cs35l56_hda_play(struct cs35l56_hda *cs35l56)
-{
-       unsigned int val;
-       int ret;
-
-       cs35l56_hda_wait_dsp_ready(cs35l56);
-
-       pm_runtime_get_sync(cs35l56->base.dev);
-       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PLAY);
-       if (ret == 0) {
-               /* Wait for firmware to enter PS0 power state */
-               ret = regmap_read_poll_timeout(cs35l56->base.regmap,
-                                              cs35l56->base.fw_reg->transducer_actual_ps,
-                                              val, (val == CS35L56_PS0),
-                                              CS35L56_PS0_POLL_US,
-                                              CS35L56_PS0_TIMEOUT_US);
-               if (ret)
-                       dev_warn(cs35l56->base.dev, "PS0 wait failed: %d\n", ret);
-       }
-       regmap_set_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
-                       BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
-                       cs35l56->asp_tx_mask);
-       cs35l56->playing = true;
-}
-
-static void cs35l56_hda_pause(struct cs35l56_hda *cs35l56)
-{
-       cs35l56->playing = false;
-       cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_PAUSE);
-       regmap_clear_bits(cs35l56->base.regmap, CS35L56_ASP1_ENABLES1,
-                         BIT(CS35L56_ASP_RX1_EN_SHIFT) | BIT(CS35L56_ASP_RX2_EN_SHIFT) |
-                         BIT(CS35L56_ASP_TX1_EN_SHIFT) | BIT(CS35L56_ASP_TX2_EN_SHIFT) |
-                         BIT(CS35L56_ASP_TX3_EN_SHIFT) | BIT(CS35L56_ASP_TX4_EN_SHIFT));
-
-       pm_runtime_put_autosuspend(cs35l56->base.dev);
-}
-
-static void cs35l56_hda_playback_hook(struct device *dev, int action)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-
-       dev_dbg(cs35l56->base.dev, "%s()%d: action: %d\n", __func__, __LINE__, action);
-
-       switch (action) {
-       case HDA_GEN_PCM_ACT_PREPARE:
-               if (cs35l56->playing)
-                       break;
-
-               /* If we're suspended: flag that resume should start playback */
-               if (cs35l56->suspended) {
-                       cs35l56->playing = true;
-                       break;
-               }
-
-               cs35l56_hda_play(cs35l56);
-               break;
-       case HDA_GEN_PCM_ACT_CLEANUP:
-               if (!cs35l56->playing)
-                       break;
-
-               cs35l56_hda_pause(cs35l56);
-               break;
-       default:
-               break;
-       }
-}
-
-static int cs35l56_hda_runtime_suspend(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-
-       if (cs35l56->cs_dsp.booted)
-               cs_dsp_stop(&cs35l56->cs_dsp);
-
-       return cs35l56_runtime_suspend_common(&cs35l56->base);
-}
-
-static int cs35l56_hda_runtime_resume(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-       int ret;
-
-       ret = cs35l56_runtime_resume_common(&cs35l56->base, false);
-       if (ret < 0)
-               return ret;
-
-       if (cs35l56->cs_dsp.booted) {
-               ret = cs_dsp_run(&cs35l56->cs_dsp);
-               if (ret) {
-                       dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
-                       goto err;
-               }
-       }
-
-       return 0;
-
-err:
-       cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_ALLOW_AUTO_HIBERNATE);
-       regmap_write(cs35l56->base.regmap, CS35L56_DSP_VIRTUAL1_MBOX_1,
-                    CS35L56_MBOX_CMD_HIBERNATE_NOW);
-
-       regcache_cache_only(cs35l56->base.regmap, true);
-
-       return ret;
-}
-
-static int cs35l56_hda_mixer_info(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = CS35L56_NUM_INPUT_SRC;
-       if (uinfo->value.enumerated.item >= CS35L56_NUM_INPUT_SRC)
-               uinfo->value.enumerated.item = CS35L56_NUM_INPUT_SRC - 1;
-       strscpy(uinfo->value.enumerated.name, cs35l56_tx_input_texts[uinfo->value.enumerated.item],
-               sizeof(uinfo->value.enumerated.name));
-
-       return 0;
-}
-
-static int cs35l56_hda_mixer_get(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
-       unsigned int reg_val;
-       int i;
-
-       cs35l56_hda_wait_dsp_ready(cs35l56);
-
-       regmap_read(cs35l56->base.regmap, kcontrol->private_value, &reg_val);
-       reg_val &= CS35L56_ASP_TXn_SRC_MASK;
-
-       for (i = 0; i < CS35L56_NUM_INPUT_SRC; ++i) {
-               if (cs35l56_tx_input_values[i] == reg_val) {
-                       ucontrol->value.enumerated.item[0] = i;
-                       break;
-               }
-       }
-
-       return 0;
-}
-
-static int cs35l56_hda_mixer_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
-       unsigned int item = ucontrol->value.enumerated.item[0];
-       bool changed;
-
-       if (item >= CS35L56_NUM_INPUT_SRC)
-               return -EINVAL;
-
-       cs35l56_hda_wait_dsp_ready(cs35l56);
-
-       regmap_update_bits_check(cs35l56->base.regmap, kcontrol->private_value,
-                                CS35L56_INPUT_MASK, cs35l56_tx_input_values[item],
-                                &changed);
-
-       return changed;
-}
-
-static int cs35l56_hda_posture_info(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = CS35L56_MAIN_POSTURE_MIN;
-       uinfo->value.integer.max = CS35L56_MAIN_POSTURE_MAX;
-       return 0;
-}
-
-static int cs35l56_hda_posture_get(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
-       unsigned int pos;
-       int ret;
-
-       cs35l56_hda_wait_dsp_ready(cs35l56);
-
-       ret = regmap_read(cs35l56->base.regmap,
-                         cs35l56->base.fw_reg->posture_number, &pos);
-       if (ret)
-               return ret;
-
-       ucontrol->value.integer.value[0] = pos;
-
-       return 0;
-}
-
-static int cs35l56_hda_posture_put(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
-       unsigned long pos = ucontrol->value.integer.value[0];
-       bool changed;
-       int ret;
-
-       if ((pos < CS35L56_MAIN_POSTURE_MIN) ||
-           (pos > CS35L56_MAIN_POSTURE_MAX))
-               return -EINVAL;
-
-       cs35l56_hda_wait_dsp_ready(cs35l56);
-
-       ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->posture_number,
-                                      CS35L56_MAIN_POSTURE_MASK, pos, &changed);
-       if (ret)
-               return ret;
-
-       return changed;
-}
-
-static const struct {
-       const char *name;
-       unsigned int reg;
-} cs35l56_hda_mixer_controls[] = {
-       { "ASP1 TX1 Source", CS35L56_ASP1TX1_INPUT },
-       { "ASP1 TX2 Source", CS35L56_ASP1TX2_INPUT },
-       { "ASP1 TX3 Source", CS35L56_ASP1TX3_INPUT },
-       { "ASP1 TX4 Source", CS35L56_ASP1TX4_INPUT },
-};
-
-static const DECLARE_TLV_DB_SCALE(cs35l56_hda_vol_tlv, -10000, 25, 0);
-
-static int cs35l56_hda_vol_info(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.step = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
-                                  CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
-
-       return 0;
-}
-
-static int cs35l56_hda_vol_get(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
-       unsigned int raw_vol;
-       int vol;
-       int ret;
-
-       cs35l56_hda_wait_dsp_ready(cs35l56);
-
-       ret = regmap_read(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume, &raw_vol);
-
-       if (ret)
-               return ret;
-
-       vol = (s16)(raw_vol & 0xFFFF);
-       vol >>= CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
-
-       if (vol & BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT))
-               vol |= ~((int)(BIT(CS35L56_MAIN_RENDER_USER_VOLUME_SIGNBIT) - 1));
-
-       ucontrol->value.integer.value[0] = vol - CS35L56_MAIN_RENDER_USER_VOLUME_MIN;
-
-       return 0;
-}
-
-static int cs35l56_hda_vol_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct cs35l56_hda *cs35l56 = snd_kcontrol_chip(kcontrol);
-       long vol = ucontrol->value.integer.value[0];
-       unsigned int raw_vol;
-       bool changed;
-       int ret;
-
-       if ((vol < 0) || (vol > (CS35L56_MAIN_RENDER_USER_VOLUME_MAX -
-                                CS35L56_MAIN_RENDER_USER_VOLUME_MIN)))
-               return -EINVAL;
-
-       raw_vol = (vol + CS35L56_MAIN_RENDER_USER_VOLUME_MIN) <<
-                 CS35L56_MAIN_RENDER_USER_VOLUME_SHIFT;
-
-       cs35l56_hda_wait_dsp_ready(cs35l56);
-
-       ret = regmap_update_bits_check(cs35l56->base.regmap, cs35l56->base.fw_reg->user_volume,
-                                      CS35L56_MAIN_RENDER_USER_VOLUME_MASK, raw_vol, &changed);
-       if (ret)
-               return ret;
-
-       return changed;
-}
-
-static void cs35l56_hda_create_controls(struct cs35l56_hda *cs35l56)
-{
-       struct snd_kcontrol_new ctl_template = {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-               .info = cs35l56_hda_posture_info,
-               .get = cs35l56_hda_posture_get,
-               .put = cs35l56_hda_posture_put,
-       };
-       char name[64];
-       int i;
-
-       snprintf(name, sizeof(name), "%s Posture Number", cs35l56->amp_name);
-       ctl_template.name = name;
-       cs35l56->posture_ctl = snd_ctl_new1(&ctl_template, cs35l56);
-       if (snd_ctl_add(cs35l56->codec->card, cs35l56->posture_ctl))
-               dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
-
-       /* Mixer controls */
-       ctl_template.info = cs35l56_hda_mixer_info;
-       ctl_template.get = cs35l56_hda_mixer_get;
-       ctl_template.put = cs35l56_hda_mixer_put;
-
-       BUILD_BUG_ON(ARRAY_SIZE(cs35l56->mixer_ctl) != ARRAY_SIZE(cs35l56_hda_mixer_controls));
-
-       for (i = 0; i < ARRAY_SIZE(cs35l56_hda_mixer_controls); ++i) {
-               snprintf(name, sizeof(name), "%s %s", cs35l56->amp_name,
-                        cs35l56_hda_mixer_controls[i].name);
-               ctl_template.private_value = cs35l56_hda_mixer_controls[i].reg;
-               cs35l56->mixer_ctl[i] = snd_ctl_new1(&ctl_template, cs35l56);
-               if (snd_ctl_add(cs35l56->codec->card, cs35l56->mixer_ctl[i])) {
-                       dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n",
-                               ctl_template.name);
-               }
-       }
-
-       ctl_template.info = cs35l56_hda_vol_info;
-       ctl_template.get = cs35l56_hda_vol_get;
-       ctl_template.put = cs35l56_hda_vol_put;
-       ctl_template.access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ);
-       ctl_template.tlv.p = cs35l56_hda_vol_tlv;
-       snprintf(name, sizeof(name), "%s Speaker Playback Volume", cs35l56->amp_name);
-       ctl_template.name = name;
-       cs35l56->volume_ctl = snd_ctl_new1(&ctl_template, cs35l56);
-       if (snd_ctl_add(cs35l56->codec->card, cs35l56->volume_ctl))
-               dev_err(cs35l56->base.dev, "Failed to add KControl: %s\n", ctl_template.name);
-}
-
-static void cs35l56_hda_remove_controls(struct cs35l56_hda *cs35l56)
-{
-       int i;
-
-       for (i = ARRAY_SIZE(cs35l56->mixer_ctl) - 1; i >= 0; i--)
-               snd_ctl_remove(cs35l56->codec->card, cs35l56->mixer_ctl[i]);
-
-       snd_ctl_remove(cs35l56->codec->card, cs35l56->posture_ctl);
-       snd_ctl_remove(cs35l56->codec->card, cs35l56->volume_ctl);
-}
-
-static const struct cs_dsp_client_ops cs35l56_hda_client_ops = {
-       /* cs_dsp requires the client to provide this even if it is empty */
-};
-
-static int cs35l56_hda_request_firmware_file(struct cs35l56_hda *cs35l56,
-                                            const struct firmware **firmware, char **filename,
-                                            const char *base_name, const char *system_name,
-                                            const char *amp_name,
-                                            const char *filetype)
-{
-       char *s, c;
-       int ret = 0;
-
-       if (system_name && amp_name)
-               *filename = kasprintf(GFP_KERNEL, "%s-%s-%s.%s", base_name,
-                                     system_name, amp_name, filetype);
-       else if (system_name)
-               *filename = kasprintf(GFP_KERNEL, "%s-%s.%s", base_name,
-                                     system_name, filetype);
-       else
-               *filename = kasprintf(GFP_KERNEL, "%s.%s", base_name, filetype);
-
-       if (!*filename)
-               return -ENOMEM;
-
-       /*
-        * Make sure that filename is lower-case and any non alpha-numeric
-        * characters except full stop and forward slash are replaced with
-        * hyphens.
-        */
-       s = *filename;
-       while (*s) {
-               c = *s;
-               if (isalnum(c))
-                       *s = tolower(c);
-               else if (c != '.' && c != '/')
-                       *s = '-';
-               s++;
-       }
-
-       ret = firmware_request_nowarn(firmware, *filename, cs35l56->base.dev);
-       if (ret) {
-               dev_dbg(cs35l56->base.dev, "Failed to request '%s'\n", *filename);
-               kfree(*filename);
-               *filename = NULL;
-               return ret;
-       }
-
-       dev_dbg(cs35l56->base.dev, "Found '%s'\n", *filename);
-
-       return 0;
-}
-
-static void cs35l56_hda_request_firmware_files(struct cs35l56_hda *cs35l56,
-                                              unsigned int preloaded_fw_ver,
-                                              const struct firmware **wmfw_firmware,
-                                              char **wmfw_filename,
-                                              const struct firmware **coeff_firmware,
-                                              char **coeff_filename)
-{
-       const char *system_name = cs35l56->system_name;
-       const char *amp_name = cs35l56->amp_name;
-       char base_name[37];
-       int ret;
-
-       if (preloaded_fw_ver) {
-               snprintf(base_name, sizeof(base_name),
-                        "cirrus/cs35l%02x-%02x%s-%06x-dsp1-misc",
-                        cs35l56->base.type,
-                        cs35l56->base.rev,
-                        cs35l56->base.secured ? "-s" : "",
-                        preloaded_fw_ver & 0xffffff);
-       } else {
-               snprintf(base_name, sizeof(base_name),
-                        "cirrus/cs35l%02x-%02x%s-dsp1-misc",
-                        cs35l56->base.type,
-                        cs35l56->base.rev,
-                        cs35l56->base.secured ? "-s" : "");
-       }
-
-       if (system_name && amp_name) {
-               if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
-                                                      base_name, system_name, amp_name, "wmfw")) {
-                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                         base_name, system_name, amp_name, "bin");
-                       return;
-               }
-       }
-
-       if (system_name) {
-               if (!cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
-                                                      base_name, system_name, NULL, "wmfw")) {
-                       if (amp_name)
-                               cs35l56_hda_request_firmware_file(cs35l56,
-                                                                 coeff_firmware, coeff_filename,
-                                                                 base_name, system_name,
-                                                                 amp_name, "bin");
-                       if (!*coeff_firmware)
-                               cs35l56_hda_request_firmware_file(cs35l56,
-                                                                 coeff_firmware, coeff_filename,
-                                                                 base_name, system_name,
-                                                                 NULL, "bin");
-                       return;
-               }
-
-               /*
-                * Check for system-specific bin files without wmfw before
-                * falling back to generic firmware
-                */
-               if (amp_name)
-                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                         base_name, system_name, amp_name, "bin");
-               if (!*coeff_firmware)
-                       cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                         base_name, system_name, NULL, "bin");
-
-               if (*coeff_firmware)
-                       return;
-       }
-
-       ret = cs35l56_hda_request_firmware_file(cs35l56, wmfw_firmware, wmfw_filename,
-                                               base_name, NULL, NULL, "wmfw");
-       if (!ret) {
-               cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                 base_name, NULL, NULL, "bin");
-               return;
-       }
-
-       if (!*coeff_firmware)
-               cs35l56_hda_request_firmware_file(cs35l56, coeff_firmware, coeff_filename,
-                                                 base_name, NULL, NULL, "bin");
-}
-
-static void cs35l56_hda_release_firmware_files(const struct firmware *wmfw_firmware,
-                                              char *wmfw_filename,
-                                              const struct firmware *coeff_firmware,
-                                              char *coeff_filename)
-{
-       release_firmware(wmfw_firmware);
-       kfree(wmfw_filename);
-
-       release_firmware(coeff_firmware);
-       kfree(coeff_filename);
-}
-
-static void cs35l56_hda_apply_calibration(struct cs35l56_hda *cs35l56)
-{
-       int ret;
-
-       if (!cs35l56->base.cal_data_valid || cs35l56->base.secured)
-               return;
-
-       ret = cs_amp_write_cal_coeffs(&cs35l56->cs_dsp,
-                                     &cs35l56_calibration_controls,
-                                     &cs35l56->base.cal_data);
-       if (ret < 0)
-               dev_warn(cs35l56->base.dev, "Failed to write calibration: %d\n", ret);
-       else
-               dev_info(cs35l56->base.dev, "Calibration applied\n");
-}
-
-static void cs35l56_hda_fw_load(struct cs35l56_hda *cs35l56)
-{
-       const struct firmware *coeff_firmware = NULL;
-       const struct firmware *wmfw_firmware = NULL;
-       char *coeff_filename = NULL;
-       char *wmfw_filename = NULL;
-       unsigned int preloaded_fw_ver;
-       bool firmware_missing;
-       int ret;
-
-       /*
-        * Prepare for a new DSP power-up. If the DSP has had firmware
-        * downloaded previously then it needs to be powered down so that it
-        * can be updated.
-        */
-       if (cs35l56->base.fw_patched)
-               cs_dsp_power_down(&cs35l56->cs_dsp);
-
-       cs35l56->base.fw_patched = false;
-
-       ret = pm_runtime_resume_and_get(cs35l56->base.dev);
-       if (ret < 0) {
-               dev_err(cs35l56->base.dev, "Failed to resume and get %d\n", ret);
-               return;
-       }
-
-       /*
-        * The firmware can only be upgraded if it is currently running
-        * from the built-in ROM. If not, the wmfw/bin must be for the
-        * version of firmware that is running on the chip.
-        */
-       ret = cs35l56_read_prot_status(&cs35l56->base, &firmware_missing, &preloaded_fw_ver);
-       if (ret)
-               goto err_pm_put;
-
-       if (firmware_missing)
-               preloaded_fw_ver = 0;
-
-       cs35l56_hda_request_firmware_files(cs35l56, preloaded_fw_ver,
-                                          &wmfw_firmware, &wmfw_filename,
-                                          &coeff_firmware, &coeff_filename);
-
-       /*
-        * If the BIOS didn't patch the firmware a bin file is mandatory to
-        * enable the ASP·
-        */
-       if (!coeff_firmware && firmware_missing) {
-               dev_err(cs35l56->base.dev, ".bin file required but not found\n");
-               goto err_fw_release;
-       }
-
-       mutex_lock(&cs35l56->base.irq_lock);
-
-       /*
-        * If the firmware hasn't been patched it must be shutdown before
-        * doing a full patch and reset afterwards. If it is already
-        * running a patched version the firmware files only contain
-        * tunings and we can use the lower cost reinit sequence instead.
-        */
-       if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
-               ret = cs35l56_firmware_shutdown(&cs35l56->base);
-               if (ret)
-                       goto err;
-       }
-
-       ret = cs_dsp_power_up(&cs35l56->cs_dsp, wmfw_firmware, wmfw_filename,
-                             coeff_firmware, coeff_filename, "misc");
-       if (ret) {
-               dev_dbg(cs35l56->base.dev, "%s: cs_dsp_power_up ret %d\n", __func__, ret);
-               goto err;
-       }
-
-       if (wmfw_filename)
-               dev_dbg(cs35l56->base.dev, "Loaded WMFW Firmware: %s\n", wmfw_filename);
-
-       if (coeff_filename)
-               dev_dbg(cs35l56->base.dev, "Loaded Coefficients: %s\n", coeff_filename);
-
-       /* If we downloaded firmware, reset the device and wait for it to boot */
-       if (firmware_missing && (wmfw_firmware || coeff_firmware)) {
-               cs35l56_system_reset(&cs35l56->base, false);
-               regcache_mark_dirty(cs35l56->base.regmap);
-               ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
-               if (ret)
-                       goto err_powered_up;
-
-               regcache_cache_only(cs35l56->base.regmap, false);
-       }
-
-       /* Disable auto-hibernate so that runtime_pm has control */
-       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
-       if (ret)
-               goto err_powered_up;
-
-       regcache_sync(cs35l56->base.regmap);
-
-       regmap_clear_bits(cs35l56->base.regmap,
-                         cs35l56->base.fw_reg->prot_sts,
-                         CS35L56_FIRMWARE_MISSING);
-       cs35l56->base.fw_patched = true;
-
-       ret = cs_dsp_run(&cs35l56->cs_dsp);
-       if (ret)
-               dev_dbg(cs35l56->base.dev, "%s: cs_dsp_run ret %d\n", __func__, ret);
-
-       cs35l56_hda_apply_calibration(cs35l56);
-       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_AUDIO_REINIT);
-       if (ret)
-               cs_dsp_stop(&cs35l56->cs_dsp);
-
-       cs35l56_log_tuning(&cs35l56->base, &cs35l56->cs_dsp);
-
-err_powered_up:
-       if (!cs35l56->base.fw_patched)
-               cs_dsp_power_down(&cs35l56->cs_dsp);
-err:
-       mutex_unlock(&cs35l56->base.irq_lock);
-err_fw_release:
-       cs35l56_hda_release_firmware_files(wmfw_firmware, wmfw_filename,
-                                          coeff_firmware, coeff_filename);
-err_pm_put:
-       pm_runtime_put(cs35l56->base.dev);
-}
-
-static void cs35l56_hda_dsp_work(struct work_struct *work)
-{
-       struct cs35l56_hda *cs35l56 = container_of(work, struct cs35l56_hda, dsp_work);
-
-       cs35l56_hda_fw_load(cs35l56);
-}
-
-static int cs35l56_hda_bind(struct device *dev, struct device *master, void *master_data)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-       struct hda_component_parent *parent = master_data;
-       struct hda_component *comp;
-
-       comp = hda_component_from_index(parent, cs35l56->index);
-       if (!comp)
-               return -EINVAL;
-
-       if (comp->dev)
-               return -EBUSY;
-
-       comp->dev = dev;
-       cs35l56->codec = parent->codec;
-       strscpy(comp->name, dev_name(dev), sizeof(comp->name));
-       comp->playback_hook = cs35l56_hda_playback_hook;
-
-       queue_work(system_long_wq, &cs35l56->dsp_work);
-
-       cs35l56_hda_create_controls(cs35l56);
-
-#if IS_ENABLED(CONFIG_SND_DEBUG)
-       cs35l56->debugfs_root = debugfs_create_dir(dev_name(cs35l56->base.dev), sound_debugfs_root);
-       cs_dsp_init_debugfs(&cs35l56->cs_dsp, cs35l56->debugfs_root);
-#endif
-
-       dev_dbg(cs35l56->base.dev, "Bound\n");
-
-       return 0;
-}
-
-static void cs35l56_hda_unbind(struct device *dev, struct device *master, void *master_data)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-       struct hda_component_parent *parent = master_data;
-       struct hda_component *comp;
-
-       cancel_work_sync(&cs35l56->dsp_work);
-
-       cs35l56_hda_remove_controls(cs35l56);
-
-#if IS_ENABLED(CONFIG_SND_DEBUG)
-       cs_dsp_cleanup_debugfs(&cs35l56->cs_dsp);
-       debugfs_remove_recursive(cs35l56->debugfs_root);
-#endif
-
-       if (cs35l56->base.fw_patched)
-               cs_dsp_power_down(&cs35l56->cs_dsp);
-
-       comp = hda_component_from_index(parent, cs35l56->index);
-       if (comp && (comp->dev == dev))
-               memset(comp, 0, sizeof(*comp));
-
-       cs35l56->codec = NULL;
-
-       dev_dbg(cs35l56->base.dev, "Unbound\n");
-}
-
-static const struct component_ops cs35l56_hda_comp_ops = {
-       .bind = cs35l56_hda_bind,
-       .unbind = cs35l56_hda_unbind,
-};
-
-static int cs35l56_hda_system_suspend(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-
-       cs35l56_hda_wait_dsp_ready(cs35l56);
-
-       if (cs35l56->playing)
-               cs35l56_hda_pause(cs35l56);
-
-       cs35l56->suspended = true;
-
-       /*
-        * The interrupt line is normally shared, but after we start suspending
-        * we can't check if our device is the source of an interrupt, and can't
-        * clear it. Prevent this race by temporarily disabling the parent irq
-        * until we reach _no_irq.
-        */
-       if (cs35l56->base.irq)
-               disable_irq(cs35l56->base.irq);
-
-       return pm_runtime_force_suspend(dev);
-}
-
-static int cs35l56_hda_system_suspend_late(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-
-       /*
-        * RESET is usually shared by all amps so it must not be asserted until
-        * all driver instances have done their suspend() stage.
-        */
-       if (cs35l56->base.reset_gpio) {
-               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
-               cs35l56_wait_min_reset_pulse();
-       }
-
-       return 0;
-}
-
-static int cs35l56_hda_system_suspend_no_irq(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-
-       /* Handlers are now disabled so the parent IRQ can safely be re-enabled. */
-       if (cs35l56->base.irq)
-               enable_irq(cs35l56->base.irq);
-
-       return 0;
-}
-
-static int cs35l56_hda_system_resume_no_irq(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-
-       /*
-        * WAKE interrupts unmask if the CS35L56 hibernates, which can cause
-        * spurious interrupts, and the interrupt line is normally shared.
-        * We can't check if our device is the source of an interrupt, and can't
-        * clear it, until it has fully resumed. Prevent this race by temporarily
-        * disabling the parent irq until we complete resume().
-        */
-       if (cs35l56->base.irq)
-               disable_irq(cs35l56->base.irq);
-
-       return 0;
-}
-
-static int cs35l56_hda_system_resume_early(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-
-       /* Ensure a spec-compliant RESET pulse. */
-       if (cs35l56->base.reset_gpio) {
-               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
-               cs35l56_wait_min_reset_pulse();
-
-               /* Release shared RESET before drivers start resume(). */
-               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
-               cs35l56_wait_control_port_ready();
-       }
-
-       return 0;
-}
-
-static int cs35l56_hda_system_resume(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-       int ret;
-
-       /* Undo pm_runtime_force_suspend() before re-enabling the irq */
-       ret = pm_runtime_force_resume(dev);
-       if (cs35l56->base.irq)
-               enable_irq(cs35l56->base.irq);
-
-       if (ret)
-               return ret;
-
-       cs35l56->suspended = false;
-
-       if (!cs35l56->codec)
-               return 0;
-
-       ret = cs35l56_is_fw_reload_needed(&cs35l56->base);
-       dev_dbg(cs35l56->base.dev, "fw_reload_needed: %d\n", ret);
-       if (ret > 0)
-               queue_work(system_long_wq, &cs35l56->dsp_work);
-
-       if (cs35l56->playing)
-               cs35l56_hda_play(cs35l56);
-
-       return 0;
-}
-
-static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)
-{
-       u32 values[HDA_MAX_COMPONENTS];
-       char hid_string[8];
-       struct acpi_device *adev;
-       const char *property, *sub;
-       size_t nval;
-       int i, ret;
-
-       /*
-        * ACPI_COMPANION isn't available when this driver was instantiated by
-        * the serial-multi-instantiate driver, so lookup the node by HID
-        */
-       if (!ACPI_COMPANION(cs35l56->base.dev)) {
-               snprintf(hid_string, sizeof(hid_string), "CSC%04X", hid);
-               adev = acpi_dev_get_first_match_dev(hid_string, NULL, -1);
-               if (!adev) {
-                       dev_err(cs35l56->base.dev, "Failed to find an ACPI device for %s\n",
-                               dev_name(cs35l56->base.dev));
-                       return -ENODEV;
-               }
-               ACPI_COMPANION_SET(cs35l56->base.dev, adev);
-       }
-
-       property = "cirrus,dev-index";
-       ret = device_property_count_u32(cs35l56->base.dev, property);
-       if (ret <= 0)
-               goto err;
-
-       if (ret > ARRAY_SIZE(values)) {
-               ret = -EINVAL;
-               goto err;
-       }
-       nval = ret;
-
-       ret = device_property_read_u32_array(cs35l56->base.dev, property, values, nval);
-       if (ret)
-               goto err;
-
-       cs35l56->index = -1;
-       for (i = 0; i < nval; i++) {
-               if (values[i] == id) {
-                       cs35l56->index = i;
-                       break;
-               }
-       }
-       /*
-        * It's not an error for the ID to be missing: for I2C there can be
-        * an alias address that is not a real device. So reject silently.
-        */
-       if (cs35l56->index == -1) {
-               dev_dbg(cs35l56->base.dev, "No index found in %s\n", property);
-               ret = -ENODEV;
-               goto err;
-       }
-
-       sub = acpi_get_subsystem_id(ACPI_HANDLE(cs35l56->base.dev));
-
-       if (IS_ERR(sub)) {
-               dev_info(cs35l56->base.dev,
-                        "Read ACPI _SUB failed(%ld): fallback to generic firmware\n",
-                        PTR_ERR(sub));
-       } else {
-               ret = cirrus_scodec_get_speaker_id(cs35l56->base.dev, cs35l56->index, nval, -1);
-               if (ret == -ENOENT) {
-                       cs35l56->system_name = sub;
-               } else if (ret >= 0) {
-                       cs35l56->system_name = kasprintf(GFP_KERNEL, "%s-spkid%d", sub, ret);
-                       kfree(sub);
-                       if (!cs35l56->system_name)
-                               return -ENOMEM;
-               } else {
-                       return ret;
-               }
-       }
-
-       cs35l56->base.reset_gpio = devm_gpiod_get_index_optional(cs35l56->base.dev,
-                                                                "reset",
-                                                                cs35l56->index,
-                                                                GPIOD_OUT_LOW);
-       if (IS_ERR(cs35l56->base.reset_gpio)) {
-               ret = PTR_ERR(cs35l56->base.reset_gpio);
-
-               /*
-                * If RESET is shared the first amp to probe will grab the reset
-                * line and reset all the amps
-                */
-               if (ret != -EBUSY)
-                       return dev_err_probe(cs35l56->base.dev, ret, "Failed to get reset GPIO\n");
-
-               dev_info(cs35l56->base.dev, "Reset GPIO busy, assume shared reset\n");
-               cs35l56->base.reset_gpio = NULL;
-       }
-
-       return 0;
-
-err:
-       if (ret != -ENODEV)
-               dev_err(cs35l56->base.dev, "Failed property %s: %d\n", property, ret);
-
-       return ret;
-}
-
-int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id)
-{
-       int ret;
-
-       mutex_init(&cs35l56->base.irq_lock);
-       dev_set_drvdata(cs35l56->base.dev, cs35l56);
-
-       INIT_WORK(&cs35l56->dsp_work, cs35l56_hda_dsp_work);
-
-       ret = cs35l56_hda_read_acpi(cs35l56, hid, id);
-       if (ret)
-               goto err;
-
-       cs35l56->amp_name = devm_kasprintf(cs35l56->base.dev, GFP_KERNEL, "AMP%d",
-                                          cs35l56->index + 1);
-       if (!cs35l56->amp_name) {
-               ret = -ENOMEM;
-               goto err;
-       }
-
-       cs35l56->base.cal_index = -1;
-
-       cs35l56_init_cs_dsp(&cs35l56->base, &cs35l56->cs_dsp);
-       cs35l56->cs_dsp.client_ops = &cs35l56_hda_client_ops;
-
-       if (cs35l56->base.reset_gpio) {
-               dev_dbg(cs35l56->base.dev, "Hard reset\n");
-
-               /*
-                * The GPIOD_OUT_LOW to *_gpiod_get_*() will be ignored if the
-                * ACPI defines a different default state. So explicitly set low.
-                */
-               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
-               cs35l56_wait_min_reset_pulse();
-               gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 1);
-       }
-
-       ret = cs35l56_hw_init(&cs35l56->base);
-       if (ret < 0)
-               goto err;
-
-       /* Reset the device and wait for it to boot */
-       cs35l56_system_reset(&cs35l56->base, false);
-       ret = cs35l56_wait_for_firmware_boot(&cs35l56->base);
-       if (ret)
-               goto err;
-
-       regcache_cache_only(cs35l56->base.regmap, false);
-
-       ret = cs35l56_set_patch(&cs35l56->base);
-       if (ret)
-               goto err;
-
-       regcache_mark_dirty(cs35l56->base.regmap);
-       regcache_sync(cs35l56->base.regmap);
-
-       /* Disable auto-hibernate so that runtime_pm has control */
-       ret = cs35l56_mbox_send(&cs35l56->base, CS35L56_MBOX_CMD_PREVENT_AUTO_HIBERNATE);
-       if (ret)
-               goto err;
-
-       ret = cs35l56_get_calibration(&cs35l56->base);
-       if (ret)
-               goto err;
-
-       ret = cs_dsp_halo_init(&cs35l56->cs_dsp);
-       if (ret) {
-               dev_err_probe(cs35l56->base.dev, ret, "cs_dsp_halo_init failed\n");
-               goto err;
-       }
-
-       dev_info(cs35l56->base.dev, "DSP system name: '%s', amp name: '%s'\n",
-                cs35l56->system_name, cs35l56->amp_name);
-
-       regmap_multi_reg_write(cs35l56->base.regmap, cs35l56_hda_dai_config,
-                              ARRAY_SIZE(cs35l56_hda_dai_config));
-
-       /*
-        * By default only enable one ASP1TXn, where n=amplifier index,
-        * This prevents multiple amps trying to drive the same slot.
-        */
-       cs35l56->asp_tx_mask = BIT(cs35l56->index);
-
-       pm_runtime_set_autosuspend_delay(cs35l56->base.dev, 3000);
-       pm_runtime_use_autosuspend(cs35l56->base.dev);
-       pm_runtime_set_active(cs35l56->base.dev);
-       pm_runtime_mark_last_busy(cs35l56->base.dev);
-       pm_runtime_enable(cs35l56->base.dev);
-
-       cs35l56->base.init_done = true;
-
-       ret = component_add(cs35l56->base.dev, &cs35l56_hda_comp_ops);
-       if (ret) {
-               dev_err(cs35l56->base.dev, "Register component failed: %d\n", ret);
-               goto pm_err;
-       }
-
-       return 0;
-
-pm_err:
-       pm_runtime_disable(cs35l56->base.dev);
-       cs_dsp_remove(&cs35l56->cs_dsp);
-err:
-       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_hda_common_probe, "SND_HDA_SCODEC_CS35L56");
-
-void cs35l56_hda_remove(struct device *dev)
-{
-       struct cs35l56_hda *cs35l56 = dev_get_drvdata(dev);
-
-       component_del(cs35l56->base.dev, &cs35l56_hda_comp_ops);
-
-       pm_runtime_dont_use_autosuspend(cs35l56->base.dev);
-       pm_runtime_get_sync(cs35l56->base.dev);
-       pm_runtime_disable(cs35l56->base.dev);
-
-       cs_dsp_remove(&cs35l56->cs_dsp);
-
-       kfree(cs35l56->system_name);
-       pm_runtime_put_noidle(cs35l56->base.dev);
-
-       gpiod_set_value_cansleep(cs35l56->base.reset_gpio, 0);
-}
-EXPORT_SYMBOL_NS_GPL(cs35l56_hda_remove, "SND_HDA_SCODEC_CS35L56");
-
-const struct dev_pm_ops cs35l56_hda_pm_ops = {
-       RUNTIME_PM_OPS(cs35l56_hda_runtime_suspend, cs35l56_hda_runtime_resume, NULL)
-       SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend, cs35l56_hda_system_resume)
-       LATE_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_late,
-                                cs35l56_hda_system_resume_early)
-       NOIRQ_SYSTEM_SLEEP_PM_OPS(cs35l56_hda_system_suspend_no_irq,
-                                 cs35l56_hda_system_resume_no_irq)
-};
-EXPORT_SYMBOL_NS_GPL(cs35l56_hda_pm_ops, "SND_HDA_SCODEC_CS35L56");
-
-MODULE_DESCRIPTION("CS35L56 HDA Driver");
-MODULE_IMPORT_NS("FW_CS_DSP");
-MODULE_IMPORT_NS("SND_HDA_CIRRUS_SCODEC");
-MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
-MODULE_IMPORT_NS("SND_SOC_CS_AMP_LIB");
-MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
-MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("cirrus/cs35l54-*.wmfw");
-MODULE_FIRMWARE("cirrus/cs35l54-*.bin");
-MODULE_FIRMWARE("cirrus/cs35l56-*.wmfw");
-MODULE_FIRMWARE("cirrus/cs35l56-*.bin");
diff --git a/sound/pci/hda/cs35l56_hda.h b/sound/pci/hda/cs35l56_hda.h
deleted file mode 100644 (file)
index 38d94fb..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only
- *
- * HDA audio driver for Cirrus Logic CS35L56 smart amp
- *
- * Copyright (C) 2023 Cirrus Logic, Inc. and
- *                    Cirrus Logic International Semiconductor Ltd.
- */
-
-#ifndef __CS35L56_HDA_H__
-#define __CS35L56_HDA_H__
-
-#include <linux/device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/firmware/cirrus/cs_dsp.h>
-#include <linux/firmware/cirrus/wmfw.h>
-#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
-#include <sound/cs35l56.h>
-
-struct dentry;
-
-struct cs35l56_hda {
-       struct cs35l56_base base;
-       struct hda_codec *codec;
-       struct work_struct dsp_work;
-
-       int index;
-       const char *system_name;
-       const char *amp_name;
-
-       struct cs_dsp cs_dsp;
-       bool playing;
-       bool suspended;
-       u8 asp_tx_mask;
-
-       struct snd_kcontrol *posture_ctl;
-       struct snd_kcontrol *volume_ctl;
-       struct snd_kcontrol *mixer_ctl[4];
-
-#if IS_ENABLED(CONFIG_SND_DEBUG)
-       struct dentry *debugfs_root;
-#endif
-};
-
-extern const struct dev_pm_ops cs35l56_hda_pm_ops;
-
-int cs35l56_hda_common_probe(struct cs35l56_hda *cs35l56, int hid, int id);
-void cs35l56_hda_remove(struct device *dev);
-
-#endif /*__CS35L56_HDA_H__*/
diff --git a/sound/pci/hda/cs35l56_hda_i2c.c b/sound/pci/hda/cs35l56_hda_i2c.c
deleted file mode 100644 (file)
index d10209e..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-//
-// CS35L56 HDA audio driver I2C binding
-//
-// Copyright (C) 2023 Cirrus Logic, Inc. and
-//                    Cirrus Logic International Semiconductor Ltd.
-
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/regmap.h>
-
-#include "cs35l56_hda.h"
-
-static int cs35l56_hda_i2c_probe(struct i2c_client *clt)
-{
-       const struct i2c_device_id *id = i2c_client_get_device_id(clt);
-       struct cs35l56_hda *cs35l56;
-       int ret;
-
-       cs35l56 = devm_kzalloc(&clt->dev, sizeof(*cs35l56), GFP_KERNEL);
-       if (!cs35l56)
-               return -ENOMEM;
-
-       cs35l56->base.dev = &clt->dev;
-
-#ifdef CS35L56_WAKE_HOLD_TIME_US
-       cs35l56->base.can_hibernate = true;
-#endif
-
-       cs35l56->base.fw_reg = &cs35l56_fw_reg;
-
-       cs35l56->base.regmap = devm_regmap_init_i2c(clt, &cs35l56_regmap_i2c);
-       if (IS_ERR(cs35l56->base.regmap)) {
-               ret = PTR_ERR(cs35l56->base.regmap);
-               dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
-                       ret);
-               return ret;
-       }
-
-       ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, clt->addr);
-       if (ret)
-               return ret;
-       ret = cs35l56_irq_request(&cs35l56->base, clt->irq);
-       if (ret < 0)
-               cs35l56_hda_remove(cs35l56->base.dev);
-
-       return ret;
-}
-
-static void cs35l56_hda_i2c_remove(struct i2c_client *clt)
-{
-       cs35l56_hda_remove(&clt->dev);
-}
-
-static const struct i2c_device_id cs35l56_hda_i2c_id[] = {
-       { "cs35l54-hda", 0x3554 },
-       { "cs35l56-hda", 0x3556 },
-       { "cs35l57-hda", 0x3557 },
-       {}
-};
-
-static const struct acpi_device_id cs35l56_acpi_hda_match[] = {
-       { "CSC3554", 0 },
-       { "CSC3556", 0 },
-       { "CSC3557", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(acpi, cs35l56_acpi_hda_match);
-
-static struct i2c_driver cs35l56_hda_i2c_driver = {
-       .driver = {
-               .name             = "cs35l56-hda",
-               .acpi_match_table = cs35l56_acpi_hda_match,
-               .pm               = &cs35l56_hda_pm_ops,
-       },
-       .id_table       = cs35l56_hda_i2c_id,
-       .probe          = cs35l56_hda_i2c_probe,
-       .remove         = cs35l56_hda_i2c_remove,
-};
-module_i2c_driver(cs35l56_hda_i2c_driver);
-
-MODULE_DESCRIPTION("HDA CS35L56 I2C driver");
-MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56");
-MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
-MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
-MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/cs35l56_hda_spi.c b/sound/pci/hda/cs35l56_hda_spi.c
deleted file mode 100644 (file)
index f57533d..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-//
-// CS35L56 HDA audio driver SPI binding
-//
-// Copyright (C) 2023 Cirrus Logic, Inc. and
-//                    Cirrus Logic International Semiconductor Ltd.
-
-#include <linux/module.h>
-#include <linux/regmap.h>
-#include <linux/spi/spi.h>
-
-#include "cs35l56_hda.h"
-
-static int cs35l56_hda_spi_probe(struct spi_device *spi)
-{
-       const struct spi_device_id *id = spi_get_device_id(spi);
-       struct cs35l56_hda *cs35l56;
-       int ret;
-
-       cs35l56 = devm_kzalloc(&spi->dev, sizeof(*cs35l56), GFP_KERNEL);
-       if (!cs35l56)
-               return -ENOMEM;
-
-       cs35l56->base.dev = &spi->dev;
-       ret = cs35l56_init_config_for_spi(&cs35l56->base, spi);
-       if (ret)
-               return ret;
-
-#ifdef CS35L56_WAKE_HOLD_TIME_US
-       cs35l56->base.can_hibernate = true;
-#endif
-
-       cs35l56->base.fw_reg = &cs35l56_fw_reg;
-
-       cs35l56->base.regmap = devm_regmap_init_spi(spi, &cs35l56_regmap_spi);
-       if (IS_ERR(cs35l56->base.regmap)) {
-               ret = PTR_ERR(cs35l56->base.regmap);
-               dev_err(cs35l56->base.dev, "Failed to allocate register map: %d\n",
-                       ret);
-               return ret;
-       }
-
-       ret = cs35l56_hda_common_probe(cs35l56, id->driver_data, spi_get_chipselect(spi, 0));
-       if (ret)
-               return ret;
-       ret = cs35l56_irq_request(&cs35l56->base, spi->irq);
-       if (ret < 0)
-               cs35l56_hda_remove(cs35l56->base.dev);
-
-       return ret;
-}
-
-static void cs35l56_hda_spi_remove(struct spi_device *spi)
-{
-       cs35l56_hda_remove(&spi->dev);
-}
-
-static const struct spi_device_id cs35l56_hda_spi_id[] = {
-       { "cs35l54-hda", 0x3554 },
-       { "cs35l56-hda", 0x3556 },
-       { "cs35l57-hda", 0x3557 },
-       {}
-};
-
-static const struct acpi_device_id cs35l56_acpi_hda_match[] = {
-       { "CSC3554", 0 },
-       { "CSC3556", 0 },
-       { "CSC3557", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(acpi, cs35l56_acpi_hda_match);
-
-static struct spi_driver cs35l56_hda_spi_driver = {
-       .driver = {
-               .name             = "cs35l56-hda",
-               .acpi_match_table = cs35l56_acpi_hda_match,
-               .pm               = &cs35l56_hda_pm_ops,
-       },
-       .id_table       = cs35l56_hda_spi_id,
-       .probe          = cs35l56_hda_spi_probe,
-       .remove         = cs35l56_hda_spi_remove,
-};
-module_spi_driver(cs35l56_hda_spi_driver);
-
-MODULE_DESCRIPTION("HDA CS35L56 SPI driver");
-MODULE_IMPORT_NS("SND_HDA_SCODEC_CS35L56");
-MODULE_IMPORT_NS("SND_SOC_CS35L56_SHARED");
-MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
-MODULE_AUTHOR("Simon Trimmer <simont@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_component.c b/sound/pci/hda/hda_component.c
deleted file mode 100644 (file)
index 71860e2..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * HD audio Component Binding Interface
- *
- * Copyright (C) 2021, 2023 Cirrus Logic, Inc. and
- *                     Cirrus Logic International Semiconductor Ltd.
- */
-
-#include <linux/acpi.h>
-#include <linux/component.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <sound/hda_codec.h>
-#include "hda_component.h"
-#include "hda_local.h"
-
-#ifdef CONFIG_ACPI
-void hda_component_acpi_device_notify(struct hda_component_parent *parent,
-                                     acpi_handle handle, u32 event, void *data)
-{
-       struct hda_component *comp;
-       int i;
-
-       mutex_lock(&parent->mutex);
-       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
-               comp = hda_component_from_index(parent, i);
-               if (comp->dev && comp->acpi_notify)
-                       comp->acpi_notify(acpi_device_handle(comp->adev), event, comp->dev);
-       }
-       mutex_unlock(&parent->mutex);
-}
-EXPORT_SYMBOL_NS_GPL(hda_component_acpi_device_notify, "SND_HDA_SCODEC_COMPONENT");
-
-int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
-                                                 struct hda_component_parent *parent,
-                                                 acpi_notify_handler handler, void *data)
-{
-       bool support_notifications = false;
-       struct acpi_device *adev;
-       struct hda_component *comp;
-       int ret;
-       int i;
-
-       adev = parent->comps[0].adev;
-       if (!acpi_device_handle(adev))
-               return 0;
-
-       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
-               comp = hda_component_from_index(parent, i);
-               support_notifications = support_notifications ||
-                       comp->acpi_notifications_supported;
-       }
-
-       if (support_notifications) {
-               ret = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
-                                                 handler, data);
-               if (ret < 0) {
-                       codec_warn(cdc, "Failed to install notify handler: %d\n", ret);
-                       return 0;
-               }
-
-               codec_dbg(cdc, "Notify handler installed\n");
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT");
-
-void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
-                                                    struct hda_component_parent *parent,
-                                                    acpi_notify_handler handler)
-{
-       struct acpi_device *adev;
-       int ret;
-
-       adev = parent->comps[0].adev;
-       if (!acpi_device_handle(adev))
-               return;
-
-       ret = acpi_remove_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY, handler);
-       if (ret < 0)
-               codec_warn(cdc, "Failed to uninstall notify handler: %d\n", ret);
-}
-EXPORT_SYMBOL_NS_GPL(hda_component_manager_unbind_acpi_notifications, "SND_HDA_SCODEC_COMPONENT");
-#endif /* ifdef CONFIG_ACPI */
-
-void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action)
-{
-       struct hda_component *comp;
-       int i;
-
-       mutex_lock(&parent->mutex);
-       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
-               comp = hda_component_from_index(parent, i);
-               if (comp->dev && comp->pre_playback_hook)
-                       comp->pre_playback_hook(comp->dev, action);
-       }
-       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
-               comp = hda_component_from_index(parent, i);
-               if (comp->dev && comp->playback_hook)
-                       comp->playback_hook(comp->dev, action);
-       }
-       for (i = 0; i < ARRAY_SIZE(parent->comps); i++) {
-               comp = hda_component_from_index(parent, i);
-               if (comp->dev && comp->post_playback_hook)
-                       comp->post_playback_hook(comp->dev, action);
-       }
-       mutex_unlock(&parent->mutex);
-}
-EXPORT_SYMBOL_NS_GPL(hda_component_manager_playback_hook, "SND_HDA_SCODEC_COMPONENT");
-
-struct hda_scodec_match {
-       const char *bus;
-       const char *hid;
-       const char *match_str;
-       int index;
-};
-
-/* match the device name in a slightly relaxed manner */
-static int hda_comp_match_dev_name(struct device *dev, void *data)
-{
-       struct hda_scodec_match *p = data;
-       const char *d = dev_name(dev);
-       int n = strlen(p->bus);
-       char tmp[32];
-
-       /* check the bus name */
-       if (strncmp(d, p->bus, n))
-               return 0;
-       /* skip the bus number */
-       if (isdigit(d[n]))
-               n++;
-       /* the rest must be exact matching */
-       snprintf(tmp, sizeof(tmp), p->match_str, p->hid, p->index);
-       return !strcmp(d + n, tmp);
-}
-
-int hda_component_manager_bind(struct hda_codec *cdc,
-                              struct hda_component_parent *parent)
-{
-       int ret;
-
-       /* Init shared and component specific data */
-       memset(parent->comps, 0, sizeof(parent->comps));
-
-       mutex_lock(&parent->mutex);
-       ret = component_bind_all(hda_codec_dev(cdc), parent);
-       mutex_unlock(&parent->mutex);
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(hda_component_manager_bind, "SND_HDA_SCODEC_COMPONENT");
-
-int hda_component_manager_init(struct hda_codec *cdc,
-                              struct hda_component_parent *parent, int count,
-                              const char *bus, const char *hid,
-                              const char *match_str,
-                              const struct component_master_ops *ops)
-{
-       struct device *dev = hda_codec_dev(cdc);
-       struct component_match *match = NULL;
-       struct hda_scodec_match *sm;
-       int ret, i;
-
-       if (parent->codec) {
-               codec_err(cdc, "Component binding already created (SSID: %x)\n",
-                         cdc->core.subsystem_id);
-               return -EINVAL;
-       }
-       parent->codec = cdc;
-
-       mutex_init(&parent->mutex);
-
-       for (i = 0; i < count; i++) {
-               sm = devm_kmalloc(dev, sizeof(*sm), GFP_KERNEL);
-               if (!sm)
-                       return -ENOMEM;
-
-               sm->bus = bus;
-               sm->hid = hid;
-               sm->match_str = match_str;
-               sm->index = i;
-               component_match_add(dev, &match, hda_comp_match_dev_name, sm);
-       }
-
-       ret = component_master_add_with_match(dev, ops, match);
-       if (ret)
-               codec_err(cdc, "Fail to register component aggregator %d\n", ret);
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(hda_component_manager_init, "SND_HDA_SCODEC_COMPONENT");
-
-void hda_component_manager_free(struct hda_component_parent *parent,
-                               const struct component_master_ops *ops)
-{
-       struct device *dev;
-
-       if (!parent->codec)
-               return;
-
-       dev = hda_codec_dev(parent->codec);
-
-       component_master_del(dev, ops);
-
-       parent->codec = NULL;
-}
-EXPORT_SYMBOL_NS_GPL(hda_component_manager_free, "SND_HDA_SCODEC_COMPONENT");
-
-MODULE_DESCRIPTION("HD Audio component binding library");
-MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
-MODULE_LICENSE("GPL");
diff --git a/sound/pci/hda/hda_component.h b/sound/pci/hda/hda_component.h
deleted file mode 100644 (file)
index 7ee3715..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * HD audio Component Binding Interface
- *
- * Copyright (C) 2021 Cirrus Logic, Inc. and
- *                    Cirrus Logic International Semiconductor Ltd.
- */
-
-#ifndef __HDA_COMPONENT_H__
-#define __HDA_COMPONENT_H__
-
-#include <linux/acpi.h>
-#include <linux/component.h>
-#include <linux/mutex.h>
-#include <sound/hda_codec.h>
-
-#define HDA_MAX_COMPONENTS     4
-#define HDA_MAX_NAME_SIZE      50
-
-struct hda_component {
-       struct device *dev;
-       char name[HDA_MAX_NAME_SIZE];
-       struct acpi_device *adev;
-       bool acpi_notifications_supported;
-       void (*acpi_notify)(acpi_handle handle, u32 event, struct device *dev);
-       void (*pre_playback_hook)(struct device *dev, int action);
-       void (*playback_hook)(struct device *dev, int action);
-       void (*post_playback_hook)(struct device *dev, int action);
-};
-
-struct hda_component_parent {
-       struct mutex mutex;
-       struct hda_codec *codec;
-       struct hda_component comps[HDA_MAX_COMPONENTS];
-};
-
-#ifdef CONFIG_ACPI
-void hda_component_acpi_device_notify(struct hda_component_parent *parent,
-                                     acpi_handle handle, u32 event, void *data);
-int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
-                                                 struct hda_component_parent *parent,
-                                                 acpi_notify_handler handler, void *data);
-void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
-                                                    struct hda_component_parent *parent,
-                                                    acpi_notify_handler handler);
-#else
-static inline void hda_component_acpi_device_notify(struct hda_component_parent *parent,
-                                                   acpi_handle handle,
-                                                   u32 event,
-                                                   void *data)
-{
-}
-
-static inline int hda_component_manager_bind_acpi_notifications(struct hda_codec *cdc,
-                                                               struct hda_component_parent *parent,
-                                                               acpi_notify_handler handler,
-                                                               void *data)
-
-{
-       return 0;
-}
-
-static inline void hda_component_manager_unbind_acpi_notifications(struct hda_codec *cdc,
-                                                                  struct hda_component_parent *parent,
-                                                                  acpi_notify_handler handler)
-{
-}
-#endif /* ifdef CONFIG_ACPI */
-
-void hda_component_manager_playback_hook(struct hda_component_parent *parent, int action);
-
-int hda_component_manager_init(struct hda_codec *cdc,
-                              struct hda_component_parent *parent, int count,
-                              const char *bus, const char *hid,
-                              const char *match_str,
-                              const struct component_master_ops *ops);
-
-void hda_component_manager_free(struct hda_component_parent *parent,
-                               const struct component_master_ops *ops);
-
-int hda_component_manager_bind(struct hda_codec *cdc, struct hda_component_parent *parent);
-
-static inline struct hda_component *hda_component_from_index(struct hda_component_parent *parent,
-                                                            int index)
-{
-       if (!parent)
-               return NULL;
-
-       if (index < 0 || index >= ARRAY_SIZE(parent->comps))
-               return NULL;
-
-       return &parent->comps[index];
-}
-
-static inline void hda_component_manager_unbind(struct hda_codec *cdc,
-                                               struct hda_component_parent *parent)
-{
-       mutex_lock(&parent->mutex);
-       component_unbind_all(hda_codec_dev(cdc), parent);
-       mutex_unlock(&parent->mutex);
-}
-
-#endif /* ifndef __HDA_COMPONENT_H__ */
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
deleted file mode 100644 (file)
index d3e87b9..0000000
+++ /dev/null
@@ -1,402 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Generic routines and proc interface for ELD(EDID Like Data) information
- *
- * Copyright(c) 2008 Intel Corporation.
- * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
- *
- * Authors:
- *             Wu Fengguang <wfg@linux.intel.com>
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <sound/core.h>
-#include <linux/unaligned.h>
-#include <sound/hda_chmap.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-
-enum cea_edid_versions {
-       CEA_EDID_VER_NONE       = 0,
-       CEA_EDID_VER_CEA861     = 1,
-       CEA_EDID_VER_CEA861A    = 2,
-       CEA_EDID_VER_CEA861BCD  = 3,
-       CEA_EDID_VER_RESERVED   = 4,
-};
-
-/*
- * The following two lists are shared between
- *     - HDMI audio InfoFrame (source to sink)
- *     - CEA E-EDID Extension (sink to source)
- */
-
-static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid,
-                                       int byte_index)
-{
-       unsigned int val;
-
-       val = snd_hda_codec_read(codec, nid, 0,
-                                       AC_VERB_GET_HDMI_ELDD, byte_index);
-#ifdef BE_PARANOID
-       codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val);
-#endif
-       return val;
-}
-
-int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid)
-{
-       return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE,
-                                                AC_DIPSIZE_ELD_BUF);
-}
-
-int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid,
-                    unsigned char *buf, int *eld_size)
-{
-       int i;
-       int ret = 0;
-       int size;
-
-       /*
-        * ELD size is initialized to zero in caller function. If no errors and
-        * ELD is valid, actual eld_size is assigned.
-        */
-
-       size = snd_hdmi_get_eld_size(codec, nid);
-       if (size == 0) {
-               /* wfg: workaround for ASUS P5E-VM HDMI board */
-               codec_info(codec, "HDMI: ELD buf size is 0, force 128\n");
-               size = 128;
-       }
-       if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) {
-               codec_info(codec, "HDMI: invalid ELD buf size %d\n", size);
-               return -ERANGE;
-       }
-
-       /* set ELD buffer */
-       for (i = 0; i < size; i++) {
-               unsigned int val = hdmi_get_eld_data(codec, nid, i);
-               /*
-                * Graphics driver might be writing to ELD buffer right now.
-                * Just abort. The caller will repoll after a while.
-                */
-               if (!(val & AC_ELDD_ELD_VALID)) {
-                       codec_info(codec, "HDMI: invalid ELD data byte %d\n", i);
-                       ret = -EINVAL;
-                       goto error;
-               }
-               val &= AC_ELDD_ELD_DATA;
-               /*
-                * The first byte cannot be zero. This can happen on some DVI
-                * connections. Some Intel chips may also need some 250ms delay
-                * to return non-zero ELD data, even when the graphics driver
-                * correctly writes ELD content before setting ELD_valid bit.
-                */
-               if (!val && !i) {
-                       codec_dbg(codec, "HDMI: 0 ELD data\n");
-                       ret = -EINVAL;
-                       goto error;
-               }
-               buf[i] = val;
-       }
-
-       *eld_size = size;
-error:
-       return ret;
-}
-
-#ifdef CONFIG_SND_PROC_FS
-void snd_hdmi_print_eld_info(struct hdmi_eld *eld,
-                            struct snd_info_buffer *buffer,
-                            hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
-{
-       snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present);
-       snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid);
-       snd_iprintf(buffer, "codec_pin_nid\t\t0x%x\n", pin_nid);
-       snd_iprintf(buffer, "codec_dev_id\t\t0x%x\n", dev_id);
-       snd_iprintf(buffer, "codec_cvt_nid\t\t0x%x\n", cvt_nid);
-
-       if (!eld->eld_valid)
-               return;
-
-       snd_print_eld_info(&eld->info, buffer);
-}
-
-void snd_hdmi_write_eld_info(struct hdmi_eld *eld,
-                            struct snd_info_buffer *buffer)
-{
-       struct snd_parsed_hdmi_eld *e = &eld->info;
-       char line[64];
-       char name[64];
-       char *sname;
-       long long val;
-       unsigned int n;
-
-       while (!snd_info_get_line(buffer, line, sizeof(line))) {
-               if (sscanf(line, "%s %llx", name, &val) != 2)
-                       continue;
-               /*
-                * We don't allow modification to these fields:
-                *      monitor_name manufacture_id product_id
-                *      eld_version edid_version
-                */
-               if (!strcmp(name, "monitor_present"))
-                       eld->monitor_present = val;
-               else if (!strcmp(name, "eld_valid"))
-                       eld->eld_valid = val;
-               else if (!strcmp(name, "connection_type"))
-                       e->conn_type = val;
-               else if (!strcmp(name, "port_id"))
-                       e->port_id = val;
-               else if (!strcmp(name, "support_hdcp"))
-                       e->support_hdcp = val;
-               else if (!strcmp(name, "support_ai"))
-                       e->support_ai = val;
-               else if (!strcmp(name, "audio_sync_delay"))
-                       e->aud_synch_delay = val;
-               else if (!strcmp(name, "speakers"))
-                       e->spk_alloc = val;
-               else if (!strcmp(name, "sad_count"))
-                       e->sad_count = val;
-               else if (!strncmp(name, "sad", 3)) {
-                       sname = name + 4;
-                       n = name[3] - '0';
-                       if (name[4] >= '0' && name[4] <= '9') {
-                               sname++;
-                               n = 10 * n + name[4] - '0';
-                       }
-                       if (n >= ELD_MAX_SAD)
-                               continue;
-                       if (!strcmp(sname, "_coding_type"))
-                               e->sad[n].format = val;
-                       else if (!strcmp(sname, "_channels"))
-                               e->sad[n].channels = val;
-                       else if (!strcmp(sname, "_rates"))
-                               e->sad[n].rates = val;
-                       else if (!strcmp(sname, "_bits"))
-                               e->sad[n].sample_bits = val;
-                       else if (!strcmp(sname, "_max_bitrate"))
-                               e->sad[n].max_bitrate = val;
-                       else if (!strcmp(sname, "_profile"))
-                               e->sad[n].profile = val;
-                       if (n >= e->sad_count)
-                               e->sad_count = n + 1;
-               }
-       }
-}
-#endif /* CONFIG_SND_PROC_FS */
-
-/* update PCM info based on ELD */
-void snd_hdmi_eld_update_pcm_info(struct snd_parsed_hdmi_eld *e,
-                             struct hda_pcm_stream *hinfo)
-{
-       u32 rates;
-       u64 formats;
-       unsigned int maxbps;
-       unsigned int channels_max;
-       int i;
-
-       /* assume basic audio support (the basic audio flag is not in ELD;
-        * however, all audio capable sinks are required to support basic
-        * audio) */
-       rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
-               SNDRV_PCM_RATE_48000;
-       formats = SNDRV_PCM_FMTBIT_S16_LE;
-       maxbps = 16;
-       channels_max = 2;
-       for (i = 0; i < e->sad_count; i++) {
-               struct snd_cea_sad *a = &e->sad[i];
-               rates |= a->rates;
-               if (a->channels > channels_max)
-                       channels_max = a->channels;
-               if (a->format == AUDIO_CODING_TYPE_LPCM) {
-                       if (a->sample_bits & ELD_PCM_BITS_20) {
-                               formats |= SNDRV_PCM_FMTBIT_S32_LE;
-                               if (maxbps < 20)
-                                       maxbps = 20;
-                       }
-                       if (a->sample_bits & ELD_PCM_BITS_24) {
-                               formats |= SNDRV_PCM_FMTBIT_S32_LE;
-                               if (maxbps < 24)
-                                       maxbps = 24;
-                       }
-               }
-       }
-
-       /* restrict the parameters by the values the codec provides */
-       hinfo->rates &= rates;
-       hinfo->formats &= formats;
-       hinfo->maxbps = min(hinfo->maxbps, maxbps);
-       hinfo->channels_max = min(hinfo->channels_max, channels_max);
-}
-
-
-/* ATI/AMD specific stuff (ELD emulation) */
-
-#define ATI_VERB_SET_AUDIO_DESCRIPTOR  0x776
-#define ATI_VERB_SET_SINK_INFO_INDEX   0x780
-#define ATI_VERB_GET_SPEAKER_ALLOCATION        0xf70
-#define ATI_VERB_GET_AUDIO_DESCRIPTOR  0xf76
-#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b
-#define ATI_VERB_GET_SINK_INFO_INDEX   0xf80
-#define ATI_VERB_GET_SINK_INFO_DATA    0xf81
-
-#define ATI_SPKALLOC_SPKALLOC          0x007f
-#define ATI_SPKALLOC_TYPE_HDMI         0x0100
-#define ATI_SPKALLOC_TYPE_DISPLAYPORT  0x0200
-
-/* first three bytes are just standard SAD */
-#define ATI_AUDIODESC_CHANNELS         0x00000007
-#define ATI_AUDIODESC_RATES            0x0000ff00
-#define ATI_AUDIODESC_LPCM_STEREO_RATES        0xff000000
-
-/* in standard HDMI VSDB format */
-#define ATI_DELAY_VIDEO_LATENCY                0x000000ff
-#define ATI_DELAY_AUDIO_LATENCY                0x0000ff00
-
-enum ati_sink_info_idx {
-       ATI_INFO_IDX_MANUFACTURER_ID    = 0,
-       ATI_INFO_IDX_PRODUCT_ID         = 1,
-       ATI_INFO_IDX_SINK_DESC_LEN      = 2,
-       ATI_INFO_IDX_PORT_ID_LOW        = 3,
-       ATI_INFO_IDX_PORT_ID_HIGH       = 4,
-       ATI_INFO_IDX_SINK_DESC_FIRST    = 5,
-       ATI_INFO_IDX_SINK_DESC_LAST     = 22, /* max len 18 bytes */
-};
-
-int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid,
-                        unsigned char *buf, int *eld_size, bool rev3_or_later)
-{
-       int spkalloc, ati_sad, aud_synch;
-       int sink_desc_len = 0;
-       int pos, i;
-
-       /* ATI/AMD does not have ELD, emulate it */
-
-       spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0);
-
-       if (spkalloc <= 0) {
-               codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n");
-               return -EINVAL;
-       }
-
-       memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3);
-
-       /* version */
-       buf[0] = ELD_VER_CEA_861D << 3;
-
-       /* speaker allocation from EDID */
-       buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC;
-
-       /* is DisplayPort? */
-       if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT)
-               buf[5] |= 0x04;
-
-       pos = ELD_FIXED_BYTES;
-
-       if (rev3_or_later) {
-               int sink_info;
-
-               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW);
-               sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-               put_unaligned_le32(sink_info, buf + 8);
-
-               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH);
-               sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-               put_unaligned_le32(sink_info, buf + 12);
-
-               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID);
-               sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-               put_unaligned_le16(sink_info, buf + 16);
-
-               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID);
-               sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-               put_unaligned_le16(sink_info, buf + 18);
-
-               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN);
-               sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-
-               if (sink_desc_len > ELD_MAX_MNL) {
-                       codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n",
-                                  sink_desc_len);
-                       sink_desc_len = ELD_MAX_MNL;
-               }
-
-               buf[4] |= sink_desc_len;
-
-               for (i = 0; i < sink_desc_len; i++) {
-                       snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i);
-                       buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0);
-               }
-       }
-
-       for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) {
-               if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST)
-                       continue; /* not handled by ATI/AMD */
-
-               snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3);
-               ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0);
-
-               if (ati_sad <= 0)
-                       continue;
-
-               if (ati_sad & ATI_AUDIODESC_RATES) {
-                       /* format is supported, copy SAD as-is */
-                       buf[pos++] = (ati_sad & 0x0000ff) >> 0;
-                       buf[pos++] = (ati_sad & 0x00ff00) >> 8;
-                       buf[pos++] = (ati_sad & 0xff0000) >> 16;
-               }
-
-               if (i == AUDIO_CODING_TYPE_LPCM
-                   && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES)
-                   && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) {
-                       /* for PCM there is a separate stereo rate mask */
-                       buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1;
-                       /* rates from the extra byte */
-                       buf[pos++] = (ati_sad & 0xff000000) >> 24;
-                       buf[pos++] = (ati_sad & 0x00ff0000) >> 16;
-               }
-       }
-
-       if (pos == ELD_FIXED_BYTES + sink_desc_len) {
-               codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n");
-               return -EINVAL;
-       }
-
-       /*
-        * HDMI VSDB latency format:
-        * separately for both audio and video:
-        *  0          field not valid or unknown latency
-        *  [1..251]   msecs = (x-1)*2  (max 500ms with x = 251 = 0xfb)
-        *  255        audio/video not supported
-        *
-        * HDA latency format:
-        * single value indicating video latency relative to audio:
-        *  0          unknown or 0ms
-        *  [1..250]   msecs = x*2  (max 500ms with x = 250 = 0xfa)
-        *  [251..255] reserved
-        */
-       aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0);
-       if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) {
-               int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY);
-               int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8;
-
-               if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb &&
-                   video_latency_hdmi > audio_latency_hdmi)
-                       buf[6] = video_latency_hdmi - audio_latency_hdmi;
-               /* else unknown/invalid or 0ms or video ahead of audio, so use zero */
-       }
-
-       /* SAD count */
-       buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4;
-
-       /* Baseline ELD block length is 4-byte aligned */
-       pos = round_up(pos, 4);
-
-       /* Baseline ELD length (4-byte header is not counted in) */
-       buf[2] = (pos - 4) / 4;
-
-       *eld_size = pos;
-
-       return 0;
-}
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
deleted file mode 100644 (file)
index 2a28c8b..0000000
+++ /dev/null
@@ -1,6160 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * Generic widget tree parser
- *
- * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/sort.h>
-#include <linux/delay.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/bitops.h>
-#include <linux/module.h>
-#include <linux/leds.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/tlv.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_beep.h"
-#include "hda_generic.h"
-
-
-/**
- * snd_hda_gen_spec_init - initialize hda_gen_spec struct
- * @spec: hda_gen_spec object to initialize
- *
- * Initialize the given hda_gen_spec object.
- */
-int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
-{
-       snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
-       snd_array_init(&spec->paths, sizeof(struct nid_path), 8);
-       snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8);
-       mutex_init(&spec->pcm_mutex);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init);
-
-/**
- * snd_hda_gen_add_kctl - Add a new kctl_new struct from the template
- * @spec: hda_gen_spec object
- * @name: name string to override the template, NULL if unchanged
- * @temp: template for the new kctl
- *
- * Add a new kctl (actually snd_kcontrol_new to be instantiated later)
- * element based on the given snd_kcontrol_new template @temp and the
- * name string @name to the list in @spec.
- * Returns the newly created object or NULL as error.
- */
-struct snd_kcontrol_new *
-snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
-                    const struct snd_kcontrol_new *temp)
-{
-       struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls);
-       if (!knew)
-               return NULL;
-       *knew = *temp;
-       if (name)
-               knew->name = kstrdup(name, GFP_KERNEL);
-       else if (knew->name)
-               knew->name = kstrdup(knew->name, GFP_KERNEL);
-       if (!knew->name)
-               return NULL;
-       return knew;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_add_kctl);
-
-static void free_kctls(struct hda_gen_spec *spec)
-{
-       if (spec->kctls.list) {
-               struct snd_kcontrol_new *kctl = spec->kctls.list;
-               int i;
-               for (i = 0; i < spec->kctls.used; i++)
-                       kfree(kctl[i].name);
-       }
-       snd_array_free(&spec->kctls);
-}
-
-static void snd_hda_gen_spec_free(struct hda_gen_spec *spec)
-{
-       if (!spec)
-               return;
-       free_kctls(spec);
-       snd_array_free(&spec->paths);
-       snd_array_free(&spec->loopback_list);
-#ifdef CONFIG_SND_HDA_GENERIC_LEDS
-       if (spec->led_cdevs[LED_AUDIO_MUTE])
-               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MUTE]);
-       if (spec->led_cdevs[LED_AUDIO_MICMUTE])
-               led_classdev_unregister(spec->led_cdevs[LED_AUDIO_MICMUTE]);
-#endif
-}
-
-/*
- * store user hints
- */
-static void parse_user_hints(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int val;
-
-       val = snd_hda_get_bool_hint(codec, "jack_detect");
-       if (val >= 0)
-               codec->no_jack_detect = !val;
-       val = snd_hda_get_bool_hint(codec, "inv_jack_detect");
-       if (val >= 0)
-               codec->inv_jack_detect = !!val;
-       val = snd_hda_get_bool_hint(codec, "trigger_sense");
-       if (val >= 0)
-               codec->no_trigger_sense = !val;
-       val = snd_hda_get_bool_hint(codec, "inv_eapd");
-       if (val >= 0)
-               codec->inv_eapd = !!val;
-       val = snd_hda_get_bool_hint(codec, "pcm_format_first");
-       if (val >= 0)
-               codec->pcm_format_first = !!val;
-       val = snd_hda_get_bool_hint(codec, "sticky_stream");
-       if (val >= 0)
-               codec->no_sticky_stream = !val;
-       val = snd_hda_get_bool_hint(codec, "spdif_status_reset");
-       if (val >= 0)
-               codec->spdif_status_reset = !!val;
-       val = snd_hda_get_bool_hint(codec, "pin_amp_workaround");
-       if (val >= 0)
-               codec->pin_amp_workaround = !!val;
-       val = snd_hda_get_bool_hint(codec, "single_adc_amp");
-       if (val >= 0)
-               codec->single_adc_amp = !!val;
-       val = snd_hda_get_bool_hint(codec, "power_save_node");
-       if (val >= 0)
-               codec->power_save_node = !!val;
-
-       val = snd_hda_get_bool_hint(codec, "auto_mute");
-       if (val >= 0)
-               spec->suppress_auto_mute = !val;
-       val = snd_hda_get_bool_hint(codec, "auto_mic");
-       if (val >= 0)
-               spec->suppress_auto_mic = !val;
-       val = snd_hda_get_bool_hint(codec, "line_in_auto_switch");
-       if (val >= 0)
-               spec->line_in_auto_switch = !!val;
-       val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp");
-       if (val >= 0)
-               spec->auto_mute_via_amp = !!val;
-       val = snd_hda_get_bool_hint(codec, "need_dac_fix");
-       if (val >= 0)
-               spec->need_dac_fix = !!val;
-       val = snd_hda_get_bool_hint(codec, "primary_hp");
-       if (val >= 0)
-               spec->no_primary_hp = !val;
-       val = snd_hda_get_bool_hint(codec, "multi_io");
-       if (val >= 0)
-               spec->no_multi_io = !val;
-       val = snd_hda_get_bool_hint(codec, "multi_cap_vol");
-       if (val >= 0)
-               spec->multi_cap_vol = !!val;
-       val = snd_hda_get_bool_hint(codec, "inv_dmic_split");
-       if (val >= 0)
-               spec->inv_dmic_split = !!val;
-       val = snd_hda_get_bool_hint(codec, "indep_hp");
-       if (val >= 0)
-               spec->indep_hp = !!val;
-       val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input");
-       if (val >= 0)
-               spec->add_stereo_mix_input = !!val;
-       /* the following two are just for compatibility */
-       val = snd_hda_get_bool_hint(codec, "add_out_jack_modes");
-       if (val >= 0)
-               spec->add_jack_modes = !!val;
-       val = snd_hda_get_bool_hint(codec, "add_in_jack_modes");
-       if (val >= 0)
-               spec->add_jack_modes = !!val;
-       val = snd_hda_get_bool_hint(codec, "add_jack_modes");
-       if (val >= 0)
-               spec->add_jack_modes = !!val;
-       val = snd_hda_get_bool_hint(codec, "power_down_unused");
-       if (val >= 0)
-               spec->power_down_unused = !!val;
-       val = snd_hda_get_bool_hint(codec, "add_hp_mic");
-       if (val >= 0)
-               spec->hp_mic = !!val;
-       val = snd_hda_get_bool_hint(codec, "hp_mic_detect");
-       if (val >= 0)
-               spec->suppress_hp_mic_detect = !val;
-       val = snd_hda_get_bool_hint(codec, "vmaster");
-       if (val >= 0)
-               spec->suppress_vmaster = !val;
-
-       if (!snd_hda_get_int_hint(codec, "mixer_nid", &val))
-               spec->mixer_nid = val;
-}
-
-/*
- * pin control value accesses
- */
-
-#define update_pin_ctl(codec, pin, val) \
-       snd_hda_codec_write_cache(codec, pin, 0, \
-                                  AC_VERB_SET_PIN_WIDGET_CONTROL, val)
-
-/* restore the pinctl based on the cached value */
-static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin)
-{
-       update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin));
-}
-
-/* set the pinctl target value and write it if requested */
-static void set_pin_target(struct hda_codec *codec, hda_nid_t pin,
-                          unsigned int val, bool do_write)
-{
-       if (!pin)
-               return;
-       val = snd_hda_correct_pin_ctl(codec, pin, val);
-       snd_hda_codec_set_pin_target(codec, pin, val);
-       if (do_write)
-               update_pin_ctl(codec, pin, val);
-}
-
-/* set pinctl target values for all given pins */
-static void set_pin_targets(struct hda_codec *codec, int num_pins,
-                           hda_nid_t *pins, unsigned int val)
-{
-       int i;
-       for (i = 0; i < num_pins; i++)
-               set_pin_target(codec, pins[i], val, false);
-}
-
-/*
- * parsing paths
- */
-
-/* return the position of NID in the list, or -1 if not found */
-static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-       int i;
-       for (i = 0; i < nums; i++)
-               if (list[i] == nid)
-                       return i;
-       return -1;
-}
-
-/* return true if the given NID is contained in the path */
-static bool is_nid_contained(struct nid_path *path, hda_nid_t nid)
-{
-       return find_idx_in_nid_list(nid, path->path, path->depth) >= 0;
-}
-
-static struct nid_path *get_nid_path(struct hda_codec *codec,
-                                    hda_nid_t from_nid, hda_nid_t to_nid,
-                                    int anchor_nid)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *path;
-       int i;
-
-       snd_array_for_each(&spec->paths, i, path) {
-               if (path->depth <= 0)
-                       continue;
-               if ((!from_nid || path->path[0] == from_nid) &&
-                   (!to_nid || path->path[path->depth - 1] == to_nid)) {
-                       if (!anchor_nid ||
-                           (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) ||
-                           (anchor_nid < 0 && !is_nid_contained(path, anchor_nid)))
-                               return path;
-               }
-       }
-       return NULL;
-}
-
-/**
- * snd_hda_get_path_idx - get the index number corresponding to the path
- * instance
- * @codec: the HDA codec
- * @path: nid_path object
- *
- * The returned index starts from 1, i.e. the actual array index with offset 1,
- * and zero is handled as an invalid path
- */
-int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *array = spec->paths.list;
-       ssize_t idx;
-
-       if (!spec->paths.used)
-               return 0;
-       idx = path - array;
-       if (idx < 0 || idx >= spec->paths.used)
-               return 0;
-       return idx + 1;
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_path_idx);
-
-/**
- * snd_hda_get_path_from_idx - get the path instance corresponding to the
- * given index number
- * @codec: the HDA codec
- * @idx: the path index
- */
-struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (idx <= 0 || idx > spec->paths.used)
-               return NULL;
-       return snd_array_elem(&spec->paths, idx - 1);
-}
-EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx);
-
-/* check whether the given DAC is already found in any existing paths */
-static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const struct nid_path *path;
-       int i;
-
-       snd_array_for_each(&spec->paths, i, path) {
-               if (path->path[0] == nid)
-                       return true;
-       }
-       return false;
-}
-
-/* check whether the given two widgets can be connected */
-static bool is_reachable_path(struct hda_codec *codec,
-                             hda_nid_t from_nid, hda_nid_t to_nid)
-{
-       if (!from_nid || !to_nid)
-               return false;
-       return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0;
-}
-
-/* nid, dir and idx */
-#define AMP_VAL_COMPARE_MASK   (0xffff | (1U << 18) | (0x0f << 19))
-
-/* check whether the given ctl is already assigned in any path elements */
-static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const struct nid_path *path;
-       int i;
-
-       val &= AMP_VAL_COMPARE_MASK;
-       snd_array_for_each(&spec->paths, i, path) {
-               if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val)
-                       return true;
-       }
-       return false;
-}
-
-/* check whether a control with the given (nid, dir, idx) was assigned */
-static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid,
-                             int dir, int idx, int type)
-{
-       unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
-       return is_ctl_used(codec, val, type);
-}
-
-static void print_nid_path(struct hda_codec *codec,
-                          const char *pfx, struct nid_path *path)
-{
-       char buf[40];
-       char *pos = buf;
-       int i;
-
-       *pos = 0;
-       for (i = 0; i < path->depth; i++)
-               pos += scnprintf(pos, sizeof(buf) - (pos - buf), "%s%02x",
-                                pos != buf ? ":" : "",
-                                path->path[i]);
-
-       codec_dbg(codec, "%s path: depth=%d '%s'\n", pfx, path->depth, buf);
-}
-
-/* called recursively */
-static bool __parse_nid_path(struct hda_codec *codec,
-                            hda_nid_t from_nid, hda_nid_t to_nid,
-                            int anchor_nid, struct nid_path *path,
-                            int depth)
-{
-       const hda_nid_t *conn;
-       int i, nums;
-
-       if (to_nid == anchor_nid)
-               anchor_nid = 0; /* anchor passed */
-       else if (to_nid == (hda_nid_t)(-anchor_nid))
-               return false; /* hit the exclusive nid */
-
-       nums = snd_hda_get_conn_list(codec, to_nid, &conn);
-       for (i = 0; i < nums; i++) {
-               if (conn[i] != from_nid) {
-                       /* special case: when from_nid is 0,
-                        * try to find an empty DAC
-                        */
-                       if (from_nid ||
-                           get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT ||
-                           is_dac_already_used(codec, conn[i]))
-                               continue;
-               }
-               /* anchor is not requested or already passed? */
-               if (anchor_nid <= 0)
-                       goto found;
-       }
-       if (depth >= MAX_NID_PATH_DEPTH)
-               return false;
-       for (i = 0; i < nums; i++) {
-               unsigned int type;
-               type = get_wcaps_type(get_wcaps(codec, conn[i]));
-               if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN ||
-                   type == AC_WID_PIN)
-                       continue;
-               if (__parse_nid_path(codec, from_nid, conn[i],
-                                    anchor_nid, path, depth + 1))
-                       goto found;
-       }
-       return false;
-
- found:
-       path->path[path->depth] = conn[i];
-       path->idx[path->depth + 1] = i;
-       if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX)
-               path->multi[path->depth + 1] = 1;
-       path->depth++;
-       return true;
-}
-
-/*
- * snd_hda_parse_nid_path - parse the widget path from the given nid to
- * the target nid
- * @codec: the HDA codec
- * @from_nid: the NID where the path start from
- * @to_nid: the NID where the path ends at
- * @anchor_nid: the anchor indication
- * @path: the path object to store the result
- *
- * Returns true if a matching path is found.
- *
- * The parsing behavior depends on parameters:
- * when @from_nid is 0, try to find an empty DAC;
- * when @anchor_nid is set to a positive value, only paths through the widget
- * with the given value are evaluated.
- * when @anchor_nid is set to a negative value, paths through the widget
- * with the negative of given value are excluded, only other paths are chosen.
- * when @anchor_nid is zero, no special handling about path selection.
- */
-static bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
-                           hda_nid_t to_nid, int anchor_nid,
-                           struct nid_path *path)
-{
-       if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) {
-               path->path[path->depth] = to_nid;
-               path->depth++;
-               return true;
-       }
-       return false;
-}
-
-/**
- * snd_hda_add_new_path - parse the path between the given NIDs and
- * add to the path list
- * @codec: the HDA codec
- * @from_nid: the NID where the path start from
- * @to_nid: the NID where the path ends at
- * @anchor_nid: the anchor indication, see snd_hda_parse_nid_path()
- *
- * If no valid path is found, returns NULL.
- */
-struct nid_path *
-snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
-                    hda_nid_t to_nid, int anchor_nid)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *path;
-
-       if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid))
-               return NULL;
-
-       /* check whether the path has been already added */
-       path = get_nid_path(codec, from_nid, to_nid, anchor_nid);
-       if (path)
-               return path;
-
-       path = snd_array_new(&spec->paths);
-       if (!path)
-               return NULL;
-       memset(path, 0, sizeof(*path));
-       if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path))
-               return path;
-       /* push back */
-       spec->paths.used--;
-       return NULL;
-}
-EXPORT_SYMBOL_GPL(snd_hda_add_new_path);
-
-/* clear the given path as invalid so that it won't be picked up later */
-static void invalidate_nid_path(struct hda_codec *codec, int idx)
-{
-       struct nid_path *path = snd_hda_get_path_from_idx(codec, idx);
-       if (!path)
-               return;
-       memset(path, 0, sizeof(*path));
-}
-
-/* return a DAC if paired to the given pin by codec driver */
-static hda_nid_t get_preferred_dac(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const hda_nid_t *list = spec->preferred_dacs;
-
-       if (!list)
-               return 0;
-       for (; *list; list += 2)
-               if (*list == pin)
-                       return list[1];
-       return 0;
-}
-
-/* look for an empty DAC slot */
-static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin,
-                             bool is_digital)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       bool cap_digital;
-       int i;
-
-       for (i = 0; i < spec->num_all_dacs; i++) {
-               hda_nid_t nid = spec->all_dacs[i];
-               if (!nid || is_dac_already_used(codec, nid))
-                       continue;
-               cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL);
-               if (is_digital != cap_digital)
-                       continue;
-               if (is_reachable_path(codec, nid, pin))
-                       return nid;
-       }
-       return 0;
-}
-
-/* replace the channels in the composed amp value with the given number */
-static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs)
-{
-       val &= ~(0x3U << 16);
-       val |= chs << 16;
-       return val;
-}
-
-static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1,
-                         hda_nid_t nid2, int dir)
-{
-       if (!(get_wcaps(codec, nid1) & (1 << (dir + 1))))
-               return !(get_wcaps(codec, nid2) & (1 << (dir + 1)));
-       return (query_amp_caps(codec, nid1, dir) ==
-               query_amp_caps(codec, nid2, dir));
-}
-
-/* look for a widget suitable for assigning a mute switch in the path */
-static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec,
-                                      struct nid_path *path)
-{
-       int i;
-
-       for (i = path->depth - 1; i >= 0; i--) {
-               if (nid_has_mute(codec, path->path[i], HDA_OUTPUT))
-                       return path->path[i];
-               if (i != path->depth - 1 && i != 0 &&
-                   nid_has_mute(codec, path->path[i], HDA_INPUT))
-                       return path->path[i];
-       }
-       return 0;
-}
-
-/* look for a widget suitable for assigning a volume ctl in the path */
-static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec,
-                                     struct nid_path *path)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-
-       for (i = path->depth - 1; i >= 0; i--) {
-               hda_nid_t nid = path->path[i];
-               if ((spec->out_vol_mask >> nid) & 1)
-                       continue;
-               if (nid_has_volume(codec, nid, HDA_OUTPUT))
-                       return nid;
-       }
-       return 0;
-}
-
-/*
- * path activation / deactivation
- */
-
-/* can have the amp-in capability? */
-static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx)
-{
-       hda_nid_t nid = path->path[idx];
-       unsigned int caps = get_wcaps(codec, nid);
-       unsigned int type = get_wcaps_type(caps);
-
-       if (!(caps & AC_WCAP_IN_AMP))
-               return false;
-       if (type == AC_WID_PIN && idx > 0) /* only for input pins */
-               return false;
-       return true;
-}
-
-/* can have the amp-out capability? */
-static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx)
-{
-       hda_nid_t nid = path->path[idx];
-       unsigned int caps = get_wcaps(codec, nid);
-       unsigned int type = get_wcaps_type(caps);
-
-       if (!(caps & AC_WCAP_OUT_AMP))
-               return false;
-       if (type == AC_WID_PIN && !idx) /* only for output pins */
-               return false;
-       return true;
-}
-
-/* check whether the given (nid,dir,idx) is active */
-static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid,
-                         unsigned int dir, unsigned int idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int type = get_wcaps_type(get_wcaps(codec, nid));
-       const struct nid_path *path;
-       int i, n;
-
-       if (nid == codec->core.afg)
-               return true;
-
-       snd_array_for_each(&spec->paths, n, path) {
-               if (!path->active)
-                       continue;
-               if (codec->power_save_node) {
-                       if (!path->stream_enabled)
-                               continue;
-                       /* ignore unplugged paths except for DAC/ADC */
-                       if (!(path->pin_enabled || path->pin_fixed) &&
-                           type != AC_WID_AUD_OUT && type != AC_WID_AUD_IN)
-                               continue;
-               }
-               for (i = 0; i < path->depth; i++) {
-                       if (path->path[i] == nid) {
-                               if (dir == HDA_OUTPUT || idx == -1 ||
-                                   path->idx[i] == idx)
-                                       return true;
-                               break;
-                       }
-               }
-       }
-       return false;
-}
-
-/* check whether the NID is referred by any active paths */
-#define is_active_nid_for_any(codec, nid) \
-       is_active_nid(codec, nid, HDA_OUTPUT, -1)
-
-/* get the default amp value for the target state */
-static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid,
-                                  int dir, unsigned int caps, bool enable)
-{
-       unsigned int val = 0;
-
-       if (caps & AC_AMPCAP_NUM_STEPS) {
-               /* set to 0dB */
-               if (enable)
-                       val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT;
-       }
-       if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
-               if (!enable)
-                       val |= HDA_AMP_MUTE;
-       }
-       return val;
-}
-
-/* is this a stereo widget or a stereo-to-mono mix? */
-static bool is_stereo_amps(struct hda_codec *codec, hda_nid_t nid, int dir)
-{
-       unsigned int wcaps = get_wcaps(codec, nid);
-       hda_nid_t conn;
-
-       if (wcaps & AC_WCAP_STEREO)
-               return true;
-       if (dir != HDA_INPUT || get_wcaps_type(wcaps) != AC_WID_AUD_MIX)
-               return false;
-       if (snd_hda_get_num_conns(codec, nid) != 1)
-               return false;
-       if (snd_hda_get_connections(codec, nid, &conn, 1) < 0)
-               return false;
-       return !!(get_wcaps(codec, conn) & AC_WCAP_STEREO);
-}
-
-/* initialize the amp value (only at the first time) */
-static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx)
-{
-       unsigned int caps = query_amp_caps(codec, nid, dir);
-       int val = get_amp_val_to_activate(codec, nid, dir, caps, false);
-
-       if (is_stereo_amps(codec, nid, dir))
-               snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val);
-       else
-               snd_hda_codec_amp_init(codec, nid, 0, dir, idx, 0xff, val);
-}
-
-/* update the amp, doing in stereo or mono depending on NID */
-static int update_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx,
-                     unsigned int mask, unsigned int val)
-{
-       if (is_stereo_amps(codec, nid, dir))
-               return snd_hda_codec_amp_stereo(codec, nid, dir, idx,
-                                               mask, val);
-       else
-               return snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
-                                               mask, val);
-}
-
-/* calculate amp value mask we can modify;
- * if the given amp is controlled by mixers, don't touch it
- */
-static unsigned int get_amp_mask_to_modify(struct hda_codec *codec,
-                                          hda_nid_t nid, int dir, int idx,
-                                          unsigned int caps)
-{
-       unsigned int mask = 0xff;
-
-       if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) {
-               if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL))
-                       mask &= ~0x80;
-       }
-       if (caps & AC_AMPCAP_NUM_STEPS) {
-               if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
-                   is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
-                       mask &= ~0x7f;
-       }
-       return mask;
-}
-
-static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir,
-                        int idx, int idx_to_check, bool enable)
-{
-       unsigned int caps;
-       unsigned int mask, val;
-
-       caps = query_amp_caps(codec, nid, dir);
-       val = get_amp_val_to_activate(codec, nid, dir, caps, enable);
-       mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps);
-       if (!mask)
-               return;
-
-       val &= mask;
-       update_amp(codec, nid, dir, idx, mask, val);
-}
-
-static void check_and_activate_amp(struct hda_codec *codec, hda_nid_t nid,
-                                  int dir, int idx, int idx_to_check,
-                                  bool enable)
-{
-       /* check whether the given amp is still used by others */
-       if (!enable && is_active_nid(codec, nid, dir, idx_to_check))
-               return;
-       activate_amp(codec, nid, dir, idx, idx_to_check, enable);
-}
-
-static void activate_amp_out(struct hda_codec *codec, struct nid_path *path,
-                            int i, bool enable)
-{
-       hda_nid_t nid = path->path[i];
-       init_amp(codec, nid, HDA_OUTPUT, 0);
-       check_and_activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable);
-}
-
-static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
-                           int i, bool enable, bool add_aamix)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const hda_nid_t *conn;
-       int n, nums, idx;
-       int type;
-       hda_nid_t nid = path->path[i];
-
-       nums = snd_hda_get_conn_list(codec, nid, &conn);
-       if (nums < 0)
-               return;
-       type = get_wcaps_type(get_wcaps(codec, nid));
-       if (type == AC_WID_PIN ||
-           (type == AC_WID_AUD_IN && codec->single_adc_amp)) {
-               nums = 1;
-               idx = 0;
-       } else
-               idx = path->idx[i];
-
-       for (n = 0; n < nums; n++)
-               init_amp(codec, nid, HDA_INPUT, n);
-
-       /* here is a little bit tricky in comparison with activate_amp_out();
-        * when aa-mixer is available, we need to enable the path as well
-        */
-       for (n = 0; n < nums; n++) {
-               if (n != idx) {
-                       if (conn[n] != spec->mixer_merge_nid)
-                               continue;
-                       /* when aamix is disabled, force to off */
-                       if (!add_aamix) {
-                               activate_amp(codec, nid, HDA_INPUT, n, n, false);
-                               continue;
-                       }
-               }
-               check_and_activate_amp(codec, nid, HDA_INPUT, n, idx, enable);
-       }
-}
-
-/* sync power of each widget in the given path */
-static hda_nid_t path_power_update(struct hda_codec *codec,
-                                  struct nid_path *path,
-                                  bool allow_powerdown)
-{
-       hda_nid_t nid, changed = 0;
-       int i, state, power;
-
-       for (i = 0; i < path->depth; i++) {
-               nid = path->path[i];
-               if (!(get_wcaps(codec, nid) & AC_WCAP_POWER))
-                       continue;
-               if (nid == codec->core.afg)
-                       continue;
-               if (!allow_powerdown || is_active_nid_for_any(codec, nid))
-                       state = AC_PWRST_D0;
-               else
-                       state = AC_PWRST_D3;
-               power = snd_hda_codec_read(codec, nid, 0,
-                                          AC_VERB_GET_POWER_STATE, 0);
-               if (power != (state | (state << 4))) {
-                       snd_hda_codec_write(codec, nid, 0,
-                                           AC_VERB_SET_POWER_STATE, state);
-                       changed = nid;
-                       /* all known codecs seem to be capable to handl
-                        * widgets state even in D3, so far.
-                        * if any new codecs need to restore the widget
-                        * states after D0 transition, call the function
-                        * below.
-                        */
-#if 0 /* disabled */
-                       if (state == AC_PWRST_D0)
-                               snd_hdac_regmap_sync_node(&codec->core, nid);
-#endif
-               }
-       }
-       return changed;
-}
-
-/* do sync with the last power state change */
-static void sync_power_state_change(struct hda_codec *codec, hda_nid_t nid)
-{
-       if (nid) {
-               msleep(10);
-               snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
-       }
-}
-
-/**
- * snd_hda_activate_path - activate or deactivate the given path
- * @codec: the HDA codec
- * @path: the path to activate/deactivate
- * @enable: flag to activate or not
- * @add_aamix: enable the input from aamix NID
- *
- * If @add_aamix is set, enable the input from aa-mix NID as well (if any).
- */
-void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
-                          bool enable, bool add_aamix)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-
-       path->active = enable;
-
-       /* make sure the widget is powered up */
-       if (enable && (spec->power_down_unused || codec->power_save_node))
-               path_power_update(codec, path, codec->power_save_node);
-
-       for (i = path->depth - 1; i >= 0; i--) {
-               hda_nid_t nid = path->path[i];
-
-               if (enable && path->multi[i])
-                       snd_hda_codec_write_cache(codec, nid, 0,
-                                           AC_VERB_SET_CONNECT_SEL,
-                                           path->idx[i]);
-               if (has_amp_in(codec, path, i))
-                       activate_amp_in(codec, path, i, enable, add_aamix);
-               if (has_amp_out(codec, path, i))
-                       activate_amp_out(codec, path, i, enable);
-       }
-}
-EXPORT_SYMBOL_GPL(snd_hda_activate_path);
-
-/* if the given path is inactive, put widgets into D3 (only if suitable) */
-static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (!(spec->power_down_unused || codec->power_save_node) || path->active)
-               return;
-       sync_power_state_change(codec, path_power_update(codec, path, true));
-}
-
-/* turn on/off EAPD on the given pin */
-static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->own_eapd_ctl ||
-           !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD))
-               return;
-       if (spec->keep_eapd_on && !enable)
-               return;
-       if (codec->inv_eapd)
-               enable = !enable;
-       snd_hda_codec_write_cache(codec, pin, 0,
-                                  AC_VERB_SET_EAPD_BTLENABLE,
-                                  enable ? 0x02 : 0x00);
-}
-
-/* re-initialize the path specified by the given path index */
-static void resume_path_from_idx(struct hda_codec *codec, int path_idx)
-{
-       struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
-       if (path)
-               snd_hda_activate_path(codec, path, path->active, false);
-}
-
-
-/*
- * Helper functions for creating mixer ctl elements
- */
-
-static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol);
-static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol);
-static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol);
-
-enum {
-       HDA_CTL_WIDGET_VOL,
-       HDA_CTL_WIDGET_MUTE,
-       HDA_CTL_BIND_MUTE,
-};
-static const struct snd_kcontrol_new control_templates[] = {
-       HDA_CODEC_VOLUME(NULL, 0, 0, 0),
-       /* only the put callback is replaced for handling the special mute */
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = hda_gen_mixer_mute_put, /* replaced */
-               .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = hda_gen_bind_mute_get,
-               .put = hda_gen_bind_mute_put, /* replaced */
-               .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0),
-       },
-};
-
-/* add dynamic controls from template */
-static struct snd_kcontrol_new *
-add_control(struct hda_gen_spec *spec, int type, const char *name,
-                      int cidx, unsigned long val)
-{
-       struct snd_kcontrol_new *knew;
-
-       knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]);
-       if (!knew)
-               return NULL;
-       knew->index = cidx;
-       if (get_amp_nid_(val))
-               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
-       if (knew->access == 0)
-               knew->access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
-       knew->private_value = val;
-       return knew;
-}
-
-static int add_control_with_pfx(struct hda_gen_spec *spec, int type,
-                               const char *pfx, const char *dir,
-                               const char *sfx, int cidx, unsigned long val)
-{
-       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       int len;
-
-       len = snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx);
-       if (snd_BUG_ON(len >= sizeof(name)))
-               return -EINVAL;
-       if (!add_control(spec, type, name, cidx, val))
-               return -ENOMEM;
-       return 0;
-}
-
-#define add_pb_vol_ctrl(spec, type, pfx, val)                  \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val)
-#define add_pb_sw_ctrl(spec, type, pfx, val)                   \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val)
-#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val)                  \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val)
-#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val)                   \
-       add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val)
-
-static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx,
-                      unsigned int chs, struct nid_path *path)
-{
-       unsigned int val;
-       if (!path)
-               return 0;
-       val = path->ctls[NID_PATH_VOL_CTL];
-       if (!val)
-               return 0;
-       val = amp_val_replace_channels(val, chs);
-       return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val);
-}
-
-/* return the channel bits suitable for the given path->ctls[] */
-static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path,
-                              int type)
-{
-       int chs = 1; /* mono (left only) */
-       if (path) {
-               hda_nid_t nid = get_amp_nid_(path->ctls[type]);
-               if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO))
-                       chs = 3; /* stereo */
-       }
-       return chs;
-}
-
-static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx,
-                         struct nid_path *path)
-{
-       int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL);
-       return add_vol_ctl(codec, pfx, cidx, chs, path);
-}
-
-/* create a mute-switch for the given mixer widget;
- * if it has multiple sources (e.g. DAC and loopback), create a bind-mute
- */
-static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx,
-                     unsigned int chs, struct nid_path *path)
-{
-       unsigned int val;
-       int type = HDA_CTL_WIDGET_MUTE;
-
-       if (!path)
-               return 0;
-       val = path->ctls[NID_PATH_MUTE_CTL];
-       if (!val)
-               return 0;
-       val = amp_val_replace_channels(val, chs);
-       if (get_amp_direction_(val) == HDA_INPUT) {
-               hda_nid_t nid = get_amp_nid_(val);
-               int nums = snd_hda_get_num_conns(codec, nid);
-               if (nums > 1) {
-                       type = HDA_CTL_BIND_MUTE;
-                       val |= nums << 19;
-               }
-       }
-       return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val);
-}
-
-static int add_stereo_sw(struct hda_codec *codec, const char *pfx,
-                                 int cidx, struct nid_path *path)
-{
-       int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL);
-       return add_sw_ctl(codec, pfx, cidx, chs, path);
-}
-
-/* playback mute control with the software mute bit check */
-static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (spec->auto_mute_via_amp) {
-               hda_nid_t nid = get_amp_nid(kcontrol);
-               bool enabled = !((spec->mute_bits >> nid) & 1);
-               ucontrol->value.integer.value[0] &= enabled;
-               ucontrol->value.integer.value[1] &= enabled;
-       }
-}
-
-static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol)
-{
-       sync_auto_mute_bits(kcontrol, ucontrol);
-       return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-}
-
-/*
- * Bound mute controls
- */
-#define AMP_VAL_IDX_SHIFT      19
-#define AMP_VAL_IDX_MASK       (0x0f<<19)
-
-static int hda_gen_bind_mute_get(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned long pval;
-       int err;
-
-       mutex_lock(&codec->control_mutex);
-       pval = kcontrol->private_value;
-       kcontrol->private_value = pval & ~AMP_VAL_IDX_MASK; /* index 0 */
-       err = snd_hda_mixer_amp_switch_get(kcontrol, ucontrol);
-       kcontrol->private_value = pval;
-       mutex_unlock(&codec->control_mutex);
-       return err;
-}
-
-static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned long pval;
-       int i, indices, err = 0, change = 0;
-
-       sync_auto_mute_bits(kcontrol, ucontrol);
-
-       mutex_lock(&codec->control_mutex);
-       pval = kcontrol->private_value;
-       indices = (pval & AMP_VAL_IDX_MASK) >> AMP_VAL_IDX_SHIFT;
-       for (i = 0; i < indices; i++) {
-               kcontrol->private_value = (pval & ~AMP_VAL_IDX_MASK) |
-                       (i << AMP_VAL_IDX_SHIFT);
-               err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-               if (err < 0)
-                       break;
-               change |= err;
-       }
-       kcontrol->private_value = pval;
-       mutex_unlock(&codec->control_mutex);
-       return err < 0 ? err : change;
-}
-
-/* any ctl assigned to the path with the given index? */
-static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type)
-{
-       struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx);
-       return path && path->ctls[ctl_type];
-}
-
-static const char * const channel_name[] = {
-       "Front", "Surround", "CLFE", "Side", "Back",
-};
-
-/* give some appropriate ctl name prefix for the given line out channel */
-static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
-                                   int *index, int ctl_type)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-
-       *index = 0;
-       if (cfg->line_outs == 1 && !spec->multi_ios &&
-           !codec->force_pin_prefix &&
-           !cfg->hp_outs && !cfg->speaker_outs)
-               return spec->vmaster_mute.hook ? "PCM" : "Master";
-
-       /* if there is really a single DAC used in the whole output paths,
-        * use it master (or "PCM" if a vmaster hook is present)
-        */
-       if (spec->multiout.num_dacs == 1 && !spec->mixer_nid &&
-           !codec->force_pin_prefix &&
-           !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0])
-               return spec->vmaster_mute.hook ? "PCM" : "Master";
-
-       /* multi-io channels */
-       if (ch >= cfg->line_outs)
-               goto fixed_name;
-
-       switch (cfg->line_out_type) {
-       case AUTO_PIN_SPEAKER_OUT:
-               /* if the primary channel vol/mute is shared with HP volume,
-                * don't name it as Speaker
-                */
-               if (!ch && cfg->hp_outs &&
-                   !path_has_mixer(codec, spec->hp_paths[0], ctl_type))
-                       break;
-               if (cfg->line_outs == 1)
-                       return "Speaker";
-               if (cfg->line_outs == 2)
-                       return ch ? "Bass Speaker" : "Speaker";
-               break;
-       case AUTO_PIN_HP_OUT:
-               /* if the primary channel vol/mute is shared with spk volume,
-                * don't name it as Headphone
-                */
-               if (!ch && cfg->speaker_outs &&
-                   !path_has_mixer(codec, spec->speaker_paths[0], ctl_type))
-                       break;
-               /* for multi-io case, only the primary out */
-               if (ch && spec->multi_ios)
-                       break;
-               *index = ch;
-               return "Headphone";
-       case AUTO_PIN_LINE_OUT:
-               /* This deals with the case where one HP or one Speaker or
-                * one HP + one Speaker need to share the DAC with LO
-                */
-               if (!ch) {
-                       bool hp_lo_shared = false, spk_lo_shared = false;
-
-                       if (cfg->speaker_outs)
-                               spk_lo_shared = !path_has_mixer(codec,
-                                                               spec->speaker_paths[0], ctl_type);
-                       if (cfg->hp_outs)
-                               hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type);
-                       if (hp_lo_shared && spk_lo_shared)
-                               return spec->vmaster_mute.hook ? "PCM" : "Master";
-                       if (hp_lo_shared)
-                               return "Headphone+LO";
-                       if (spk_lo_shared)
-                               return "Speaker+LO";
-               }
-       }
-
-       /* for a single channel output, we don't have to name the channel */
-       if (cfg->line_outs == 1 && !spec->multi_ios)
-               return "Line Out";
-
- fixed_name:
-       if (ch >= ARRAY_SIZE(channel_name)) {
-               snd_BUG();
-               return "PCM";
-       }
-
-       return channel_name[ch];
-}
-
-/*
- * Parse output paths
- */
-
-/* badness definition */
-enum {
-       /* No primary DAC is found for the main output */
-       BAD_NO_PRIMARY_DAC = 0x10000,
-       /* No DAC is found for the extra output */
-       BAD_NO_DAC = 0x4000,
-       /* No possible multi-ios */
-       BAD_MULTI_IO = 0x120,
-       /* No individual DAC for extra output */
-       BAD_NO_EXTRA_DAC = 0x102,
-       /* No individual DAC for extra surrounds */
-       BAD_NO_EXTRA_SURR_DAC = 0x101,
-       /* Primary DAC shared with main surrounds */
-       BAD_SHARED_SURROUND = 0x100,
-       /* No independent HP possible */
-       BAD_NO_INDEP_HP = 0x10,
-       /* Primary DAC shared with main CLFE */
-       BAD_SHARED_CLFE = 0x10,
-       /* Primary DAC shared with extra surrounds */
-       BAD_SHARED_EXTRA_SURROUND = 0x10,
-       /* Volume widget is shared */
-       BAD_SHARED_VOL = 0x10,
-};
-
-/* look for widgets in the given path which are appropriate for
- * volume and mute controls, and assign the values to ctls[].
- *
- * When no appropriate widget is found in the path, the badness value
- * is incremented depending on the situation.  The function returns the
- * total badness for both volume and mute controls.
- */
-static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       hda_nid_t nid;
-       unsigned int val;
-       int badness = 0;
-
-       if (!path)
-               return BAD_SHARED_VOL * 2;
-
-       if (path->ctls[NID_PATH_VOL_CTL] ||
-           path->ctls[NID_PATH_MUTE_CTL])
-               return 0; /* already evaluated */
-
-       nid = look_for_out_vol_nid(codec, path);
-       if (nid) {
-               val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-               if (spec->dac_min_mute)
-                       val |= HDA_AMP_VAL_MIN_MUTE;
-               if (is_ctl_used(codec, val, NID_PATH_VOL_CTL))
-                       badness += BAD_SHARED_VOL;
-               else
-                       path->ctls[NID_PATH_VOL_CTL] = val;
-       } else
-               badness += BAD_SHARED_VOL;
-       nid = look_for_out_mute_nid(codec, path);
-       if (nid) {
-               unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid));
-               if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT ||
-                   nid_has_mute(codec, nid, HDA_OUTPUT))
-                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-               else
-                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT);
-               if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL))
-                       badness += BAD_SHARED_VOL;
-               else
-                       path->ctls[NID_PATH_MUTE_CTL] = val;
-       } else
-               badness += BAD_SHARED_VOL;
-       return badness;
-}
-
-const struct badness_table hda_main_out_badness = {
-       .no_primary_dac = BAD_NO_PRIMARY_DAC,
-       .no_dac = BAD_NO_DAC,
-       .shared_primary = BAD_NO_PRIMARY_DAC,
-       .shared_surr = BAD_SHARED_SURROUND,
-       .shared_clfe = BAD_SHARED_CLFE,
-       .shared_surr_main = BAD_SHARED_SURROUND,
-};
-EXPORT_SYMBOL_GPL(hda_main_out_badness);
-
-const struct badness_table hda_extra_out_badness = {
-       .no_primary_dac = BAD_NO_DAC,
-       .no_dac = BAD_NO_DAC,
-       .shared_primary = BAD_NO_EXTRA_DAC,
-       .shared_surr = BAD_SHARED_EXTRA_SURROUND,
-       .shared_clfe = BAD_SHARED_EXTRA_SURROUND,
-       .shared_surr_main = BAD_NO_EXTRA_SURR_DAC,
-};
-EXPORT_SYMBOL_GPL(hda_extra_out_badness);
-
-/* get the DAC of the primary output corresponding to the given array index */
-static hda_nid_t get_primary_out(struct hda_codec *codec, int idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-
-       if (cfg->line_outs > idx)
-               return spec->private_dac_nids[idx];
-       idx -= cfg->line_outs;
-       if (spec->multi_ios > idx)
-               return spec->multi_io[idx].dac;
-       return 0;
-}
-
-/* return the DAC if it's reachable, otherwise zero */
-static inline hda_nid_t try_dac(struct hda_codec *codec,
-                               hda_nid_t dac, hda_nid_t pin)
-{
-       return is_reachable_path(codec, dac, pin) ? dac : 0;
-}
-
-/* try to assign DACs to pins and return the resultant badness */
-static int try_assign_dacs(struct hda_codec *codec, int num_outs,
-                          const hda_nid_t *pins, hda_nid_t *dacs,
-                          int *path_idx,
-                          const struct badness_table *bad)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i, j;
-       int badness = 0;
-       hda_nid_t dac;
-
-       if (!num_outs)
-               return 0;
-
-       for (i = 0; i < num_outs; i++) {
-               struct nid_path *path;
-               hda_nid_t pin = pins[i];
-
-               if (!spec->preferred_dacs) {
-                       path = snd_hda_get_path_from_idx(codec, path_idx[i]);
-                       if (path) {
-                               badness += assign_out_path_ctls(codec, path);
-                               continue;
-                       }
-               }
-
-               dacs[i] = get_preferred_dac(codec, pin);
-               if (dacs[i]) {
-                       if (is_dac_already_used(codec, dacs[i]))
-                               badness += bad->shared_primary;
-               } else if (spec->preferred_dacs) {
-                       badness += BAD_NO_PRIMARY_DAC;
-               }
-
-               if (!dacs[i])
-                       dacs[i] = look_for_dac(codec, pin, false);
-               if (!dacs[i] && !i) {
-                       /* try to steal the DAC of surrounds for the front */
-                       for (j = 1; j < num_outs; j++) {
-                               if (is_reachable_path(codec, dacs[j], pin)) {
-                                       dacs[0] = dacs[j];
-                                       dacs[j] = 0;
-                                       invalidate_nid_path(codec, path_idx[j]);
-                                       path_idx[j] = 0;
-                                       break;
-                               }
-                       }
-               }
-               dac = dacs[i];
-               if (!dac) {
-                       if (num_outs > 2)
-                               dac = try_dac(codec, get_primary_out(codec, i), pin);
-                       if (!dac)
-                               dac = try_dac(codec, dacs[0], pin);
-                       if (!dac)
-                               dac = try_dac(codec, get_primary_out(codec, i), pin);
-                       if (dac) {
-                               if (!i)
-                                       badness += bad->shared_primary;
-                               else if (i == 1)
-                                       badness += bad->shared_surr;
-                               else
-                                       badness += bad->shared_clfe;
-                       } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) {
-                               dac = spec->private_dac_nids[0];
-                               badness += bad->shared_surr_main;
-                       } else if (!i)
-                               badness += bad->no_primary_dac;
-                       else
-                               badness += bad->no_dac;
-               }
-               if (!dac)
-                       continue;
-               path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid);
-               if (!path && !i && spec->mixer_nid) {
-                       /* try with aamix */
-                       path = snd_hda_add_new_path(codec, dac, pin, 0);
-               }
-               if (!path) {
-                       dacs[i] = 0;
-                       badness += bad->no_dac;
-               } else {
-                       /* print_nid_path(codec, "output", path); */
-                       path->active = true;
-                       path_idx[i] = snd_hda_get_path_idx(codec, path);
-                       badness += assign_out_path_ctls(codec, path);
-               }
-       }
-
-       return badness;
-}
-
-/* return NID if the given pin has only a single connection to a certain DAC */
-static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-       hda_nid_t nid_found = 0;
-
-       for (i = 0; i < spec->num_all_dacs; i++) {
-               hda_nid_t nid = spec->all_dacs[i];
-               if (!nid || is_dac_already_used(codec, nid))
-                       continue;
-               if (is_reachable_path(codec, nid, pin)) {
-                       if (nid_found)
-                               return 0;
-                       nid_found = nid;
-               }
-       }
-       return nid_found;
-}
-
-/* check whether the given pin can be a multi-io pin */
-static bool can_be_multiio_pin(struct hda_codec *codec,
-                              unsigned int location, hda_nid_t nid)
-{
-       unsigned int defcfg, caps;
-
-       defcfg = snd_hda_codec_get_pincfg(codec, nid);
-       if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX)
-               return false;
-       if (location && get_defcfg_location(defcfg) != location)
-               return false;
-       caps = snd_hda_query_pin_caps(codec, nid);
-       if (!(caps & AC_PINCAP_OUT))
-               return false;
-       return true;
-}
-
-/* count the number of input pins that are capable to be multi-io */
-static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
-       unsigned int location = get_defcfg_location(defcfg);
-       int type, i;
-       int num_pins = 0;
-
-       for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
-               for (i = 0; i < cfg->num_inputs; i++) {
-                       if (cfg->inputs[i].type != type)
-                               continue;
-                       if (can_be_multiio_pin(codec, location,
-                                              cfg->inputs[i].pin))
-                               num_pins++;
-               }
-       }
-       return num_pins;
-}
-
-/*
- * multi-io helper
- *
- * When hardwired is set, try to fill ony hardwired pins, and returns
- * zero if any pins are filled, non-zero if nothing found.
- * When hardwired is off, try to fill possible input pins, and returns
- * the badness value.
- */
-static int fill_multi_ios(struct hda_codec *codec,
-                         hda_nid_t reference_pin,
-                         bool hardwired)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int type, i, j, num_pins, old_pins;
-       unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin);
-       unsigned int location = get_defcfg_location(defcfg);
-       int badness = 0;
-       struct nid_path *path;
-
-       old_pins = spec->multi_ios;
-       if (old_pins >= 2)
-               goto end_fill;
-
-       num_pins = count_multiio_pins(codec, reference_pin);
-       if (num_pins < 2)
-               goto end_fill;
-
-       for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) {
-               for (i = 0; i < cfg->num_inputs; i++) {
-                       hda_nid_t nid = cfg->inputs[i].pin;
-                       hda_nid_t dac = 0;
-
-                       if (cfg->inputs[i].type != type)
-                               continue;
-                       if (!can_be_multiio_pin(codec, location, nid))
-                               continue;
-                       for (j = 0; j < spec->multi_ios; j++) {
-                               if (nid == spec->multi_io[j].pin)
-                                       break;
-                       }
-                       if (j < spec->multi_ios)
-                               continue;
-
-                       if (hardwired)
-                               dac = get_dac_if_single(codec, nid);
-                       else if (!dac)
-                               dac = look_for_dac(codec, nid, false);
-                       if (!dac) {
-                               badness++;
-                               continue;
-                       }
-                       path = snd_hda_add_new_path(codec, dac, nid,
-                                                   -spec->mixer_nid);
-                       if (!path) {
-                               badness++;
-                               continue;
-                       }
-                       /* print_nid_path(codec, "multiio", path); */
-                       spec->multi_io[spec->multi_ios].pin = nid;
-                       spec->multi_io[spec->multi_ios].dac = dac;
-                       spec->out_paths[cfg->line_outs + spec->multi_ios] =
-                               snd_hda_get_path_idx(codec, path);
-                       spec->multi_ios++;
-                       if (spec->multi_ios >= 2)
-                               break;
-               }
-       }
- end_fill:
-       if (badness)
-               badness = BAD_MULTI_IO;
-       if (old_pins == spec->multi_ios) {
-               if (hardwired)
-                       return 1; /* nothing found */
-               else
-                       return badness; /* no badness if nothing found */
-       }
-       if (!hardwired && spec->multi_ios < 2) {
-               /* cancel newly assigned paths */
-               spec->paths.used -= spec->multi_ios - old_pins;
-               spec->multi_ios = old_pins;
-               return badness;
-       }
-
-       /* assign volume and mute controls */
-       for (i = old_pins; i < spec->multi_ios; i++) {
-               path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]);
-               badness += assign_out_path_ctls(codec, path);
-       }
-
-       return badness;
-}
-
-/* map DACs for all pins in the list if they are single connections */
-static bool map_singles(struct hda_codec *codec, int outs,
-                       const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-       bool found = false;
-       for (i = 0; i < outs; i++) {
-               struct nid_path *path;
-               hda_nid_t dac;
-               if (dacs[i])
-                       continue;
-               dac = get_dac_if_single(codec, pins[i]);
-               if (!dac)
-                       continue;
-               path = snd_hda_add_new_path(codec, dac, pins[i],
-                                           -spec->mixer_nid);
-               if (!path && !i && spec->mixer_nid)
-                       path = snd_hda_add_new_path(codec, dac, pins[i], 0);
-               if (path) {
-                       dacs[i] = dac;
-                       found = true;
-                       /* print_nid_path(codec, "output", path); */
-                       path->active = true;
-                       path_idx[i] = snd_hda_get_path_idx(codec, path);
-               }
-       }
-       return found;
-}
-
-static inline bool has_aamix_out_paths(struct hda_gen_spec *spec)
-{
-       return spec->aamix_out_paths[0] || spec->aamix_out_paths[1] ||
-               spec->aamix_out_paths[2];
-}
-
-/* create a new path including aamix if available, and return its index */
-static int check_aamix_out_path(struct hda_codec *codec, int path_idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *path;
-       hda_nid_t path_dac, dac, pin;
-
-       path = snd_hda_get_path_from_idx(codec, path_idx);
-       if (!path || !path->depth ||
-           is_nid_contained(path, spec->mixer_nid))
-               return 0;
-       path_dac = path->path[0];
-       dac = spec->private_dac_nids[0];
-       pin = path->path[path->depth - 1];
-       path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid);
-       if (!path) {
-               if (dac != path_dac)
-                       dac = path_dac;
-               else if (spec->multiout.hp_out_nid[0])
-                       dac = spec->multiout.hp_out_nid[0];
-               else if (spec->multiout.extra_out_nid[0])
-                       dac = spec->multiout.extra_out_nid[0];
-               else
-                       dac = 0;
-               if (dac)
-                       path = snd_hda_add_new_path(codec, dac, pin,
-                                                   spec->mixer_nid);
-       }
-       if (!path)
-               return 0;
-       /* print_nid_path(codec, "output-aamix", path); */
-       path->active = false; /* unused as default */
-       path->pin_fixed = true; /* static route */
-       return snd_hda_get_path_idx(codec, path);
-}
-
-/* check whether the independent HP is available with the current config */
-static bool indep_hp_possible(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       struct nid_path *path;
-       int i, idx;
-
-       if (cfg->line_out_type == AUTO_PIN_HP_OUT)
-               idx = spec->out_paths[0];
-       else
-               idx = spec->hp_paths[0];
-       path = snd_hda_get_path_from_idx(codec, idx);
-       if (!path)
-               return false;
-
-       /* assume no path conflicts unless aamix is involved */
-       if (!spec->mixer_nid || !is_nid_contained(path, spec->mixer_nid))
-               return true;
-
-       /* check whether output paths contain aamix */
-       for (i = 0; i < cfg->line_outs; i++) {
-               if (spec->out_paths[i] == idx)
-                       break;
-               path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
-               if (path && is_nid_contained(path, spec->mixer_nid))
-                       return false;
-       }
-       for (i = 0; i < cfg->speaker_outs; i++) {
-               path = snd_hda_get_path_from_idx(codec, spec->speaker_paths[i]);
-               if (path && is_nid_contained(path, spec->mixer_nid))
-                       return false;
-       }
-
-       return true;
-}
-
-/* fill the empty entries in the dac array for speaker/hp with the
- * shared dac pointed by the paths
- */
-static void refill_shared_dacs(struct hda_codec *codec, int num_outs,
-                              hda_nid_t *dacs, int *path_idx)
-{
-       struct nid_path *path;
-       int i;
-
-       for (i = 0; i < num_outs; i++) {
-               if (dacs[i])
-                       continue;
-               path = snd_hda_get_path_from_idx(codec, path_idx[i]);
-               if (!path)
-                       continue;
-               dacs[i] = path->path[0];
-       }
-}
-
-/* fill in the dac_nids table from the parsed pin configuration */
-static int fill_and_eval_dacs(struct hda_codec *codec,
-                             bool fill_hardwired,
-                             bool fill_mio_first)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i, err, badness;
-
-       /* set num_dacs once to full for look_for_dac() */
-       spec->multiout.num_dacs = cfg->line_outs;
-       spec->multiout.dac_nids = spec->private_dac_nids;
-       memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids));
-       memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid));
-       memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid));
-       spec->multi_ios = 0;
-       snd_array_free(&spec->paths);
-
-       /* clear path indices */
-       memset(spec->out_paths, 0, sizeof(spec->out_paths));
-       memset(spec->hp_paths, 0, sizeof(spec->hp_paths));
-       memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths));
-       memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths));
-       memset(spec->digout_paths, 0, sizeof(spec->digout_paths));
-       memset(spec->input_paths, 0, sizeof(spec->input_paths));
-       memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths));
-       memset(&spec->digin_path, 0, sizeof(spec->digin_path));
-
-       badness = 0;
-
-       /* fill hard-wired DACs first */
-       if (fill_hardwired) {
-               bool mapped;
-               do {
-                       mapped = map_singles(codec, cfg->line_outs,
-                                            cfg->line_out_pins,
-                                            spec->private_dac_nids,
-                                            spec->out_paths);
-                       mapped |= map_singles(codec, cfg->hp_outs,
-                                             cfg->hp_pins,
-                                             spec->multiout.hp_out_nid,
-                                             spec->hp_paths);
-                       mapped |= map_singles(codec, cfg->speaker_outs,
-                                             cfg->speaker_pins,
-                                             spec->multiout.extra_out_nid,
-                                             spec->speaker_paths);
-                       if (!spec->no_multi_io &&
-                           fill_mio_first && cfg->line_outs == 1 &&
-                           cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-                               err = fill_multi_ios(codec, cfg->line_out_pins[0], true);
-                               if (!err)
-                                       mapped = true;
-                       }
-               } while (mapped);
-       }
-
-       badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins,
-                                  spec->private_dac_nids, spec->out_paths,
-                                  spec->main_out_badness);
-
-       if (!spec->no_multi_io && fill_mio_first &&
-           cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-               /* try to fill multi-io first */
-               err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
-               if (err < 0)
-                       return err;
-               /* we don't count badness at this stage yet */
-       }
-
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
-               err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins,
-                                     spec->multiout.hp_out_nid,
-                                     spec->hp_paths,
-                                     spec->extra_out_badness);
-               if (err < 0)
-                       return err;
-               badness += err;
-       }
-       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-               err = try_assign_dacs(codec, cfg->speaker_outs,
-                                     cfg->speaker_pins,
-                                     spec->multiout.extra_out_nid,
-                                     spec->speaker_paths,
-                                     spec->extra_out_badness);
-               if (err < 0)
-                       return err;
-               badness += err;
-       }
-       if (!spec->no_multi_io &&
-           cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-               err = fill_multi_ios(codec, cfg->line_out_pins[0], false);
-               if (err < 0)
-                       return err;
-               badness += err;
-       }
-
-       if (spec->mixer_nid) {
-               spec->aamix_out_paths[0] =
-                       check_aamix_out_path(codec, spec->out_paths[0]);
-               if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-                       spec->aamix_out_paths[1] =
-                               check_aamix_out_path(codec, spec->hp_paths[0]);
-               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
-                       spec->aamix_out_paths[2] =
-                               check_aamix_out_path(codec, spec->speaker_paths[0]);
-       }
-
-       if (!spec->no_multi_io &&
-           cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT)
-               if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2)
-                       spec->multi_ios = 1; /* give badness */
-
-       /* re-count num_dacs and squash invalid entries */
-       spec->multiout.num_dacs = 0;
-       for (i = 0; i < cfg->line_outs; i++) {
-               if (spec->private_dac_nids[i])
-                       spec->multiout.num_dacs++;
-               else {
-                       memmove(spec->private_dac_nids + i,
-                               spec->private_dac_nids + i + 1,
-                               sizeof(hda_nid_t) * (cfg->line_outs - i - 1));
-                       spec->private_dac_nids[cfg->line_outs - 1] = 0;
-               }
-       }
-
-       spec->ext_channel_count = spec->min_channel_count =
-               spec->multiout.num_dacs * 2;
-
-       if (spec->multi_ios == 2) {
-               for (i = 0; i < 2; i++)
-                       spec->private_dac_nids[spec->multiout.num_dacs++] =
-                               spec->multi_io[i].dac;
-       } else if (spec->multi_ios) {
-               spec->multi_ios = 0;
-               badness += BAD_MULTI_IO;
-       }
-
-       if (spec->indep_hp && !indep_hp_possible(codec))
-               badness += BAD_NO_INDEP_HP;
-
-       /* re-fill the shared DAC for speaker / headphone */
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-               refill_shared_dacs(codec, cfg->hp_outs,
-                                  spec->multiout.hp_out_nid,
-                                  spec->hp_paths);
-       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
-               refill_shared_dacs(codec, cfg->speaker_outs,
-                                  spec->multiout.extra_out_nid,
-                                  spec->speaker_paths);
-
-       return badness;
-}
-
-#define DEBUG_BADNESS
-
-#ifdef DEBUG_BADNESS
-#define debug_badness(fmt, ...)                                                \
-       codec_dbg(codec, fmt, ##__VA_ARGS__)
-#else
-#define debug_badness(fmt, ...)                                                \
-       do { if (0) codec_dbg(codec, fmt, ##__VA_ARGS__); } while (0)
-#endif
-
-#ifdef DEBUG_BADNESS
-static inline void print_nid_path_idx(struct hda_codec *codec,
-                                     const char *pfx, int idx)
-{
-       struct nid_path *path;
-
-       path = snd_hda_get_path_from_idx(codec, idx);
-       if (path)
-               print_nid_path(codec, pfx, path);
-}
-
-static void debug_show_configs(struct hda_codec *codec,
-                              struct auto_pin_cfg *cfg)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       static const char * const lo_type[3] = { "LO", "SP", "HP" };
-       int i;
-
-       debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n",
-                     cfg->line_out_pins[0], cfg->line_out_pins[1],
-                     cfg->line_out_pins[2], cfg->line_out_pins[3],
-                     spec->multiout.dac_nids[0],
-                     spec->multiout.dac_nids[1],
-                     spec->multiout.dac_nids[2],
-                     spec->multiout.dac_nids[3],
-                     lo_type[cfg->line_out_type]);
-       for (i = 0; i < cfg->line_outs; i++)
-               print_nid_path_idx(codec, "  out", spec->out_paths[i]);
-       if (spec->multi_ios > 0)
-               debug_badness("multi_ios(%d) = %x/%x : %x/%x\n",
-                             spec->multi_ios,
-                             spec->multi_io[0].pin, spec->multi_io[1].pin,
-                             spec->multi_io[0].dac, spec->multi_io[1].dac);
-       for (i = 0; i < spec->multi_ios; i++)
-               print_nid_path_idx(codec, "  mio",
-                                  spec->out_paths[cfg->line_outs + i]);
-       if (cfg->hp_outs)
-               debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
-                     cfg->hp_pins[0], cfg->hp_pins[1],
-                     cfg->hp_pins[2], cfg->hp_pins[3],
-                     spec->multiout.hp_out_nid[0],
-                     spec->multiout.hp_out_nid[1],
-                     spec->multiout.hp_out_nid[2],
-                     spec->multiout.hp_out_nid[3]);
-       for (i = 0; i < cfg->hp_outs; i++)
-               print_nid_path_idx(codec, "  hp ", spec->hp_paths[i]);
-       if (cfg->speaker_outs)
-               debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n",
-                     cfg->speaker_pins[0], cfg->speaker_pins[1],
-                     cfg->speaker_pins[2], cfg->speaker_pins[3],
-                     spec->multiout.extra_out_nid[0],
-                     spec->multiout.extra_out_nid[1],
-                     spec->multiout.extra_out_nid[2],
-                     spec->multiout.extra_out_nid[3]);
-       for (i = 0; i < cfg->speaker_outs; i++)
-               print_nid_path_idx(codec, "  spk", spec->speaker_paths[i]);
-       for (i = 0; i < 3; i++)
-               print_nid_path_idx(codec, "  mix", spec->aamix_out_paths[i]);
-}
-#else
-#define debug_show_configs(codec, cfg) /* NOP */
-#endif
-
-/* find all available DACs of the codec */
-static void fill_all_dac_nids(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       spec->num_all_dacs = 0;
-       memset(spec->all_dacs, 0, sizeof(spec->all_dacs));
-       for_each_hda_codec_node(nid, codec) {
-               if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT)
-                       continue;
-               if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) {
-                       codec_err(codec, "Too many DACs!\n");
-                       break;
-               }
-               spec->all_dacs[spec->num_all_dacs++] = nid;
-       }
-}
-
-static int parse_output_paths(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       struct auto_pin_cfg *best_cfg;
-       unsigned int val;
-       int best_badness = INT_MAX;
-       int badness;
-       bool fill_hardwired = true, fill_mio_first = true;
-       bool best_wired = true, best_mio = true;
-       bool hp_spk_swapped = false;
-
-       best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL);
-       if (!best_cfg)
-               return -ENOMEM;
-       *best_cfg = *cfg;
-
-       for (;;) {
-               badness = fill_and_eval_dacs(codec, fill_hardwired,
-                                            fill_mio_first);
-               if (badness < 0) {
-                       kfree(best_cfg);
-                       return badness;
-               }
-               debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n",
-                             cfg->line_out_type, fill_hardwired, fill_mio_first,
-                             badness);
-               debug_show_configs(codec, cfg);
-               if (badness < best_badness) {
-                       best_badness = badness;
-                       *best_cfg = *cfg;
-                       best_wired = fill_hardwired;
-                       best_mio = fill_mio_first;
-               }
-               if (!badness)
-                       break;
-               fill_mio_first = !fill_mio_first;
-               if (!fill_mio_first)
-                       continue;
-               fill_hardwired = !fill_hardwired;
-               if (!fill_hardwired)
-                       continue;
-               if (hp_spk_swapped)
-                       break;
-               hp_spk_swapped = true;
-               if (cfg->speaker_outs > 0 &&
-                   cfg->line_out_type == AUTO_PIN_HP_OUT) {
-                       cfg->hp_outs = cfg->line_outs;
-                       memcpy(cfg->hp_pins, cfg->line_out_pins,
-                              sizeof(cfg->hp_pins));
-                       cfg->line_outs = cfg->speaker_outs;
-                       memcpy(cfg->line_out_pins, cfg->speaker_pins,
-                              sizeof(cfg->speaker_pins));
-                       cfg->speaker_outs = 0;
-                       memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins));
-                       cfg->line_out_type = AUTO_PIN_SPEAKER_OUT;
-                       fill_hardwired = true;
-                       continue;
-               }
-               if (cfg->hp_outs > 0 &&
-                   cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
-                       cfg->speaker_outs = cfg->line_outs;
-                       memcpy(cfg->speaker_pins, cfg->line_out_pins,
-                              sizeof(cfg->speaker_pins));
-                       cfg->line_outs = cfg->hp_outs;
-                       memcpy(cfg->line_out_pins, cfg->hp_pins,
-                              sizeof(cfg->hp_pins));
-                       cfg->hp_outs = 0;
-                       memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
-                       cfg->line_out_type = AUTO_PIN_HP_OUT;
-                       fill_hardwired = true;
-                       continue;
-               }
-               break;
-       }
-
-       if (badness) {
-               debug_badness("==> restoring best_cfg\n");
-               *cfg = *best_cfg;
-               fill_and_eval_dacs(codec, best_wired, best_mio);
-       }
-       debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n",
-                     cfg->line_out_type, best_wired, best_mio);
-       debug_show_configs(codec, cfg);
-
-       if (cfg->line_out_pins[0]) {
-               struct nid_path *path;
-               path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]);
-               if (path)
-                       spec->vmaster_nid = look_for_out_vol_nid(codec, path);
-               if (spec->vmaster_nid) {
-                       snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid,
-                                               HDA_OUTPUT, spec->vmaster_tlv);
-                       if (spec->dac_min_mute)
-                               spec->vmaster_tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] |= TLV_DB_SCALE_MUTE;
-               }
-       }
-
-       /* set initial pinctl targets */
-       if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT)
-               val = PIN_HP;
-       else
-               val = PIN_OUT;
-       set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val);
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-               set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP);
-       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-               val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT;
-               set_pin_targets(codec, cfg->speaker_outs,
-                               cfg->speaker_pins, val);
-       }
-
-       /* clear indep_hp flag if not available */
-       if (spec->indep_hp && !indep_hp_possible(codec))
-               spec->indep_hp = 0;
-
-       kfree(best_cfg);
-       return 0;
-}
-
-/* add playback controls from the parsed DAC table */
-static int create_multi_out_ctls(struct hda_codec *codec,
-                                const struct auto_pin_cfg *cfg)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i, err, noutputs;
-
-       noutputs = cfg->line_outs;
-       if (spec->multi_ios > 0 && cfg->line_outs < 3)
-               noutputs += spec->multi_ios;
-
-       for (i = 0; i < noutputs; i++) {
-               const char *name;
-               int index;
-               struct nid_path *path;
-
-               path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]);
-               if (!path)
-                       continue;
-
-               name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL);
-               if (!name || !strcmp(name, "CLFE")) {
-                       /* Center/LFE */
-                       err = add_vol_ctl(codec, "Center", 0, 1, path);
-                       if (err < 0)
-                               return err;
-                       err = add_vol_ctl(codec, "LFE", 0, 2, path);
-                       if (err < 0)
-                               return err;
-               } else {
-                       err = add_stereo_vol(codec, name, index, path);
-                       if (err < 0)
-                               return err;
-               }
-
-               name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL);
-               if (!name || !strcmp(name, "CLFE")) {
-                       err = add_sw_ctl(codec, "Center", 0, 1, path);
-                       if (err < 0)
-                               return err;
-                       err = add_sw_ctl(codec, "LFE", 0, 2, path);
-                       if (err < 0)
-                               return err;
-               } else {
-                       err = add_stereo_sw(codec, name, index, path);
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-static int create_extra_out(struct hda_codec *codec, int path_idx,
-                           const char *pfx, int cidx)
-{
-       struct nid_path *path;
-       int err;
-
-       path = snd_hda_get_path_from_idx(codec, path_idx);
-       if (!path)
-               return 0;
-       err = add_stereo_vol(codec, pfx, cidx, path);
-       if (err < 0)
-               return err;
-       err = add_stereo_sw(codec, pfx, cidx, path);
-       if (err < 0)
-               return err;
-       return 0;
-}
-
-/* add playback controls for speaker and HP outputs */
-static int create_extra_outs(struct hda_codec *codec, int num_pins,
-                            const int *paths, const char *pfx)
-{
-       int i;
-
-       for (i = 0; i < num_pins; i++) {
-               const char *name;
-               char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-               int err, idx = 0;
-
-               if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker"))
-                       name = "Bass Speaker";
-               else if (num_pins >= 3) {
-                       snprintf(tmp, sizeof(tmp), "%s %s",
-                                pfx, channel_name[i]);
-                       name = tmp;
-               } else {
-                       name = pfx;
-                       idx = i;
-               }
-               err = create_extra_out(codec, paths[i], name, idx);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-static int create_hp_out_ctls(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return create_extra_outs(codec, spec->autocfg.hp_outs,
-                                spec->hp_paths,
-                                "Headphone");
-}
-
-static int create_speaker_out_ctls(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return create_extra_outs(codec, spec->autocfg.speaker_outs,
-                                spec->speaker_paths,
-                                "Speaker");
-}
-
-/*
- * independent HP controls
- */
-
-static void call_hp_automute(struct hda_codec *codec,
-                            struct hda_jack_callback *jack);
-static int indep_hp_info(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_info *uinfo)
-{
-       return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
-}
-
-static int indep_hp_get(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled;
-       return 0;
-}
-
-static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
-                              int nomix_path_idx, int mix_path_idx,
-                              int out_type);
-
-static int indep_hp_put(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       unsigned int select = ucontrol->value.enumerated.item[0];
-       int ret = 0;
-
-       mutex_lock(&spec->pcm_mutex);
-       if (spec->active_streams) {
-               ret = -EBUSY;
-               goto unlock;
-       }
-
-       if (spec->indep_hp_enabled != select) {
-               hda_nid_t *dacp;
-               if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
-                       dacp = &spec->private_dac_nids[0];
-               else
-                       dacp = &spec->multiout.hp_out_nid[0];
-
-               /* update HP aamix paths in case it conflicts with indep HP */
-               if (spec->have_aamix_ctl) {
-                       if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
-                               update_aamix_paths(codec, spec->aamix_mode,
-                                                  spec->out_paths[0],
-                                                  spec->aamix_out_paths[0],
-                                                  spec->autocfg.line_out_type);
-                       else
-                               update_aamix_paths(codec, spec->aamix_mode,
-                                                  spec->hp_paths[0],
-                                                  spec->aamix_out_paths[1],
-                                                  AUTO_PIN_HP_OUT);
-               }
-
-               spec->indep_hp_enabled = select;
-               if (spec->indep_hp_enabled)
-                       *dacp = 0;
-               else
-                       *dacp = spec->alt_dac_nid;
-
-               call_hp_automute(codec, NULL);
-               ret = 1;
-       }
- unlock:
-       mutex_unlock(&spec->pcm_mutex);
-       return ret;
-}
-
-static const struct snd_kcontrol_new indep_hp_ctl = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Independent HP",
-       .info = indep_hp_info,
-       .get = indep_hp_get,
-       .put = indep_hp_put,
-};
-
-
-static int create_indep_hp_ctls(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       hda_nid_t dac;
-
-       if (!spec->indep_hp)
-               return 0;
-       if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
-               dac = spec->multiout.dac_nids[0];
-       else
-               dac = spec->multiout.hp_out_nid[0];
-       if (!dac) {
-               spec->indep_hp = 0;
-               return 0;
-       }
-
-       spec->indep_hp_enabled = false;
-       spec->alt_dac_nid = dac;
-       if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl))
-               return -ENOMEM;
-       return 0;
-}
-
-/*
- * channel mode enum control
- */
-
-static int ch_mode_info(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       int chs;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = spec->multi_ios + 1;
-       if (uinfo->value.enumerated.item > spec->multi_ios)
-               uinfo->value.enumerated.item = spec->multi_ios;
-       chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count;
-       sprintf(uinfo->value.enumerated.name, "%dch", chs);
-       return 0;
-}
-
-static int ch_mode_get(struct snd_kcontrol *kcontrol,
-                      struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       ucontrol->value.enumerated.item[0] =
-               (spec->ext_channel_count - spec->min_channel_count) / 2;
-       return 0;
-}
-
-static inline struct nid_path *
-get_multiio_path(struct hda_codec *codec, int idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_get_path_from_idx(codec,
-               spec->out_paths[spec->autocfg.line_outs + idx]);
-}
-
-static void update_automute_all(struct hda_codec *codec);
-
-/* Default value to be passed as aamix argument for snd_hda_activate_path();
- * used for output paths
- */
-static bool aamix_default(struct hda_gen_spec *spec)
-{
-       return !spec->have_aamix_ctl || spec->aamix_mode;
-}
-
-static int set_multi_io(struct hda_codec *codec, int idx, bool output)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       hda_nid_t nid = spec->multi_io[idx].pin;
-       struct nid_path *path;
-
-       path = get_multiio_path(codec, idx);
-       if (!path)
-               return -EINVAL;
-
-       if (path->active == output)
-               return 0;
-
-       if (output) {
-               set_pin_target(codec, nid, PIN_OUT, true);
-               snd_hda_activate_path(codec, path, true, aamix_default(spec));
-               set_pin_eapd(codec, nid, true);
-       } else {
-               set_pin_eapd(codec, nid, false);
-               snd_hda_activate_path(codec, path, false, aamix_default(spec));
-               set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true);
-               path_power_down_sync(codec, path);
-       }
-
-       /* update jack retasking in case it modifies any of them */
-       update_automute_all(codec);
-
-       return 0;
-}
-
-static int ch_mode_put(struct snd_kcontrol *kcontrol,
-                      struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       int i, ch;
-
-       ch = ucontrol->value.enumerated.item[0];
-       if (ch < 0 || ch > spec->multi_ios)
-               return -EINVAL;
-       if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2)
-               return 0;
-       spec->ext_channel_count = ch * 2 + spec->min_channel_count;
-       for (i = 0; i < spec->multi_ios; i++)
-               set_multi_io(codec, i, i < ch);
-       spec->multiout.max_channels = max(spec->ext_channel_count,
-                                         spec->const_channel_count);
-       if (spec->need_dac_fix)
-               spec->multiout.num_dacs = spec->multiout.max_channels / 2;
-       return 1;
-}
-
-static const struct snd_kcontrol_new channel_mode_enum = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Channel Mode",
-       .info = ch_mode_info,
-       .get = ch_mode_get,
-       .put = ch_mode_put,
-};
-
-static int create_multi_channel_mode(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (spec->multi_ios > 0) {
-               if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum))
-                       return -ENOMEM;
-       }
-       return 0;
-}
-
-/*
- * aamix loopback enable/disable switch
- */
-
-#define loopback_mixing_info   indep_hp_info
-
-static int loopback_mixing_get(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       ucontrol->value.enumerated.item[0] = spec->aamix_mode;
-       return 0;
-}
-
-static void update_aamix_paths(struct hda_codec *codec, bool do_mix,
-                              int nomix_path_idx, int mix_path_idx,
-                              int out_type)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *nomix_path, *mix_path;
-
-       nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx);
-       mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx);
-       if (!nomix_path || !mix_path)
-               return;
-
-       /* if HP aamix path is driven from a different DAC and the
-        * independent HP mode is ON, can't turn on aamix path
-        */
-       if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled &&
-           mix_path->path[0] != spec->alt_dac_nid)
-               do_mix = false;
-
-       if (do_mix) {
-               snd_hda_activate_path(codec, nomix_path, false, true);
-               snd_hda_activate_path(codec, mix_path, true, true);
-               path_power_down_sync(codec, nomix_path);
-       } else {
-               snd_hda_activate_path(codec, mix_path, false, false);
-               snd_hda_activate_path(codec, nomix_path, true, false);
-               path_power_down_sync(codec, mix_path);
-       }
-}
-
-/* re-initialize the output paths; only called from loopback_mixing_put() */
-static void update_output_paths(struct hda_codec *codec, int num_outs,
-                               const int *paths)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *path;
-       int i;
-
-       for (i = 0; i < num_outs; i++) {
-               path = snd_hda_get_path_from_idx(codec, paths[i]);
-               if (path)
-                       snd_hda_activate_path(codec, path, path->active,
-                                             spec->aamix_mode);
-       }
-}
-
-static int loopback_mixing_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int val = ucontrol->value.enumerated.item[0];
-
-       if (val == spec->aamix_mode)
-               return 0;
-       spec->aamix_mode = val;
-       if (has_aamix_out_paths(spec)) {
-               update_aamix_paths(codec, val, spec->out_paths[0],
-                                  spec->aamix_out_paths[0],
-                                  cfg->line_out_type);
-               update_aamix_paths(codec, val, spec->hp_paths[0],
-                                  spec->aamix_out_paths[1],
-                                  AUTO_PIN_HP_OUT);
-               update_aamix_paths(codec, val, spec->speaker_paths[0],
-                                  spec->aamix_out_paths[2],
-                                  AUTO_PIN_SPEAKER_OUT);
-       } else {
-               update_output_paths(codec, cfg->line_outs, spec->out_paths);
-               if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-                       update_output_paths(codec, cfg->hp_outs, spec->hp_paths);
-               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
-                       update_output_paths(codec, cfg->speaker_outs,
-                                           spec->speaker_paths);
-       }
-       return 1;
-}
-
-static const struct snd_kcontrol_new loopback_mixing_enum = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Loopback Mixing",
-       .info = loopback_mixing_info,
-       .get = loopback_mixing_get,
-       .put = loopback_mixing_put,
-};
-
-static int create_loopback_mixing_ctl(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (!spec->mixer_nid)
-               return 0;
-       if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum))
-               return -ENOMEM;
-       spec->have_aamix_ctl = 1;
-       return 0;
-}
-
-/*
- * shared headphone/mic handling
- */
-
-static void call_update_outputs(struct hda_codec *codec);
-
-/* for shared I/O, change the pin-control accordingly */
-static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       bool as_mic;
-       unsigned int val;
-       hda_nid_t pin;
-
-       pin = spec->hp_mic_pin;
-       as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx;
-
-       if (!force) {
-               val = snd_hda_codec_get_pin_target(codec, pin);
-               if (as_mic) {
-                       if (val & PIN_IN)
-                               return;
-               } else {
-                       if (val & PIN_OUT)
-                               return;
-               }
-       }
-
-       val = snd_hda_get_default_vref(codec, pin);
-       /* if the HP pin doesn't support VREF and the codec driver gives an
-        * alternative pin, set up the VREF on that pin instead
-        */
-       if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) {
-               const hda_nid_t vref_pin = spec->shared_mic_vref_pin;
-               unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin);
-               if (vref_val != AC_PINCTL_VREF_HIZ)
-                       snd_hda_set_pin_ctl_cache(codec, vref_pin,
-                                                 PIN_IN | (as_mic ? vref_val : 0));
-       }
-
-       if (!spec->hp_mic_jack_modes) {
-               if (as_mic)
-                       val |= PIN_IN;
-               else
-                       val = PIN_HP;
-               set_pin_target(codec, pin, val, true);
-               call_hp_automute(codec, NULL);
-       }
-}
-
-/* create a shared input with the headphone out */
-static int create_hp_mic(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int defcfg;
-       hda_nid_t nid;
-
-       if (!spec->hp_mic) {
-               if (spec->suppress_hp_mic_detect)
-                       return 0;
-               /* automatic detection: only if no input or a single internal
-                * input pin is found, try to detect the shared hp/mic
-                */
-               if (cfg->num_inputs > 1)
-                       return 0;
-               else if (cfg->num_inputs == 1) {
-                       defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin);
-                       if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
-                               return 0;
-               }
-       }
-
-       spec->hp_mic = 0; /* clear once */
-       if (cfg->num_inputs >= AUTO_CFG_MAX_INS)
-               return 0;
-
-       nid = 0;
-       if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0)
-               nid = cfg->line_out_pins[0];
-       else if (cfg->hp_outs > 0)
-               nid = cfg->hp_pins[0];
-       if (!nid)
-               return 0;
-
-       if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN))
-               return 0; /* no input */
-
-       cfg->inputs[cfg->num_inputs].pin = nid;
-       cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC;
-       cfg->inputs[cfg->num_inputs].is_headphone_mic = 1;
-       cfg->num_inputs++;
-       spec->hp_mic = 1;
-       spec->hp_mic_pin = nid;
-       /* we can't handle auto-mic together with HP-mic */
-       spec->suppress_auto_mic = 1;
-       codec_dbg(codec, "Enable shared I/O jack on NID 0x%x\n", nid);
-       return 0;
-}
-
-/*
- * output jack mode
- */
-
-static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin);
-
-static const char * const out_jack_texts[] = {
-       "Line Out", "Headphone Out",
-};
-
-static int out_jack_mode_info(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_info *uinfo)
-{
-       return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts);
-}
-
-static int out_jack_mode_get(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP)
-               ucontrol->value.enumerated.item[0] = 1;
-       else
-               ucontrol->value.enumerated.item[0] = 0;
-       return 0;
-}
-
-static int out_jack_mode_put(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       unsigned int val;
-
-       val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT;
-       if (snd_hda_codec_get_pin_target(codec, nid) == val)
-               return 0;
-       snd_hda_set_pin_ctl_cache(codec, nid, val);
-       return 1;
-}
-
-static const struct snd_kcontrol_new out_jack_mode_enum = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .info = out_jack_mode_info,
-       .get = out_jack_mode_get,
-       .put = out_jack_mode_put,
-};
-
-static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const struct snd_kcontrol_new *kctl;
-       int i;
-
-       snd_array_for_each(&spec->kctls, i, kctl) {
-               if (!strcmp(kctl->name, name) && kctl->index == idx)
-                       return true;
-       }
-       return false;
-}
-
-static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin,
-                              char *name, size_t name_len)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int idx = 0;
-
-       snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx);
-       strlcat(name, " Jack Mode", name_len);
-
-       for (; find_kctl_name(codec, name, idx); idx++)
-               ;
-}
-
-static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->add_jack_modes) {
-               unsigned int pincap = snd_hda_query_pin_caps(codec, pin);
-               if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV))
-                       return 2;
-       }
-       return 1;
-}
-
-static int create_out_jack_modes(struct hda_codec *codec, int num_pins,
-                                hda_nid_t *pins)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < num_pins; i++) {
-               hda_nid_t pin = pins[i];
-               if (pin == spec->hp_mic_pin)
-                       continue;
-               if (get_out_jack_num_items(codec, pin) > 1) {
-                       struct snd_kcontrol_new *knew;
-                       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-                       get_jack_mode_name(codec, pin, name, sizeof(name));
-                       knew = snd_hda_gen_add_kctl(spec, name,
-                                                   &out_jack_mode_enum);
-                       if (!knew)
-                               return -ENOMEM;
-                       knew->private_value = pin;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * input jack mode
- */
-
-/* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */
-#define NUM_VREFS      6
-
-static const char * const vref_texts[NUM_VREFS] = {
-       "Line In", "Mic 50pc Bias", "Mic 0V Bias",
-       "", "Mic 80pc Bias", "Mic 100pc Bias"
-};
-
-static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin)
-{
-       unsigned int pincap;
-
-       pincap = snd_hda_query_pin_caps(codec, pin);
-       pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT;
-       /* filter out unusual vrefs */
-       pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100);
-       return pincap;
-}
-
-/* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */
-static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx)
-{
-       unsigned int i, n = 0;
-
-       for (i = 0; i < NUM_VREFS; i++) {
-               if (vref_caps & (1 << i)) {
-                       if (n == item_idx)
-                               return i;
-                       n++;
-               }
-       }
-       return 0;
-}
-
-/* convert back from the vref ctl index to the enum item index */
-static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx)
-{
-       unsigned int i, n = 0;
-
-       for (i = 0; i < NUM_VREFS; i++) {
-               if (i == idx)
-                       return n;
-               if (vref_caps & (1 << i))
-                       n++;
-       }
-       return 0;
-}
-
-static int in_jack_mode_info(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       unsigned int vref_caps = get_vref_caps(codec, nid);
-
-       snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps),
-                                vref_texts);
-       /* set the right text */
-       strcpy(uinfo->value.enumerated.name,
-              vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]);
-       return 0;
-}
-
-static int in_jack_mode_get(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       unsigned int vref_caps = get_vref_caps(codec, nid);
-       unsigned int idx;
-
-       idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN;
-       ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx);
-       return 0;
-}
-
-static int in_jack_mode_put(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       unsigned int vref_caps = get_vref_caps(codec, nid);
-       unsigned int val, idx;
-
-       val = snd_hda_codec_get_pin_target(codec, nid);
-       idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN);
-       if (idx == ucontrol->value.enumerated.item[0])
-               return 0;
-
-       val &= ~AC_PINCTL_VREFEN;
-       val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]);
-       snd_hda_set_pin_ctl_cache(codec, nid, val);
-       return 1;
-}
-
-static const struct snd_kcontrol_new in_jack_mode_enum = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .info = in_jack_mode_info,
-       .get = in_jack_mode_get,
-       .put = in_jack_mode_put,
-};
-
-static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int nitems = 0;
-       if (spec->add_jack_modes)
-               nitems = hweight32(get_vref_caps(codec, pin));
-       return nitems ? nitems : 1;
-}
-
-static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct snd_kcontrol_new *knew;
-       char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       unsigned int defcfg;
-
-       if (pin == spec->hp_mic_pin)
-               return 0; /* already done in create_out_jack_mode() */
-
-       /* no jack mode for fixed pins */
-       defcfg = snd_hda_codec_get_pincfg(codec, pin);
-       if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
-               return 0;
-
-       /* no multiple vref caps? */
-       if (get_in_jack_num_items(codec, pin) <= 1)
-               return 0;
-
-       get_jack_mode_name(codec, pin, name, sizeof(name));
-       knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum);
-       if (!knew)
-               return -ENOMEM;
-       knew->private_value = pin;
-       return 0;
-}
-
-/*
- * HP/mic shared jack mode
- */
-static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       int out_jacks = get_out_jack_num_items(codec, nid);
-       int in_jacks = get_in_jack_num_items(codec, nid);
-       const char *text = NULL;
-       int idx;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = out_jacks + in_jacks;
-       if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
-               uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
-       idx = uinfo->value.enumerated.item;
-       if (idx < out_jacks) {
-               if (out_jacks > 1)
-                       text = out_jack_texts[idx];
-               else
-                       text = "Headphone Out";
-       } else {
-               idx -= out_jacks;
-               if (in_jacks > 1) {
-                       unsigned int vref_caps = get_vref_caps(codec, nid);
-                       text = vref_texts[get_vref_idx(vref_caps, idx)];
-               } else
-                       text = "Mic In";
-       }
-
-       strcpy(uinfo->value.enumerated.name, text);
-       return 0;
-}
-
-static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid)
-{
-       int out_jacks = get_out_jack_num_items(codec, nid);
-       int in_jacks = get_in_jack_num_items(codec, nid);
-       unsigned int val = snd_hda_codec_get_pin_target(codec, nid);
-       int idx = 0;
-
-       if (val & PIN_OUT) {
-               if (out_jacks > 1 && val == PIN_HP)
-                       idx = 1;
-       } else if (val & PIN_IN) {
-               idx = out_jacks;
-               if (in_jacks > 1) {
-                       unsigned int vref_caps = get_vref_caps(codec, nid);
-                       val &= AC_PINCTL_VREFEN;
-                       idx += cvt_from_vref_idx(vref_caps, val);
-               }
-       }
-       return idx;
-}
-
-static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       ucontrol->value.enumerated.item[0] =
-               get_cur_hp_mic_jack_mode(codec, nid);
-       return 0;
-}
-
-static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = kcontrol->private_value;
-       int out_jacks = get_out_jack_num_items(codec, nid);
-       int in_jacks = get_in_jack_num_items(codec, nid);
-       unsigned int val, oldval, idx;
-
-       oldval = get_cur_hp_mic_jack_mode(codec, nid);
-       idx = ucontrol->value.enumerated.item[0];
-       if (oldval == idx)
-               return 0;
-
-       if (idx < out_jacks) {
-               if (out_jacks > 1)
-                       val = idx ? PIN_HP : PIN_OUT;
-               else
-                       val = PIN_HP;
-       } else {
-               idx -= out_jacks;
-               if (in_jacks > 1) {
-                       unsigned int vref_caps = get_vref_caps(codec, nid);
-                       val = snd_hda_codec_get_pin_target(codec, nid);
-                       val &= ~(AC_PINCTL_VREFEN | PIN_HP);
-                       val |= get_vref_idx(vref_caps, idx) | PIN_IN;
-               } else
-                       val = snd_hda_get_default_vref(codec, nid) | PIN_IN;
-       }
-       snd_hda_set_pin_ctl_cache(codec, nid, val);
-       call_hp_automute(codec, NULL);
-
-       return 1;
-}
-
-static const struct snd_kcontrol_new hp_mic_jack_mode_enum = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .info = hp_mic_jack_mode_info,
-       .get = hp_mic_jack_mode_get,
-       .put = hp_mic_jack_mode_put,
-};
-
-static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct snd_kcontrol_new *knew;
-
-       knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode",
-                                   &hp_mic_jack_mode_enum);
-       if (!knew)
-               return -ENOMEM;
-       knew->private_value = pin;
-       spec->hp_mic_jack_modes = 1;
-       return 0;
-}
-
-/*
- * Parse input paths
- */
-
-/* add the powersave loopback-list entry */
-static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx)
-{
-       struct hda_amp_list *list;
-
-       list = snd_array_new(&spec->loopback_list);
-       if (!list)
-               return -ENOMEM;
-       list->nid = mix;
-       list->dir = HDA_INPUT;
-       list->idx = idx;
-       spec->loopback.amplist = spec->loopback_list.list;
-       return 0;
-}
-
-/* return true if either a volume or a mute amp is found for the given
- * aamix path; the amp has to be either in the mixer node or its direct leaf
- */
-static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid,
-                                  hda_nid_t pin, unsigned int *mix_val,
-                                  unsigned int *mute_val)
-{
-       int idx, num_conns;
-       const hda_nid_t *list;
-       hda_nid_t nid;
-
-       idx = snd_hda_get_conn_index(codec, mix_nid, pin, true);
-       if (idx < 0)
-               return false;
-
-       *mix_val = *mute_val = 0;
-       if (nid_has_volume(codec, mix_nid, HDA_INPUT))
-               *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
-       if (nid_has_mute(codec, mix_nid, HDA_INPUT))
-               *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT);
-       if (*mix_val && *mute_val)
-               return true;
-
-       /* check leaf node */
-       num_conns = snd_hda_get_conn_list(codec, mix_nid, &list);
-       if (num_conns < idx)
-               return false;
-       nid = list[idx];
-       if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) &&
-           !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL))
-               *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-       if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) &&
-           !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL))
-               *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-
-       return *mix_val || *mute_val;
-}
-
-/* create input playback/capture controls for the given pin */
-static int new_analog_input(struct hda_codec *codec, int input_idx,
-                           hda_nid_t pin, const char *ctlname, int ctlidx,
-                           hda_nid_t mix_nid)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *path;
-       unsigned int mix_val, mute_val;
-       int err, idx;
-
-       if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val))
-               return 0;
-
-       path = snd_hda_add_new_path(codec, pin, mix_nid, 0);
-       if (!path)
-               return -EINVAL;
-       print_nid_path(codec, "loopback", path);
-       spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path);
-
-       idx = path->idx[path->depth - 1];
-       if (mix_val) {
-               err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val);
-               if (err < 0)
-                       return err;
-               path->ctls[NID_PATH_VOL_CTL] = mix_val;
-       }
-
-       if (mute_val) {
-               err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val);
-               if (err < 0)
-                       return err;
-               path->ctls[NID_PATH_MUTE_CTL] = mute_val;
-       }
-
-       path->active = true;
-       path->stream_enabled = true; /* no DAC/ADC involved */
-       err = add_loopback_list(spec, mix_nid, idx);
-       if (err < 0)
-               return err;
-
-       if (spec->mixer_nid != spec->mixer_merge_nid &&
-           !spec->loopback_merge_path) {
-               path = snd_hda_add_new_path(codec, spec->mixer_nid,
-                                           spec->mixer_merge_nid, 0);
-               if (path) {
-                       print_nid_path(codec, "loopback-merge", path);
-                       path->active = true;
-                       path->pin_fixed = true; /* static route */
-                       path->stream_enabled = true; /* no DAC/ADC involved */
-                       spec->loopback_merge_path =
-                               snd_hda_get_path_idx(codec, path);
-               }
-       }
-
-       return 0;
-}
-
-static int is_input_pin(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int pincap = snd_hda_query_pin_caps(codec, nid);
-       return (pincap & AC_PINCAP_IN) != 0;
-}
-
-/* Parse the codec tree and retrieve ADCs */
-static int fill_adc_nids(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       hda_nid_t nid;
-       hda_nid_t *adc_nids = spec->adc_nids;
-       int max_nums = ARRAY_SIZE(spec->adc_nids);
-       int nums = 0;
-
-       for_each_hda_codec_node(nid, codec) {
-               unsigned int caps = get_wcaps(codec, nid);
-               int type = get_wcaps_type(caps);
-
-               if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL))
-                       continue;
-               adc_nids[nums] = nid;
-               if (++nums >= max_nums)
-                       break;
-       }
-       spec->num_adc_nids = nums;
-
-       /* copy the detected ADCs to all_adcs[] */
-       spec->num_all_adcs = nums;
-       memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t));
-
-       return nums;
-}
-
-/* filter out invalid adc_nids that don't give all active input pins;
- * if needed, check whether dynamic ADC-switching is available
- */
-static int check_dyn_adc_switch(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->input_mux;
-       unsigned int ok_bits;
-       int i, n, nums;
-
-       nums = 0;
-       ok_bits = 0;
-       for (n = 0; n < spec->num_adc_nids; n++) {
-               for (i = 0; i < imux->num_items; i++) {
-                       if (!spec->input_paths[i][n])
-                               break;
-               }
-               if (i >= imux->num_items) {
-                       ok_bits |= (1 << n);
-                       nums++;
-               }
-       }
-
-       if (!ok_bits) {
-               /* check whether ADC-switch is possible */
-               for (i = 0; i < imux->num_items; i++) {
-                       for (n = 0; n < spec->num_adc_nids; n++) {
-                               if (spec->input_paths[i][n]) {
-                                       spec->dyn_adc_idx[i] = n;
-                                       break;
-                               }
-                       }
-               }
-
-               codec_dbg(codec, "enabling ADC switching\n");
-               spec->dyn_adc_switch = 1;
-       } else if (nums != spec->num_adc_nids) {
-               /* shrink the invalid adcs and input paths */
-               nums = 0;
-               for (n = 0; n < spec->num_adc_nids; n++) {
-                       if (!(ok_bits & (1 << n)))
-                               continue;
-                       if (n != nums) {
-                               spec->adc_nids[nums] = spec->adc_nids[n];
-                               for (i = 0; i < imux->num_items; i++) {
-                                       invalidate_nid_path(codec,
-                                               spec->input_paths[i][nums]);
-                                       spec->input_paths[i][nums] =
-                                               spec->input_paths[i][n];
-                                       spec->input_paths[i][n] = 0;
-                               }
-                       }
-                       nums++;
-               }
-               spec->num_adc_nids = nums;
-       }
-
-       if (imux->num_items == 1 ||
-           (imux->num_items == 2 && spec->hp_mic)) {
-               codec_dbg(codec, "reducing to a single ADC\n");
-               spec->num_adc_nids = 1; /* reduce to a single ADC */
-       }
-
-       /* single index for individual volumes ctls */
-       if (!spec->dyn_adc_switch && spec->multi_cap_vol)
-               spec->num_adc_nids = 1;
-
-       return 0;
-}
-
-/* parse capture source paths from the given pin and create imux items */
-static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin,
-                               int cfg_idx, int num_adcs,
-                               const char *label, int anchor)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->input_mux;
-       int imux_idx = imux->num_items;
-       bool imux_added = false;
-       int c;
-
-       for (c = 0; c < num_adcs; c++) {
-               struct nid_path *path;
-               hda_nid_t adc = spec->adc_nids[c];
-
-               if (!is_reachable_path(codec, pin, adc))
-                       continue;
-               path = snd_hda_add_new_path(codec, pin, adc, anchor);
-               if (!path)
-                       continue;
-               print_nid_path(codec, "input", path);
-               spec->input_paths[imux_idx][c] =
-                       snd_hda_get_path_idx(codec, path);
-
-               if (!imux_added) {
-                       if (spec->hp_mic_pin == pin)
-                               spec->hp_mic_mux_idx = imux->num_items;
-                       spec->imux_pins[imux->num_items] = pin;
-                       snd_hda_add_imux_item(codec, imux, label, cfg_idx, NULL);
-                       imux_added = true;
-                       if (spec->dyn_adc_switch)
-                               spec->dyn_adc_idx[imux_idx] = c;
-               }
-       }
-
-       return 0;
-}
-
-/*
- * create playback/capture controls for input pins
- */
-
-/* fill the label for each input at first */
-static int fill_input_pin_labels(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t pin = cfg->inputs[i].pin;
-               const char *label;
-               int j, idx;
-
-               if (!is_input_pin(codec, pin))
-                       continue;
-
-               label = hda_get_autocfg_input_label(codec, cfg, i);
-               idx = 0;
-               for (j = i - 1; j >= 0; j--) {
-                       if (spec->input_labels[j] &&
-                           !strcmp(spec->input_labels[j], label)) {
-                               idx = spec->input_label_idxs[j] + 1;
-                               break;
-                       }
-               }
-
-               spec->input_labels[i] = label;
-               spec->input_label_idxs[i] = idx;
-       }
-
-       return 0;
-}
-
-#define CFG_IDX_MIX    99      /* a dummy cfg->input idx for stereo mix */
-
-static int create_input_ctls(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t mixer = spec->mixer_nid;
-       int num_adcs;
-       int i, err;
-       unsigned int val;
-
-       num_adcs = fill_adc_nids(codec);
-       if (num_adcs < 0)
-               return 0;
-
-       err = fill_input_pin_labels(codec);
-       if (err < 0)
-               return err;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t pin;
-
-               pin = cfg->inputs[i].pin;
-               if (!is_input_pin(codec, pin))
-                       continue;
-
-               val = PIN_IN;
-               if (cfg->inputs[i].type == AUTO_PIN_MIC)
-                       val |= snd_hda_get_default_vref(codec, pin);
-               if (pin != spec->hp_mic_pin &&
-                   !snd_hda_codec_get_pin_target(codec, pin))
-                       set_pin_target(codec, pin, val, false);
-
-               if (mixer) {
-                       if (is_reachable_path(codec, pin, mixer)) {
-                               err = new_analog_input(codec, i, pin,
-                                                      spec->input_labels[i],
-                                                      spec->input_label_idxs[i],
-                                                      mixer);
-                               if (err < 0)
-                                       return err;
-                       }
-               }
-
-               err = parse_capture_source(codec, pin, i, num_adcs,
-                                          spec->input_labels[i], -mixer);
-               if (err < 0)
-                       return err;
-
-               if (spec->add_jack_modes) {
-                       err = create_in_jack_mode(codec, pin);
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       /* add stereo mix when explicitly enabled via hint */
-       if (mixer && spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_ENABLE) {
-               err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs,
-                                          "Stereo Mix", 0);
-               if (err < 0)
-                       return err;
-               else
-                       spec->suppress_auto_mic = 1;
-       }
-
-       return 0;
-}
-
-
-/*
- * input source mux
- */
-
-/* get the input path specified by the given adc and imux indices */
-static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) {
-               snd_BUG();
-               return NULL;
-       }
-       if (spec->dyn_adc_switch)
-               adc_idx = spec->dyn_adc_idx[imux_idx];
-       if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) {
-               snd_BUG();
-               return NULL;
-       }
-       return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]);
-}
-
-static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
-                     unsigned int idx);
-
-static int mux_enum_info(struct snd_kcontrol *kcontrol,
-                        struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_input_mux_info(&spec->input_mux, uinfo);
-}
-
-static int mux_enum_get(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       /* the ctls are created at once with multiple counts */
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-       ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx];
-       return 0;
-}
-
-static int mux_enum_put(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       return mux_select(codec, adc_idx,
-                         ucontrol->value.enumerated.item[0]);
-}
-
-static const struct snd_kcontrol_new cap_src_temp = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Input Source",
-       .info = mux_enum_info,
-       .get = mux_enum_get,
-       .put = mux_enum_put,
-};
-
-/*
- * capture volume and capture switch ctls
- */
-
-typedef int (*put_call_t)(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol);
-
-/* call the given amp update function for all amps in the imux list at once */
-static int cap_put_caller(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol,
-                         put_call_t func, int type)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       const struct hda_input_mux *imux;
-       struct nid_path *path;
-       int i, adc_idx, ret, err = 0;
-
-       imux = &spec->input_mux;
-       adc_idx = kcontrol->id.index;
-       mutex_lock(&codec->control_mutex);
-       for (i = 0; i < imux->num_items; i++) {
-               path = get_input_path(codec, adc_idx, i);
-               if (!path || !path->ctls[type])
-                       continue;
-               kcontrol->private_value = path->ctls[type];
-               ret = func(kcontrol, ucontrol);
-               if (ret < 0) {
-                       err = ret;
-                       break;
-               }
-               if (ret > 0)
-                       err = 1;
-       }
-       mutex_unlock(&codec->control_mutex);
-       if (err >= 0 && spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, kcontrol, ucontrol);
-       return err;
-}
-
-/* capture volume ctl callbacks */
-#define cap_vol_info           snd_hda_mixer_amp_volume_info
-#define cap_vol_get            snd_hda_mixer_amp_volume_get
-#define cap_vol_tlv            snd_hda_mixer_amp_tlv
-
-static int cap_vol_put(struct snd_kcontrol *kcontrol,
-                      struct snd_ctl_elem_value *ucontrol)
-{
-       return cap_put_caller(kcontrol, ucontrol,
-                             snd_hda_mixer_amp_volume_put,
-                             NID_PATH_VOL_CTL);
-}
-
-static const struct snd_kcontrol_new cap_vol_temp = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Volume",
-       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                  SNDRV_CTL_ELEM_ACCESS_TLV_READ |
-                  SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK),
-       .info = cap_vol_info,
-       .get = cap_vol_get,
-       .put = cap_vol_put,
-       .tlv = { .c = cap_vol_tlv },
-};
-
-/* capture switch ctl callbacks */
-#define cap_sw_info            snd_ctl_boolean_stereo_info
-#define cap_sw_get             snd_hda_mixer_amp_switch_get
-
-static int cap_sw_put(struct snd_kcontrol *kcontrol,
-                     struct snd_ctl_elem_value *ucontrol)
-{
-       return cap_put_caller(kcontrol, ucontrol,
-                             snd_hda_mixer_amp_switch_put,
-                             NID_PATH_MUTE_CTL);
-}
-
-static const struct snd_kcontrol_new cap_sw_temp = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Capture Switch",
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-       .info = cap_sw_info,
-       .get = cap_sw_get,
-       .put = cap_sw_put,
-};
-
-static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path)
-{
-       hda_nid_t nid;
-       int i, depth;
-
-       path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0;
-       for (depth = 0; depth < 3; depth++) {
-               if (depth >= path->depth)
-                       return -EINVAL;
-               i = path->depth - depth - 1;
-               nid = path->path[i];
-               if (!path->ctls[NID_PATH_VOL_CTL]) {
-                       if (nid_has_volume(codec, nid, HDA_OUTPUT))
-                               path->ctls[NID_PATH_VOL_CTL] =
-                                       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-                       else if (nid_has_volume(codec, nid, HDA_INPUT)) {
-                               int idx = path->idx[i];
-                               if (!depth && codec->single_adc_amp)
-                                       idx = 0;
-                               path->ctls[NID_PATH_VOL_CTL] =
-                                       HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
-                       }
-               }
-               if (!path->ctls[NID_PATH_MUTE_CTL]) {
-                       if (nid_has_mute(codec, nid, HDA_OUTPUT))
-                               path->ctls[NID_PATH_MUTE_CTL] =
-                                       HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-                       else if (nid_has_mute(codec, nid, HDA_INPUT)) {
-                               int idx = path->idx[i];
-                               if (!depth && codec->single_adc_amp)
-                                       idx = 0;
-                               path->ctls[NID_PATH_MUTE_CTL] =
-                                       HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT);
-                       }
-               }
-       }
-       return 0;
-}
-
-static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int val;
-       int i;
-
-       if (!spec->inv_dmic_split)
-               return false;
-       for (i = 0; i < cfg->num_inputs; i++) {
-               if (cfg->inputs[i].pin != nid)
-                       continue;
-               if (cfg->inputs[i].type != AUTO_PIN_MIC)
-                       return false;
-               val = snd_hda_codec_get_pincfg(codec, nid);
-               return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT;
-       }
-       return false;
-}
-
-/* capture switch put callback for a single control with hook call */
-static int cap_single_sw_put(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       int ret;
-
-       ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-       if (ret < 0)
-               return ret;
-
-       if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, kcontrol, ucontrol);
-
-       return ret;
-}
-
-static int add_single_cap_ctl(struct hda_codec *codec, const char *label,
-                             int idx, bool is_switch, unsigned int ctl,
-                             bool inv_dmic)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL;
-       const char *sfx = is_switch ? "Switch" : "Volume";
-       unsigned int chs = inv_dmic ? 1 : 3;
-       struct snd_kcontrol_new *knew;
-
-       if (!ctl)
-               return 0;
-
-       if (label)
-               snprintf(tmpname, sizeof(tmpname),
-                        "%s Capture %s", label, sfx);
-       else
-               snprintf(tmpname, sizeof(tmpname),
-                        "Capture %s", sfx);
-       knew = add_control(spec, type, tmpname, idx,
-                          amp_val_replace_channels(ctl, chs));
-       if (!knew)
-               return -ENOMEM;
-       if (is_switch) {
-               knew->put = cap_single_sw_put;
-               if (spec->mic_mute_led)
-                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
-       }
-       if (!inv_dmic)
-               return 0;
-
-       /* Make independent right kcontrol */
-       if (label)
-               snprintf(tmpname, sizeof(tmpname),
-                        "Inverted %s Capture %s", label, sfx);
-       else
-               snprintf(tmpname, sizeof(tmpname),
-                        "Inverted Capture %s", sfx);
-       knew = add_control(spec, type, tmpname, idx,
-                          amp_val_replace_channels(ctl, 2));
-       if (!knew)
-               return -ENOMEM;
-       if (is_switch) {
-               knew->put = cap_single_sw_put;
-               if (spec->mic_mute_led)
-                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
-       }
-       return 0;
-}
-
-/* create single (and simple) capture volume and switch controls */
-static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx,
-                                    unsigned int vol_ctl, unsigned int sw_ctl,
-                                    bool inv_dmic)
-{
-       int err;
-       err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic);
-       if (err < 0)
-               return err;
-       err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic);
-       if (err < 0)
-               return err;
-       return 0;
-}
-
-/* create bound capture volume and switch controls */
-static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx,
-                                  unsigned int vol_ctl, unsigned int sw_ctl)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct snd_kcontrol_new *knew;
-
-       if (vol_ctl) {
-               knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp);
-               if (!knew)
-                       return -ENOMEM;
-               knew->index = idx;
-               knew->private_value = vol_ctl;
-               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
-       }
-       if (sw_ctl) {
-               knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp);
-               if (!knew)
-                       return -ENOMEM;
-               knew->index = idx;
-               knew->private_value = sw_ctl;
-               knew->subdevice = HDA_SUBDEV_AMP_FLAG;
-               if (spec->mic_mute_led)
-                       knew->access |= SNDRV_CTL_ELEM_ACCESS_MIC_LED;
-       }
-       return 0;
-}
-
-/* return the vol ctl when used first in the imux list */
-static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type)
-{
-       struct nid_path *path;
-       unsigned int ctl;
-       int i;
-
-       path = get_input_path(codec, 0, idx);
-       if (!path)
-               return 0;
-       ctl = path->ctls[type];
-       if (!ctl)
-               return 0;
-       for (i = 0; i < idx - 1; i++) {
-               path = get_input_path(codec, 0, i);
-               if (path && path->ctls[type] == ctl)
-                       return 0;
-       }
-       return ctl;
-}
-
-/* create individual capture volume and switch controls per input */
-static int create_multi_cap_vol_ctl(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->input_mux;
-       int i, err, type;
-
-       for (i = 0; i < imux->num_items; i++) {
-               bool inv_dmic;
-               int idx;
-
-               idx = imux->items[i].index;
-               if (idx >= spec->autocfg.num_inputs)
-                       continue;
-               inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]);
-
-               for (type = 0; type < 2; type++) {
-                       err = add_single_cap_ctl(codec,
-                                                spec->input_labels[idx],
-                                                spec->input_label_idxs[idx],
-                                                type,
-                                                get_first_cap_ctl(codec, i, type),
-                                                inv_dmic);
-                       if (err < 0)
-                               return err;
-               }
-       }
-       return 0;
-}
-
-static int create_capture_mixers(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->input_mux;
-       int i, n, nums, err;
-
-       if (spec->dyn_adc_switch)
-               nums = 1;
-       else
-               nums = spec->num_adc_nids;
-
-       if (!spec->auto_mic && imux->num_items > 1) {
-               struct snd_kcontrol_new *knew;
-               const char *name;
-               name = nums > 1 ? "Input Source" : "Capture Source";
-               knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp);
-               if (!knew)
-                       return -ENOMEM;
-               knew->count = nums;
-       }
-
-       for (n = 0; n < nums; n++) {
-               bool multi = false;
-               bool multi_cap_vol = spec->multi_cap_vol;
-               bool inv_dmic = false;
-               int vol, sw;
-
-               vol = sw = 0;
-               for (i = 0; i < imux->num_items; i++) {
-                       struct nid_path *path;
-                       path = get_input_path(codec, n, i);
-                       if (!path)
-                               continue;
-                       parse_capvol_in_path(codec, path);
-                       if (!vol)
-                               vol = path->ctls[NID_PATH_VOL_CTL];
-                       else if (vol != path->ctls[NID_PATH_VOL_CTL]) {
-                               multi = true;
-                               if (!same_amp_caps(codec, vol,
-                                   path->ctls[NID_PATH_VOL_CTL], HDA_INPUT))
-                                       multi_cap_vol = true;
-                       }
-                       if (!sw)
-                               sw = path->ctls[NID_PATH_MUTE_CTL];
-                       else if (sw != path->ctls[NID_PATH_MUTE_CTL]) {
-                               multi = true;
-                               if (!same_amp_caps(codec, sw,
-                                   path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT))
-                                       multi_cap_vol = true;
-                       }
-                       if (is_inv_dmic_pin(codec, spec->imux_pins[i]))
-                               inv_dmic = true;
-               }
-
-               if (!multi)
-                       err = create_single_cap_vol_ctl(codec, n, vol, sw,
-                                                       inv_dmic);
-               else if (!multi_cap_vol && !inv_dmic)
-                       err = create_bind_cap_vol_ctl(codec, n, vol, sw);
-               else
-                       err = create_multi_cap_vol_ctl(codec);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-/*
- * add mic boosts if needed
- */
-
-/* check whether the given amp is feasible as a boost volume */
-static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid,
-                           int dir, int idx)
-{
-       unsigned int step;
-
-       if (!nid_has_volume(codec, nid, dir) ||
-           is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) ||
-           is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL))
-               return false;
-
-       step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE)
-               >> AC_AMPCAP_STEP_SIZE_SHIFT;
-       if (step < 0x20)
-               return false;
-       return true;
-}
-
-/* look for a boost amp in a widget close to the pin */
-static unsigned int look_for_boost_amp(struct hda_codec *codec,
-                                      struct nid_path *path)
-{
-       unsigned int val = 0;
-       hda_nid_t nid;
-       int depth;
-
-       for (depth = 0; depth < 3; depth++) {
-               if (depth >= path->depth - 1)
-                       break;
-               nid = path->path[depth];
-               if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) {
-                       val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT);
-                       break;
-               } else if (check_boost_vol(codec, nid, HDA_INPUT,
-                                          path->idx[depth])) {
-                       val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth],
-                                                 HDA_INPUT);
-                       break;
-               }
-       }
-
-       return val;
-}
-
-static int parse_mic_boost(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       struct hda_input_mux *imux = &spec->input_mux;
-       int i;
-
-       if (!spec->num_adc_nids)
-               return 0;
-
-       for (i = 0; i < imux->num_items; i++) {
-               struct nid_path *path;
-               unsigned int val;
-               int idx;
-               char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-
-               idx = imux->items[i].index;
-               if (idx >= imux->num_items)
-                       continue;
-
-               /* check only line-in and mic pins */
-               if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN)
-                       continue;
-
-               path = get_input_path(codec, 0, i);
-               if (!path)
-                       continue;
-
-               val = look_for_boost_amp(codec, path);
-               if (!val)
-                       continue;
-
-               /* create a boost control */
-               snprintf(boost_label, sizeof(boost_label),
-                        "%s Boost Volume", spec->input_labels[idx]);
-               if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label,
-                                spec->input_label_idxs[idx], val))
-                       return -ENOMEM;
-
-               path->ctls[NID_PATH_BOOST_CTL] = val;
-       }
-       return 0;
-}
-
-#ifdef CONFIG_SND_HDA_GENERIC_LEDS
-/*
- * vmaster mute LED hook helpers
- */
-
-static int create_mute_led_cdev(struct hda_codec *codec,
-                               int (*callback)(struct led_classdev *,
-                                               enum led_brightness),
-                               bool micmute)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct led_classdev *cdev;
-       int idx = micmute ? LED_AUDIO_MICMUTE : LED_AUDIO_MUTE;
-       int err;
-
-       cdev = devm_kzalloc(&codec->core.dev, sizeof(*cdev), GFP_KERNEL);
-       if (!cdev)
-               return -ENOMEM;
-
-       cdev->name = micmute ? "hda::micmute" : "hda::mute";
-       cdev->max_brightness = 1;
-       cdev->default_trigger = micmute ? "audio-micmute" : "audio-mute";
-       cdev->brightness_set_blocking = callback;
-       cdev->flags = LED_CORE_SUSPENDRESUME;
-
-       err = led_classdev_register(&codec->core.dev, cdev);
-       if (err < 0)
-               return err;
-       spec->led_cdevs[idx] = cdev;
-       return 0;
-}
-
-/**
- * snd_hda_gen_add_mute_led_cdev - Create a LED classdev and enable as vmaster mute LED
- * @codec: the HDA codec
- * @callback: the callback for LED classdev brightness_set_blocking
- */
-int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
-                                 int (*callback)(struct led_classdev *,
-                                                 enum led_brightness))
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err;
-
-       if (callback) {
-               err = create_mute_led_cdev(codec, callback, false);
-               if (err) {
-                       codec_warn(codec, "failed to create a mute LED cdev\n");
-                       return err;
-               }
-       }
-
-       if (spec->vmaster_mute.hook)
-               codec_err(codec, "vmaster hook already present before cdev!\n");
-
-       spec->vmaster_mute_led = 1;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_add_mute_led_cdev);
-
-/**
- * snd_hda_gen_add_micmute_led_cdev - Create a LED classdev and enable as mic-mute LED
- * @codec: the HDA codec
- * @callback: the callback for LED classdev brightness_set_blocking
- *
- * Called from the codec drivers for offering the mic mute LED controls.
- * This creates a LED classdev and sets up the cap_sync_hook that is called at
- * each time when the capture mixer switch changes.
- *
- * When NULL is passed to @callback, no classdev is created but only the
- * LED-trigger is set up.
- *
- * Returns 0 or a negative error.
- */
-int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
-                                    int (*callback)(struct led_classdev *,
-                                                    enum led_brightness))
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err;
-
-       if (callback) {
-               err = create_mute_led_cdev(codec, callback, true);
-               if (err) {
-                       codec_warn(codec, "failed to create a mic-mute LED cdev\n");
-                       return err;
-               }
-       }
-
-       spec->mic_mute_led = 1;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_add_micmute_led_cdev);
-#endif /* CONFIG_SND_HDA_GENERIC_LEDS */
-
-/*
- * parse digital I/Os and set up NIDs in BIOS auto-parse mode
- */
-static void parse_digital(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *path;
-       int i, nums;
-       hda_nid_t dig_nid, pin;
-
-       /* support multiple SPDIFs; the secondary is set up as a follower */
-       nums = 0;
-       for (i = 0; i < spec->autocfg.dig_outs; i++) {
-               pin = spec->autocfg.dig_out_pins[i];
-               dig_nid = look_for_dac(codec, pin, true);
-               if (!dig_nid)
-                       continue;
-               path = snd_hda_add_new_path(codec, dig_nid, pin, 0);
-               if (!path)
-                       continue;
-               print_nid_path(codec, "digout", path);
-               path->active = true;
-               path->pin_fixed = true; /* no jack detection */
-               spec->digout_paths[i] = snd_hda_get_path_idx(codec, path);
-               set_pin_target(codec, pin, PIN_OUT, false);
-               if (!nums) {
-                       spec->multiout.dig_out_nid = dig_nid;
-                       spec->dig_out_type = spec->autocfg.dig_out_type[0];
-               } else {
-                       spec->multiout.follower_dig_outs = spec->follower_dig_outs;
-                       if (nums >= ARRAY_SIZE(spec->follower_dig_outs) - 1)
-                               break;
-                       spec->follower_dig_outs[nums - 1] = dig_nid;
-               }
-               nums++;
-       }
-
-       if (spec->autocfg.dig_in_pin) {
-               pin = spec->autocfg.dig_in_pin;
-               for_each_hda_codec_node(dig_nid, codec) {
-                       unsigned int wcaps = get_wcaps(codec, dig_nid);
-                       if (get_wcaps_type(wcaps) != AC_WID_AUD_IN)
-                               continue;
-                       if (!(wcaps & AC_WCAP_DIGITAL))
-                               continue;
-                       path = snd_hda_add_new_path(codec, pin, dig_nid, 0);
-                       if (path) {
-                               print_nid_path(codec, "digin", path);
-                               path->active = true;
-                               path->pin_fixed = true; /* no jack */
-                               spec->dig_in_nid = dig_nid;
-                               spec->digin_path = snd_hda_get_path_idx(codec, path);
-                               set_pin_target(codec, pin, PIN_IN, false);
-                               break;
-                       }
-               }
-       }
-}
-
-
-/*
- * input MUX handling
- */
-
-static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur);
-
-/* select the given imux item; either unmute exclusively or select the route */
-static int mux_select(struct hda_codec *codec, unsigned int adc_idx,
-                     unsigned int idx)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const struct hda_input_mux *imux;
-       struct nid_path *old_path, *path;
-
-       imux = &spec->input_mux;
-       if (!imux->num_items)
-               return 0;
-
-       if (idx >= imux->num_items)
-               idx = imux->num_items - 1;
-       if (spec->cur_mux[adc_idx] == idx)
-               return 0;
-
-       old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]);
-       if (!old_path)
-               return 0;
-       if (old_path->active)
-               snd_hda_activate_path(codec, old_path, false, false);
-
-       spec->cur_mux[adc_idx] = idx;
-
-       if (spec->hp_mic)
-               update_hp_mic(codec, adc_idx, false);
-
-       if (spec->dyn_adc_switch)
-               dyn_adc_pcm_resetup(codec, idx);
-
-       path = get_input_path(codec, adc_idx, idx);
-       if (!path)
-               return 0;
-       if (path->active)
-               return 0;
-       snd_hda_activate_path(codec, path, true, false);
-       if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, NULL, NULL);
-       path_power_down_sync(codec, old_path);
-       return 1;
-}
-
-/* power up/down widgets in the all paths that match with the given NID
- * as terminals (either start- or endpoint)
- *
- * returns the last changed NID, or zero if unchanged.
- */
-static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid,
-                               int pin_state, int stream_state)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       hda_nid_t last, changed = 0;
-       struct nid_path *path;
-       int n;
-
-       snd_array_for_each(&spec->paths, n, path) {
-               if (!path->depth)
-                       continue;
-               if (path->path[0] == nid ||
-                   path->path[path->depth - 1] == nid) {
-                       bool pin_old = path->pin_enabled;
-                       bool stream_old = path->stream_enabled;
-
-                       if (pin_state >= 0)
-                               path->pin_enabled = pin_state;
-                       if (stream_state >= 0)
-                               path->stream_enabled = stream_state;
-                       if ((!path->pin_fixed && path->pin_enabled != pin_old)
-                           || path->stream_enabled != stream_old) {
-                               last = path_power_update(codec, path, true);
-                               if (last)
-                                       changed = last;
-                       }
-               }
-       }
-       return changed;
-}
-
-/* check the jack status for power control */
-static bool detect_pin_state(struct hda_codec *codec, hda_nid_t pin)
-{
-       if (!is_jack_detectable(codec, pin))
-               return true;
-       return snd_hda_jack_detect_state(codec, pin) != HDA_JACK_NOT_PRESENT;
-}
-
-/* power up/down the paths of the given pin according to the jack state;
- * power = 0/1 : only power up/down if it matches with the jack state,
- *       < 0   : force power up/down to follow the jack sate
- *
- * returns the last changed NID, or zero if unchanged.
- */
-static hda_nid_t set_pin_power_jack(struct hda_codec *codec, hda_nid_t pin,
-                                   int power)
-{
-       bool on;
-
-       if (!codec->power_save_node)
-               return 0;
-
-       on = detect_pin_state(codec, pin);
-
-       if (power >= 0 && on != power)
-               return 0;
-       return set_path_power(codec, pin, on, -1);
-}
-
-static void pin_power_callback(struct hda_codec *codec,
-                              struct hda_jack_callback *jack,
-                              bool on)
-{
-       if (jack && jack->nid)
-               sync_power_state_change(codec,
-                                       set_pin_power_jack(codec, jack->nid, on));
-}
-
-/* callback only doing power up -- called at first */
-static void pin_power_up_callback(struct hda_codec *codec,
-                                 struct hda_jack_callback *jack)
-{
-       pin_power_callback(codec, jack, true);
-}
-
-/* callback only doing power down -- called at last */
-static void pin_power_down_callback(struct hda_codec *codec,
-                                   struct hda_jack_callback *jack)
-{
-       pin_power_callback(codec, jack, false);
-}
-
-/* set up the power up/down callbacks */
-static void add_pin_power_ctls(struct hda_codec *codec, int num_pins,
-                              const hda_nid_t *pins, bool on)
-{
-       int i;
-       hda_jack_callback_fn cb =
-               on ? pin_power_up_callback : pin_power_down_callback;
-
-       for (i = 0; i < num_pins && pins[i]; i++) {
-               if (is_jack_detectable(codec, pins[i]))
-                       snd_hda_jack_detect_enable_callback(codec, pins[i], cb);
-               else
-                       set_path_power(codec, pins[i], true, -1);
-       }
-}
-
-/* enabled power callback to each available I/O pin with jack detections;
- * the digital I/O pins are excluded because of the unreliable detectsion
- */
-static void add_all_pin_power_ctls(struct hda_codec *codec, bool on)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       if (!codec->power_save_node)
-               return;
-       add_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins, on);
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-               add_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins, on);
-       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
-               add_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, on);
-       for (i = 0; i < cfg->num_inputs; i++)
-               add_pin_power_ctls(codec, 1, &cfg->inputs[i].pin, on);
-}
-
-/* sync path power up/down with the jack states of given pins */
-static void sync_pin_power_ctls(struct hda_codec *codec, int num_pins,
-                               const hda_nid_t *pins)
-{
-       int i;
-
-       for (i = 0; i < num_pins && pins[i]; i++)
-               if (is_jack_detectable(codec, pins[i]))
-                       set_pin_power_jack(codec, pins[i], -1);
-}
-
-/* sync path power up/down with pins; called at init and resume */
-static void sync_all_pin_power_ctls(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       if (!codec->power_save_node)
-               return;
-       sync_pin_power_ctls(codec, cfg->line_outs, cfg->line_out_pins);
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-               sync_pin_power_ctls(codec, cfg->hp_outs, cfg->hp_pins);
-       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
-               sync_pin_power_ctls(codec, cfg->speaker_outs, cfg->speaker_pins);
-       for (i = 0; i < cfg->num_inputs; i++)
-               sync_pin_power_ctls(codec, 1, &cfg->inputs[i].pin);
-}
-
-/* add fake paths if not present yet */
-static int add_fake_paths(struct hda_codec *codec, hda_nid_t nid,
-                          int num_pins, const hda_nid_t *pins)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *path;
-       int i;
-
-       for (i = 0; i < num_pins; i++) {
-               if (!pins[i])
-                       break;
-               if (get_nid_path(codec, nid, pins[i], 0))
-                       continue;
-               path = snd_array_new(&spec->paths);
-               if (!path)
-                       return -ENOMEM;
-               memset(path, 0, sizeof(*path));
-               path->depth = 2;
-               path->path[0] = nid;
-               path->path[1] = pins[i];
-               path->active = true;
-       }
-       return 0;
-}
-
-/* create fake paths to all outputs from beep */
-static int add_fake_beep_paths(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       hda_nid_t nid = spec->beep_nid;
-       int err;
-
-       if (!codec->power_save_node || !nid)
-               return 0;
-       err = add_fake_paths(codec, nid, cfg->line_outs, cfg->line_out_pins);
-       if (err < 0)
-               return err;
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
-               err = add_fake_paths(codec, nid, cfg->hp_outs, cfg->hp_pins);
-               if (err < 0)
-                       return err;
-       }
-       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-               err = add_fake_paths(codec, nid, cfg->speaker_outs,
-                                    cfg->speaker_pins);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-/* power up/down beep widget and its output paths */
-static void beep_power_hook(struct hda_beep *beep, bool on)
-{
-       set_path_power(beep->codec, beep->nid, -1, on);
-}
-
-/**
- * snd_hda_gen_fix_pin_power - Fix the power of the given pin widget to D0
- * @codec: the HDA codec
- * @pin: NID of pin to fix
- */
-int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct nid_path *path;
-
-       path = snd_array_new(&spec->paths);
-       if (!path)
-               return -ENOMEM;
-       memset(path, 0, sizeof(*path));
-       path->depth = 1;
-       path->path[0] = pin;
-       path->active = true;
-       path->pin_fixed = true;
-       path->stream_enabled = true;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_fix_pin_power);
-
-/*
- * Jack detections for HP auto-mute and mic-switch
- */
-
-/* check each pin in the given array; returns true if any of them is plugged */
-static bool detect_jacks(struct hda_codec *codec, int num_pins, const hda_nid_t *pins)
-{
-       int i;
-       bool present = false;
-
-       for (i = 0; i < num_pins; i++) {
-               hda_nid_t nid = pins[i];
-               if (!nid)
-                       break;
-               /* don't detect pins retasked as inputs */
-               if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN)
-                       continue;
-               if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT)
-                       present = true;
-       }
-       return present;
-}
-
-/* standard HP/line-out auto-mute helper */
-static void do_automute(struct hda_codec *codec, int num_pins, const hda_nid_t *pins,
-                       int *paths, bool mute)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < num_pins; i++) {
-               hda_nid_t nid = pins[i];
-               unsigned int val, oldval;
-               if (!nid)
-                       break;
-
-               oldval = snd_hda_codec_get_pin_target(codec, nid);
-               if (oldval & PIN_IN)
-                       continue; /* no mute for inputs */
-
-               if (spec->auto_mute_via_amp) {
-                       struct nid_path *path;
-                       hda_nid_t mute_nid;
-
-                       path = snd_hda_get_path_from_idx(codec, paths[i]);
-                       if (!path)
-                               continue;
-                       mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]);
-                       if (!mute_nid)
-                               continue;
-                       if (mute)
-                               spec->mute_bits |= (1ULL << mute_nid);
-                       else
-                               spec->mute_bits &= ~(1ULL << mute_nid);
-                       continue;
-               } else {
-                       /* don't reset VREF value in case it's controlling
-                        * the amp (see alc861_fixup_asus_amp_vref_0f())
-                        */
-                       if (spec->keep_vref_in_automute)
-                               val = oldval & ~PIN_HP;
-                       else
-                               val = 0;
-                       if (!mute)
-                               val |= oldval;
-                       /* here we call update_pin_ctl() so that the pinctl is
-                        * changed without changing the pinctl target value;
-                        * the original target value will be still referred at
-                        * the init / resume again
-                        */
-                       update_pin_ctl(codec, nid, val);
-               }
-
-               set_pin_eapd(codec, nid, !mute);
-               if (codec->power_save_node) {
-                       bool on = !mute;
-                       if (on)
-                               on = detect_pin_state(codec, nid);
-                       set_path_power(codec, nid, on, -1);
-               }
-       }
-}
-
-/**
- * snd_hda_gen_update_outputs - Toggle outputs muting
- * @codec: the HDA codec
- *
- * Update the mute status of all outputs based on the current jack states.
- */
-void snd_hda_gen_update_outputs(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int *paths;
-       int on;
-
-       /* Control HP pins/amps depending on master_mute state;
-        * in general, HP pins/amps control should be enabled in all cases,
-        * but currently set only for master_mute, just to be safe
-        */
-       if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)
-               paths = spec->out_paths;
-       else
-               paths = spec->hp_paths;
-       do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins),
-                   spec->autocfg.hp_pins, paths, spec->master_mute);
-
-       if (!spec->automute_speaker)
-               on = 0;
-       else
-               on = spec->hp_jack_present | spec->line_jack_present;
-       on |= spec->master_mute;
-       spec->speaker_muted = on;
-       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
-               paths = spec->out_paths;
-       else
-               paths = spec->speaker_paths;
-       do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins),
-                   spec->autocfg.speaker_pins, paths, on);
-
-       /* toggle line-out mutes if needed, too */
-       /* if LO is a copy of either HP or Speaker, don't need to handle it */
-       if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] ||
-           spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0])
-               return;
-       if (!spec->automute_lo)
-               on = 0;
-       else
-               on = spec->hp_jack_present;
-       on |= spec->master_mute;
-       spec->line_out_muted = on;
-       paths = spec->out_paths;
-       do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
-                   spec->autocfg.line_out_pins, paths, on);
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs);
-
-static void call_update_outputs(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->automute_hook)
-               spec->automute_hook(codec);
-       else
-               snd_hda_gen_update_outputs(codec);
-
-       /* sync the whole vmaster followers to reflect the new auto-mute status */
-       if (spec->auto_mute_via_amp && !codec->bus->shutdown)
-               snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
-}
-
-/**
- * snd_hda_gen_hp_automute - standard HP-automute helper
- * @codec: the HDA codec
- * @jack: jack object, NULL for the whole
- */
-void snd_hda_gen_hp_automute(struct hda_codec *codec,
-                            struct hda_jack_callback *jack)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       hda_nid_t *pins = spec->autocfg.hp_pins;
-       int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins);
-
-       /* No detection for the first HP jack during indep-HP mode */
-       if (spec->indep_hp_enabled) {
-               pins++;
-               num_pins--;
-       }
-
-       spec->hp_jack_present = detect_jacks(codec, num_pins, pins);
-       if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo))
-               return;
-       call_update_outputs(codec);
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
-
-/**
- * snd_hda_gen_line_automute - standard line-out-automute helper
- * @codec: the HDA codec
- * @jack: jack object, NULL for the whole
- */
-void snd_hda_gen_line_automute(struct hda_codec *codec,
-                              struct hda_jack_callback *jack)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
-               return;
-       /* check LO jack only when it's different from HP */
-       if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0])
-               return;
-
-       spec->line_jack_present =
-               detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins),
-                            spec->autocfg.line_out_pins);
-       if (!spec->automute_speaker || !spec->detect_lo)
-               return;
-       call_update_outputs(codec);
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
-
-/**
- * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper
- * @codec: the HDA codec
- * @jack: jack object, NULL for the whole
- */
-void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
-                               struct hda_jack_callback *jack)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-
-       if (!spec->auto_mic)
-               return;
-
-       for (i = spec->am_num_entries - 1; i > 0; i--) {
-               hda_nid_t pin = spec->am_entry[i].pin;
-               /* don't detect pins retasked as outputs */
-               if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN)
-                       continue;
-               if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) {
-                       mux_select(codec, 0, spec->am_entry[i].idx);
-                       return;
-               }
-       }
-       mux_select(codec, 0, spec->am_entry[0].idx);
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch);
-
-/* call appropriate hooks */
-static void call_hp_automute(struct hda_codec *codec,
-                            struct hda_jack_callback *jack)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->hp_automute_hook)
-               spec->hp_automute_hook(codec, jack);
-       else
-               snd_hda_gen_hp_automute(codec, jack);
-}
-
-static void call_line_automute(struct hda_codec *codec,
-                              struct hda_jack_callback *jack)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->line_automute_hook)
-               spec->line_automute_hook(codec, jack);
-       else
-               snd_hda_gen_line_automute(codec, jack);
-}
-
-static void call_mic_autoswitch(struct hda_codec *codec,
-                               struct hda_jack_callback *jack)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->mic_autoswitch_hook)
-               spec->mic_autoswitch_hook(codec, jack);
-       else
-               snd_hda_gen_mic_autoswitch(codec, jack);
-}
-
-/* update jack retasking */
-static void update_automute_all(struct hda_codec *codec)
-{
-       call_hp_automute(codec, NULL);
-       call_line_automute(codec, NULL);
-       call_mic_autoswitch(codec, NULL);
-}
-
-/*
- * Auto-Mute mode mixer enum support
- */
-static int automute_mode_info(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       static const char * const texts3[] = {
-               "Disabled", "Speaker Only", "Line Out+Speaker"
-       };
-
-       if (spec->automute_speaker_possible && spec->automute_lo_possible)
-               return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
-       return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
-}
-
-static int automute_mode_get(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-       unsigned int val = 0;
-       if (spec->automute_speaker)
-               val++;
-       if (spec->automute_lo)
-               val++;
-
-       ucontrol->value.enumerated.item[0] = val;
-       return 0;
-}
-
-static int automute_mode_put(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hda_gen_spec *spec = codec->spec;
-
-       switch (ucontrol->value.enumerated.item[0]) {
-       case 0:
-               if (!spec->automute_speaker && !spec->automute_lo)
-                       return 0;
-               spec->automute_speaker = 0;
-               spec->automute_lo = 0;
-               break;
-       case 1:
-               if (spec->automute_speaker_possible) {
-                       if (!spec->automute_lo && spec->automute_speaker)
-                               return 0;
-                       spec->automute_speaker = 1;
-                       spec->automute_lo = 0;
-               } else if (spec->automute_lo_possible) {
-                       if (spec->automute_lo)
-                               return 0;
-                       spec->automute_lo = 1;
-               } else
-                       return -EINVAL;
-               break;
-       case 2:
-               if (!spec->automute_lo_possible || !spec->automute_speaker_possible)
-                       return -EINVAL;
-               if (spec->automute_speaker && spec->automute_lo)
-                       return 0;
-               spec->automute_speaker = 1;
-               spec->automute_lo = 1;
-               break;
-       default:
-               return -EINVAL;
-       }
-       call_update_outputs(codec);
-       return 1;
-}
-
-static const struct snd_kcontrol_new automute_mode_enum = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Auto-Mute Mode",
-       .info = automute_mode_info,
-       .get = automute_mode_get,
-       .put = automute_mode_put,
-};
-
-static int add_automute_mode_enum(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum))
-               return -ENOMEM;
-       return 0;
-}
-
-/*
- * Check the availability of HP/line-out auto-mute;
- * Set up appropriately if really supported
- */
-static int check_auto_mute_availability(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int present = 0;
-       int i, err;
-
-       if (spec->suppress_auto_mute)
-               return 0;
-
-       if (cfg->hp_pins[0])
-               present++;
-       if (cfg->line_out_pins[0])
-               present++;
-       if (cfg->speaker_pins[0])
-               present++;
-       if (present < 2) /* need two different output types */
-               return 0;
-
-       if (!cfg->speaker_pins[0] &&
-           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) {
-               memcpy(cfg->speaker_pins, cfg->line_out_pins,
-                      sizeof(cfg->speaker_pins));
-               cfg->speaker_outs = cfg->line_outs;
-       }
-
-       if (!cfg->hp_pins[0] &&
-           cfg->line_out_type == AUTO_PIN_HP_OUT) {
-               memcpy(cfg->hp_pins, cfg->line_out_pins,
-                      sizeof(cfg->hp_pins));
-               cfg->hp_outs = cfg->line_outs;
-       }
-
-       for (i = 0; i < cfg->hp_outs; i++) {
-               hda_nid_t nid = cfg->hp_pins[i];
-               if (!is_jack_detectable(codec, nid))
-                       continue;
-               codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid);
-               snd_hda_jack_detect_enable_callback(codec, nid,
-                                                   call_hp_automute);
-               spec->detect_hp = 1;
-       }
-
-       if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) {
-               if (cfg->speaker_outs)
-                       for (i = 0; i < cfg->line_outs; i++) {
-                               hda_nid_t nid = cfg->line_out_pins[i];
-                               if (!is_jack_detectable(codec, nid))
-                                       continue;
-                               codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid);
-                               snd_hda_jack_detect_enable_callback(codec, nid,
-                                                                   call_line_automute);
-                               spec->detect_lo = 1;
-                       }
-               spec->automute_lo_possible = spec->detect_hp;
-       }
-
-       spec->automute_speaker_possible = cfg->speaker_outs &&
-               (spec->detect_hp || spec->detect_lo);
-
-       spec->automute_lo = spec->automute_lo_possible;
-       spec->automute_speaker = spec->automute_speaker_possible;
-
-       if (spec->automute_speaker_possible || spec->automute_lo_possible) {
-               /* create a control for automute mode */
-               err = add_automute_mode_enum(codec);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-
-/* check whether all auto-mic pins are valid; setup indices if OK */
-static bool auto_mic_check_imux(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const struct hda_input_mux *imux;
-       int i;
-
-       imux = &spec->input_mux;
-       for (i = 0; i < spec->am_num_entries; i++) {
-               spec->am_entry[i].idx =
-                       find_idx_in_nid_list(spec->am_entry[i].pin,
-                                            spec->imux_pins, imux->num_items);
-               if (spec->am_entry[i].idx < 0)
-                       return false; /* no corresponding imux */
-       }
-
-       /* we don't need the jack detection for the first pin */
-       for (i = 1; i < spec->am_num_entries; i++)
-               snd_hda_jack_detect_enable_callback(codec,
-                                                   spec->am_entry[i].pin,
-                                                   call_mic_autoswitch);
-       return true;
-}
-
-static int compare_attr(const void *ap, const void *bp)
-{
-       const struct automic_entry *a = ap;
-       const struct automic_entry *b = bp;
-       return (int)(a->attr - b->attr);
-}
-
-/*
- * Check the availability of auto-mic switch;
- * Set up if really supported
- */
-static int check_auto_mic_availability(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int types;
-       int i, num_pins;
-
-       if (spec->suppress_auto_mic)
-               return 0;
-
-       types = 0;
-       num_pins = 0;
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               unsigned int attr;
-               attr = snd_hda_codec_get_pincfg(codec, nid);
-               attr = snd_hda_get_input_pin_attr(attr);
-               if (types & (1 << attr))
-                       return 0; /* already occupied */
-               switch (attr) {
-               case INPUT_PIN_ATTR_INT:
-                       if (cfg->inputs[i].type != AUTO_PIN_MIC)
-                               return 0; /* invalid type */
-                       break;
-               case INPUT_PIN_ATTR_UNUSED:
-                       return 0; /* invalid entry */
-               default:
-                       if (cfg->inputs[i].type > AUTO_PIN_LINE_IN)
-                               return 0; /* invalid type */
-                       if (!spec->line_in_auto_switch &&
-                           cfg->inputs[i].type != AUTO_PIN_MIC)
-                               return 0; /* only mic is allowed */
-                       if (!is_jack_detectable(codec, nid))
-                               return 0; /* no unsol support */
-                       break;
-               }
-               if (num_pins >= MAX_AUTO_MIC_PINS)
-                       return 0;
-               types |= (1 << attr);
-               spec->am_entry[num_pins].pin = nid;
-               spec->am_entry[num_pins].attr = attr;
-               num_pins++;
-       }
-
-       if (num_pins < 2)
-               return 0;
-
-       spec->am_num_entries = num_pins;
-       /* sort the am_entry in the order of attr so that the pin with a
-        * higher attr will be selected when the jack is plugged.
-        */
-       sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]),
-            compare_attr, NULL);
-
-       if (!auto_mic_check_imux(codec))
-               return 0;
-
-       spec->auto_mic = 1;
-       spec->num_adc_nids = 1;
-       spec->cur_mux[0] = spec->am_entry[0].idx;
-       codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n",
-                   spec->am_entry[0].pin,
-                   spec->am_entry[1].pin,
-                   spec->am_entry[2].pin);
-
-       return 0;
-}
-
-/**
- * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets
- * into power down
- * @codec: the HDA codec
- * @nid: NID to evalute
- * @power_state: target power state
- */
-unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
-                                                 hda_nid_t nid,
-                                                 unsigned int power_state)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (!spec->power_down_unused && !codec->power_save_node)
-               return power_state;
-       if (power_state != AC_PWRST_D0 || nid == codec->core.afg)
-               return power_state;
-       if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER)
-               return power_state;
-       if (is_active_nid_for_any(codec, nid))
-               return power_state;
-       return AC_PWRST_D3;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter);
-
-/* mute all aamix inputs initially; parse up to the first leaves */
-static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
-{
-       int i, nums;
-       const hda_nid_t *conn;
-       bool has_amp;
-
-       nums = snd_hda_get_conn_list(codec, mix, &conn);
-       has_amp = nid_has_mute(codec, mix, HDA_INPUT);
-       for (i = 0; i < nums; i++) {
-               if (has_amp)
-                       update_amp(codec, mix, HDA_INPUT, i,
-                                  0xff, HDA_AMP_MUTE);
-               else if (nid_has_volume(codec, conn[i], HDA_OUTPUT))
-                       update_amp(codec, conn[i], HDA_OUTPUT, 0,
-                                  0xff, HDA_AMP_MUTE);
-       }
-}
-
-/**
- * snd_hda_gen_stream_pm - Stream power management callback
- * @codec: the HDA codec
- * @nid: audio widget
- * @on: power on/off flag
- *
- * Set this in patch_ops.stream_pm.  Only valid with power_save_node flag.
- */
-void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on)
-{
-       if (codec->power_save_node)
-               set_path_power(codec, nid, -1, on);
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_stream_pm);
-
-/* forcibly mute the speaker output without caching; return true if updated */
-static bool force_mute_output_path(struct hda_codec *codec, hda_nid_t nid)
-{
-       if (!nid)
-               return false;
-       if (!nid_has_mute(codec, nid, HDA_OUTPUT))
-               return false; /* no mute, skip */
-       if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) &
-           snd_hda_codec_amp_read(codec, nid, 1, HDA_OUTPUT, 0) &
-           HDA_AMP_MUTE)
-               return false; /* both channels already muted, skip */
-
-       /* direct amp update without caching */
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                           AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT |
-                           AC_AMP_SET_RIGHT | HDA_AMP_MUTE);
-       return true;
-}
-
-/**
- * snd_hda_gen_shutup_speakers - Forcibly mute the speaker outputs
- * @codec: the HDA codec
- *
- * Forcibly mute the speaker outputs, to be called at suspend or shutdown.
- *
- * The mute state done by this function isn't cached, hence the original state
- * will be restored at resume.
- *
- * Return true if the mute state has been changed.
- */
-bool snd_hda_gen_shutup_speakers(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       const int *paths;
-       const struct nid_path *path;
-       int i, p, num_paths;
-       bool updated = false;
-
-       /* if already powered off, do nothing */
-       if (!snd_hdac_is_power_on(&codec->core))
-               return false;
-
-       if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
-               paths = spec->out_paths;
-               num_paths = spec->autocfg.line_outs;
-       } else {
-               paths = spec->speaker_paths;
-               num_paths = spec->autocfg.speaker_outs;
-       }
-
-       for (i = 0; i < num_paths; i++) {
-               path = snd_hda_get_path_from_idx(codec, paths[i]);
-               if (!path)
-                       continue;
-               for (p = 0; p < path->depth; p++)
-                       if (force_mute_output_path(codec, path->path[p]))
-                               updated = true;
-       }
-
-       return updated;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_shutup_speakers);
-
-/**
- * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
- * set up the hda_gen_spec
- * @codec: the HDA codec
- * @cfg: Parsed pin configuration
- *
- * return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- */
-int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
-                                 struct auto_pin_cfg *cfg)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err;
-
-       parse_user_hints(codec);
-
-       if (spec->vmaster_mute_led || spec->mic_mute_led)
-               snd_ctl_led_request();
-
-       if (spec->mixer_nid && !spec->mixer_merge_nid)
-               spec->mixer_merge_nid = spec->mixer_nid;
-
-       if (cfg != &spec->autocfg) {
-               spec->autocfg = *cfg;
-               cfg = &spec->autocfg;
-       }
-
-       if (!spec->main_out_badness)
-               spec->main_out_badness = &hda_main_out_badness;
-       if (!spec->extra_out_badness)
-               spec->extra_out_badness = &hda_extra_out_badness;
-
-       fill_all_dac_nids(codec);
-
-       if (!cfg->line_outs) {
-               if (cfg->dig_outs || cfg->dig_in_pin) {
-                       spec->multiout.max_channels = 2;
-                       spec->no_analog = 1;
-                       goto dig_only;
-               }
-               if (!cfg->num_inputs && !cfg->dig_in_pin)
-                       return 0; /* can't find valid BIOS pin config */
-       }
-
-       if (!spec->no_primary_hp &&
-           cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
-           cfg->line_outs <= cfg->hp_outs) {
-               /* use HP as primary out */
-               cfg->speaker_outs = cfg->line_outs;
-               memcpy(cfg->speaker_pins, cfg->line_out_pins,
-                      sizeof(cfg->speaker_pins));
-               cfg->line_outs = cfg->hp_outs;
-               memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins));
-               cfg->hp_outs = 0;
-               memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins));
-               cfg->line_out_type = AUTO_PIN_HP_OUT;
-       }
-
-       err = parse_output_paths(codec);
-       if (err < 0)
-               return err;
-       err = create_multi_channel_mode(codec);
-       if (err < 0)
-               return err;
-       err = create_multi_out_ctls(codec, cfg);
-       if (err < 0)
-               return err;
-       err = create_hp_out_ctls(codec);
-       if (err < 0)
-               return err;
-       err = create_speaker_out_ctls(codec);
-       if (err < 0)
-               return err;
-       err = create_indep_hp_ctls(codec);
-       if (err < 0)
-               return err;
-       err = create_loopback_mixing_ctl(codec);
-       if (err < 0)
-               return err;
-       err = create_hp_mic(codec);
-       if (err < 0)
-               return err;
-       err = create_input_ctls(codec);
-       if (err < 0)
-               return err;
-
-       /* add power-down pin callbacks at first */
-       add_all_pin_power_ctls(codec, false);
-
-       spec->const_channel_count = spec->ext_channel_count;
-       /* check the multiple speaker and headphone pins */
-       if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT)
-               spec->const_channel_count = max(spec->const_channel_count,
-                                               cfg->speaker_outs * 2);
-       if (cfg->line_out_type != AUTO_PIN_HP_OUT)
-               spec->const_channel_count = max(spec->const_channel_count,
-                                               cfg->hp_outs * 2);
-       spec->multiout.max_channels = max(spec->ext_channel_count,
-                                         spec->const_channel_count);
-
-       err = check_auto_mute_availability(codec);
-       if (err < 0)
-               return err;
-
-       err = check_dyn_adc_switch(codec);
-       if (err < 0)
-               return err;
-
-       err = check_auto_mic_availability(codec);
-       if (err < 0)
-               return err;
-
-       /* add stereo mix if available and not enabled yet */
-       if (!spec->auto_mic && spec->mixer_nid &&
-           spec->add_stereo_mix_input == HDA_HINT_STEREO_MIX_AUTO &&
-           spec->input_mux.num_items > 1) {
-               err = parse_capture_source(codec, spec->mixer_nid,
-                                          CFG_IDX_MIX, spec->num_all_adcs,
-                                          "Stereo Mix", 0);
-               if (err < 0)
-                       return err;
-       }
-
-
-       err = create_capture_mixers(codec);
-       if (err < 0)
-               return err;
-
-       err = parse_mic_boost(codec);
-       if (err < 0)
-               return err;
-
-       /* create "Headphone Mic Jack Mode" if no input selection is
-        * available (or user specifies add_jack_modes hint)
-        */
-       if (spec->hp_mic_pin &&
-           (spec->auto_mic || spec->input_mux.num_items == 1 ||
-            spec->add_jack_modes)) {
-               err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin);
-               if (err < 0)
-                       return err;
-       }
-
-       if (spec->add_jack_modes) {
-               if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) {
-                       err = create_out_jack_modes(codec, cfg->line_outs,
-                                                   cfg->line_out_pins);
-                       if (err < 0)
-                               return err;
-               }
-               if (cfg->line_out_type != AUTO_PIN_HP_OUT) {
-                       err = create_out_jack_modes(codec, cfg->hp_outs,
-                                                   cfg->hp_pins);
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       /* add power-up pin callbacks at last */
-       add_all_pin_power_ctls(codec, true);
-
-       /* mute all aamix input initially */
-       if (spec->mixer_nid)
-               mute_all_mixer_nid(codec, spec->mixer_nid);
-
- dig_only:
-       parse_digital(codec);
-
-       if (spec->power_down_unused || codec->power_save_node) {
-               if (!codec->power_filter)
-                       codec->power_filter = snd_hda_gen_path_power_filter;
-               if (!codec->patch_ops.stream_pm)
-                       codec->patch_ops.stream_pm = snd_hda_gen_stream_pm;
-       }
-
-       if (!spec->no_analog && spec->beep_nid) {
-               err = snd_hda_attach_beep_device(codec, spec->beep_nid);
-               if (err < 0)
-                       return err;
-               if (codec->beep && codec->power_save_node) {
-                       err = add_fake_beep_paths(codec);
-                       if (err < 0)
-                               return err;
-                       codec->beep->power_hook = beep_power_hook;
-               }
-       }
-
-       return 1;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config);
-
-
-/*
- * Build control elements
- */
-
-/* follower controls for virtual master */
-static const char * const follower_pfxs[] = {
-       "Front", "Surround", "Center", "LFE", "Side",
-       "Headphone", "Speaker", "Mono", "Line Out",
-       "CLFE", "Bass Speaker", "PCM",
-       "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
-       "Headphone Front", "Headphone Surround", "Headphone CLFE",
-       "Headphone Side", "Headphone+LO", "Speaker+LO",
-       NULL,
-};
-
-/**
- * snd_hda_gen_build_controls - Build controls from the parsed results
- * @codec: the HDA codec
- *
- * Pass this to build_controls patch_ops.
- */
-int snd_hda_gen_build_controls(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err;
-
-       if (spec->kctls.used) {
-               err = snd_hda_add_new_ctls(codec, spec->kctls.list);
-               if (err < 0)
-                       return err;
-       }
-
-       if (spec->multiout.dig_out_nid) {
-               err = snd_hda_create_dig_out_ctls(codec,
-                                                 spec->multiout.dig_out_nid,
-                                                 spec->multiout.dig_out_nid,
-                                                 spec->pcm_rec[1]->pcm_type);
-               if (err < 0)
-                       return err;
-               if (!spec->no_analog) {
-                       err = snd_hda_create_spdif_share_sw(codec,
-                                                           &spec->multiout);
-                       if (err < 0)
-                               return err;
-                       spec->multiout.share_spdif = 1;
-               }
-       }
-       if (spec->dig_in_nid) {
-               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       /* if we have no master control, let's create it */
-       if (!spec->no_analog && !spec->suppress_vmaster &&
-           !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) {
-               err = snd_hda_add_vmaster(codec, "Master Playback Volume",
-                                         spec->vmaster_tlv, follower_pfxs,
-                                         "Playback Volume", 0);
-               if (err < 0)
-                       return err;
-       }
-       if (!spec->no_analog && !spec->suppress_vmaster &&
-           !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) {
-               err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
-                                           NULL, follower_pfxs,
-                                           "Playback Switch", true,
-                                           spec->vmaster_mute_led ?
-                                               SNDRV_CTL_ELEM_ACCESS_SPK_LED : 0,
-                                           &spec->vmaster_mute.sw_kctl);
-               if (err < 0)
-                       return err;
-               if (spec->vmaster_mute.hook) {
-                       snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute);
-                       snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
-               }
-       }
-
-       free_kctls(spec); /* no longer needed */
-
-       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls);
-
-
-/*
- * PCM definitions
- */
-
-static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream,
-                                  int action)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->pcm_playback_hook)
-               spec->pcm_playback_hook(hinfo, codec, substream, action);
-}
-
-static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 struct snd_pcm_substream *substream,
-                                 int action)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       if (spec->pcm_capture_hook)
-               spec->pcm_capture_hook(hinfo, codec, substream, action);
-}
-
-/*
- * Analog playback callbacks
- */
-static int playback_pcm_open(struct hda_pcm_stream *hinfo,
-                            struct hda_codec *codec,
-                            struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err;
-
-       mutex_lock(&spec->pcm_mutex);
-       err = snd_hda_multi_out_analog_open(codec,
-                                           &spec->multiout, substream,
-                                            hinfo);
-       if (!err) {
-               spec->active_streams |= 1 << STREAM_MULTI_OUT;
-               call_pcm_playback_hook(hinfo, codec, substream,
-                                      HDA_GEN_PCM_ACT_OPEN);
-       }
-       mutex_unlock(&spec->pcm_mutex);
-       return err;
-}
-
-static int playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                               struct hda_codec *codec,
-                               unsigned int stream_tag,
-                               unsigned int format,
-                               struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout,
-                                              stream_tag, format, substream);
-       if (!err)
-               call_pcm_playback_hook(hinfo, codec, substream,
-                                      HDA_GEN_PCM_ACT_PREPARE);
-       return err;
-}
-
-static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                               struct hda_codec *codec,
-                               struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout);
-       if (!err)
-               call_pcm_playback_hook(hinfo, codec, substream,
-                                      HDA_GEN_PCM_ACT_CLEANUP);
-       return err;
-}
-
-static int playback_pcm_close(struct hda_pcm_stream *hinfo,
-                             struct hda_codec *codec,
-                             struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       mutex_lock(&spec->pcm_mutex);
-       spec->active_streams &= ~(1 << STREAM_MULTI_OUT);
-       call_pcm_playback_hook(hinfo, codec, substream,
-                              HDA_GEN_PCM_ACT_CLOSE);
-       mutex_unlock(&spec->pcm_mutex);
-       return 0;
-}
-
-static int capture_pcm_open(struct hda_pcm_stream *hinfo,
-                           struct hda_codec *codec,
-                           struct snd_pcm_substream *substream)
-{
-       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN);
-       return 0;
-}
-
-static int capture_pcm_prepare(struct hda_pcm_stream *hinfo,
-                              struct hda_codec *codec,
-                              unsigned int stream_tag,
-                              unsigned int format,
-                              struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
-       call_pcm_capture_hook(hinfo, codec, substream,
-                             HDA_GEN_PCM_ACT_PREPARE);
-       return 0;
-}
-
-static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                              struct hda_codec *codec,
-                              struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
-       call_pcm_capture_hook(hinfo, codec, substream,
-                             HDA_GEN_PCM_ACT_CLEANUP);
-       return 0;
-}
-
-static int capture_pcm_close(struct hda_pcm_stream *hinfo,
-                            struct hda_codec *codec,
-                            struct snd_pcm_substream *substream)
-{
-       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE);
-       return 0;
-}
-
-static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                struct hda_codec *codec,
-                                struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err = 0;
-
-       mutex_lock(&spec->pcm_mutex);
-       if (spec->indep_hp && !spec->indep_hp_enabled)
-               err = -EBUSY;
-       else
-               spec->active_streams |= 1 << STREAM_INDEP_HP;
-       call_pcm_playback_hook(hinfo, codec, substream,
-                              HDA_GEN_PCM_ACT_OPEN);
-       mutex_unlock(&spec->pcm_mutex);
-       return err;
-}
-
-static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       mutex_lock(&spec->pcm_mutex);
-       spec->active_streams &= ~(1 << STREAM_INDEP_HP);
-       call_pcm_playback_hook(hinfo, codec, substream,
-                              HDA_GEN_PCM_ACT_CLOSE);
-       mutex_unlock(&spec->pcm_mutex);
-       return 0;
-}
-
-static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   unsigned int stream_tag,
-                                   unsigned int format,
-                                   struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format);
-       call_pcm_playback_hook(hinfo, codec, substream,
-                              HDA_GEN_PCM_ACT_PREPARE);
-       return 0;
-}
-
-static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
-       call_pcm_playback_hook(hinfo, codec, substream,
-                              HDA_GEN_PCM_ACT_CLEANUP);
-       return 0;
-}
-
-/*
- * Digital out
- */
-static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                struct hda_codec *codec,
-                                struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   unsigned int stream_tag,
-                                   unsigned int format,
-                                   struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
-                                            stream_tag, format, substream);
-}
-
-static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
-}
-
-static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-/*
- * Analog capture
- */
-#define alt_capture_pcm_open   capture_pcm_open
-#define alt_capture_pcm_close  capture_pcm_close
-
-static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  unsigned int stream_tag,
-                                  unsigned int format,
-                                  struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1],
-                                  stream_tag, 0, format);
-       call_pcm_capture_hook(hinfo, codec, substream,
-                             HDA_GEN_PCM_ACT_PREPARE);
-       return 0;
-}
-
-static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       snd_hda_codec_cleanup_stream(codec,
-                                    spec->adc_nids[substream->number + 1]);
-       call_pcm_capture_hook(hinfo, codec, substream,
-                             HDA_GEN_PCM_ACT_CLEANUP);
-       return 0;
-}
-
-/*
- */
-static const struct hda_pcm_stream pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 8,
-       /* NID is set in build_pcms */
-       .ops = {
-               .open = playback_pcm_open,
-               .close = playback_pcm_close,
-               .prepare = playback_pcm_prepare,
-               .cleanup = playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in build_pcms */
-       .ops = {
-               .open = capture_pcm_open,
-               .close = capture_pcm_close,
-               .prepare = capture_pcm_prepare,
-               .cleanup = capture_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream pcm_analog_alt_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in build_pcms */
-       .ops = {
-               .open = alt_playback_pcm_open,
-               .close = alt_playback_pcm_close,
-               .prepare = alt_playback_pcm_prepare,
-               .cleanup = alt_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream pcm_analog_alt_capture = {
-       .substreams = 2, /* can be overridden */
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in build_pcms */
-       .ops = {
-               .open = alt_capture_pcm_open,
-               .close = alt_capture_pcm_close,
-               .prepare = alt_capture_pcm_prepare,
-               .cleanup = alt_capture_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in build_pcms */
-       .ops = {
-               .open = dig_playback_pcm_open,
-               .close = dig_playback_pcm_close,
-               .prepare = dig_playback_pcm_prepare,
-               .cleanup = dig_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream pcm_digital_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       /* NID is set in build_pcms */
-};
-
-/* Used by build_pcms to flag that a PCM has no playback stream */
-static const struct hda_pcm_stream pcm_null_stream = {
-       .substreams = 0,
-       .channels_min = 0,
-       .channels_max = 0,
-};
-
-/*
- * dynamic changing ADC PCM streams
- */
-static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]];
-
-       if (spec->cur_adc && spec->cur_adc != new_adc) {
-               /* stream is running, let's swap the current ADC */
-               __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1);
-               spec->cur_adc = new_adc;
-               snd_hda_codec_setup_stream(codec, new_adc,
-                                          spec->cur_adc_stream_tag, 0,
-                                          spec->cur_adc_format);
-               return true;
-       }
-       return false;
-}
-
-/* analog capture with dynamic dual-adc changes */
-static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      unsigned int stream_tag,
-                                      unsigned int format,
-                                      struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]];
-       spec->cur_adc_stream_tag = stream_tag;
-       spec->cur_adc_format = format;
-       snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format);
-       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_PREPARE);
-       return 0;
-}
-
-static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      struct snd_pcm_substream *substream)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       snd_hda_codec_cleanup_stream(codec, spec->cur_adc);
-       spec->cur_adc = 0;
-       call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLEANUP);
-       return 0;
-}
-
-static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .nid = 0, /* fill later */
-       .ops = {
-               .prepare = dyn_adc_capture_pcm_prepare,
-               .cleanup = dyn_adc_capture_pcm_cleanup
-       },
-};
-
-static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
-                                const char *chip_name)
-{
-       char *p;
-
-       if (*str)
-               return;
-       strscpy(str, chip_name, len);
-
-       /* drop non-alnum chars after a space */
-       for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) {
-               if (!isalnum(p[1])) {
-                       *p = 0;
-                       break;
-               }
-       }
-       strlcat(str, sfx, len);
-}
-
-/* copy PCM stream info from @default_str, and override non-NULL entries
- * from @spec_str and @nid
- */
-static void setup_pcm_stream(struct hda_pcm_stream *str,
-                            const struct hda_pcm_stream *default_str,
-                            const struct hda_pcm_stream *spec_str,
-                            hda_nid_t nid)
-{
-       *str = *default_str;
-       if (nid)
-               str->nid = nid;
-       if (spec_str) {
-               if (spec_str->substreams)
-                       str->substreams = spec_str->substreams;
-               if (spec_str->channels_min)
-                       str->channels_min = spec_str->channels_min;
-               if (spec_str->channels_max)
-                       str->channels_max = spec_str->channels_max;
-               if (spec_str->rates)
-                       str->rates = spec_str->rates;
-               if (spec_str->formats)
-                       str->formats = spec_str->formats;
-               if (spec_str->maxbps)
-                       str->maxbps = spec_str->maxbps;
-       }
-}
-
-/**
- * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
- * @codec: the HDA codec
- *
- * Pass this to build_pcms patch_ops.
- */
-int snd_hda_gen_build_pcms(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct hda_pcm *info;
-       bool have_multi_adcs;
-
-       if (spec->no_analog)
-               goto skip_analog;
-
-       fill_pcm_stream_name(spec->stream_name_analog,
-                            sizeof(spec->stream_name_analog),
-                            " Analog", codec->core.chip_name);
-       info = snd_hda_codec_pcm_new(codec, "%s", spec->stream_name_analog);
-       if (!info)
-               return -ENOMEM;
-       spec->pcm_rec[0] = info;
-
-       if (spec->multiout.num_dacs > 0) {
-               setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
-                                &pcm_analog_playback,
-                                spec->stream_analog_playback,
-                                spec->multiout.dac_nids[0]);
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
-                       spec->multiout.max_channels;
-               if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT &&
-                   spec->autocfg.line_outs == 2)
-                       info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap =
-                               snd_pcm_2_1_chmaps;
-       }
-       if (spec->num_adc_nids) {
-               setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
-                                (spec->dyn_adc_switch ?
-                                 &dyn_adc_pcm_analog_capture : &pcm_analog_capture),
-                                spec->stream_analog_capture,
-                                spec->adc_nids[0]);
-       }
-
- skip_analog:
-       /* SPDIF for stream index #1 */
-       if (spec->multiout.dig_out_nid || spec->dig_in_nid) {
-               fill_pcm_stream_name(spec->stream_name_digital,
-                                    sizeof(spec->stream_name_digital),
-                                    " Digital", codec->core.chip_name);
-               info = snd_hda_codec_pcm_new(codec, "%s",
-                                            spec->stream_name_digital);
-               if (!info)
-                       return -ENOMEM;
-               codec->follower_dig_outs = spec->multiout.follower_dig_outs;
-               spec->pcm_rec[1] = info;
-               if (spec->dig_out_type)
-                       info->pcm_type = spec->dig_out_type;
-               else
-                       info->pcm_type = HDA_PCM_TYPE_SPDIF;
-               if (spec->multiout.dig_out_nid)
-                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
-                                        &pcm_digital_playback,
-                                        spec->stream_digital_playback,
-                                        spec->multiout.dig_out_nid);
-               if (spec->dig_in_nid)
-                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
-                                        &pcm_digital_capture,
-                                        spec->stream_digital_capture,
-                                        spec->dig_in_nid);
-       }
-
-       if (spec->no_analog)
-               return 0;
-
-       /* If the use of more than one ADC is requested for the current
-        * model, configure a second analog capture-only PCM.
-        */
-       have_multi_adcs = (spec->num_adc_nids > 1) &&
-               !spec->dyn_adc_switch && !spec->auto_mic;
-       /* Additional Analaog capture for index #2 */
-       if (spec->alt_dac_nid || have_multi_adcs) {
-               fill_pcm_stream_name(spec->stream_name_alt_analog,
-                                    sizeof(spec->stream_name_alt_analog),
-                            " Alt Analog", codec->core.chip_name);
-               info = snd_hda_codec_pcm_new(codec, "%s",
-                                            spec->stream_name_alt_analog);
-               if (!info)
-                       return -ENOMEM;
-               spec->pcm_rec[2] = info;
-               if (spec->alt_dac_nid)
-                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
-                                        &pcm_analog_alt_playback,
-                                        spec->stream_analog_alt_playback,
-                                        spec->alt_dac_nid);
-               else
-                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_PLAYBACK],
-                                        &pcm_null_stream, NULL, 0);
-               if (have_multi_adcs) {
-                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
-                                        &pcm_analog_alt_capture,
-                                        spec->stream_analog_alt_capture,
-                                        spec->adc_nids[1]);
-                       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams =
-                               spec->num_adc_nids - 1;
-               } else {
-                       setup_pcm_stream(&info->stream[SNDRV_PCM_STREAM_CAPTURE],
-                                        &pcm_null_stream, NULL, 0);
-               }
-       }
-
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms);
-
-
-/*
- * Standard auto-parser initializations
- */
-
-/* configure the given path as a proper output */
-static void set_output_and_unmute(struct hda_codec *codec, int path_idx)
-{
-       struct nid_path *path;
-       hda_nid_t pin;
-
-       path = snd_hda_get_path_from_idx(codec, path_idx);
-       if (!path || !path->depth)
-               return;
-       pin = path->path[path->depth - 1];
-       restore_pin_ctl(codec, pin);
-       snd_hda_activate_path(codec, path, path->active,
-                             aamix_default(codec->spec));
-       set_pin_eapd(codec, pin, path->active);
-}
-
-/* initialize primary output paths */
-static void init_multi_out(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->autocfg.line_outs; i++)
-               set_output_and_unmute(codec, spec->out_paths[i]);
-}
-
-
-static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths)
-{
-       int i;
-
-       for (i = 0; i < num_outs; i++)
-               set_output_and_unmute(codec, paths[i]);
-}
-
-/* initialize hp and speaker paths */
-static void init_extra_out(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT)
-               __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths);
-       if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT)
-               __init_extra_out(codec, spec->autocfg.speaker_outs,
-                                spec->speaker_paths);
-}
-
-/* initialize multi-io paths */
-static void init_multi_io(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->multi_ios; i++) {
-               hda_nid_t pin = spec->multi_io[i].pin;
-               struct nid_path *path;
-               path = get_multiio_path(codec, i);
-               if (!path)
-                       continue;
-               if (!spec->multi_io[i].ctl_in)
-                       spec->multi_io[i].ctl_in =
-                               snd_hda_codec_get_pin_target(codec, pin);
-               snd_hda_activate_path(codec, path, path->active,
-                                     aamix_default(spec));
-       }
-}
-
-static void init_aamix_paths(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (!spec->have_aamix_ctl)
-               return;
-       if (!has_aamix_out_paths(spec))
-               return;
-       update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0],
-                          spec->aamix_out_paths[0],
-                          spec->autocfg.line_out_type);
-       update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0],
-                          spec->aamix_out_paths[1],
-                          AUTO_PIN_HP_OUT);
-       update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0],
-                          spec->aamix_out_paths[2],
-                          AUTO_PIN_SPEAKER_OUT);
-}
-
-/* set up input pins and loopback paths */
-static void init_analog_input(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               if (is_input_pin(codec, nid))
-                       restore_pin_ctl(codec, nid);
-
-               /* init loopback inputs */
-               if (spec->mixer_nid) {
-                       resume_path_from_idx(codec, spec->loopback_paths[i]);
-                       resume_path_from_idx(codec, spec->loopback_merge_path);
-               }
-       }
-}
-
-/* initialize ADC paths */
-static void init_input_src(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->input_mux;
-       struct nid_path *path;
-       int i, c, nums;
-
-       if (spec->dyn_adc_switch)
-               nums = 1;
-       else
-               nums = spec->num_adc_nids;
-
-       for (c = 0; c < nums; c++) {
-               for (i = 0; i < imux->num_items; i++) {
-                       path = get_input_path(codec, c, i);
-                       if (path) {
-                               bool active = path->active;
-                               if (i == spec->cur_mux[c])
-                                       active = true;
-                               snd_hda_activate_path(codec, path, active, false);
-                       }
-               }
-               if (spec->hp_mic)
-                       update_hp_mic(codec, c, true);
-       }
-
-       if (spec->cap_sync_hook)
-               spec->cap_sync_hook(codec, NULL, NULL);
-}
-
-/* set right pin controls for digital I/O */
-static void init_digital(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int i;
-       hda_nid_t pin;
-
-       for (i = 0; i < spec->autocfg.dig_outs; i++)
-               set_output_and_unmute(codec, spec->digout_paths[i]);
-       pin = spec->autocfg.dig_in_pin;
-       if (pin) {
-               restore_pin_ctl(codec, pin);
-               resume_path_from_idx(codec, spec->digin_path);
-       }
-}
-
-/* clear unsol-event tags on unused pins; Conexant codecs seem to leave
- * invalid unsol tags by some reason
- */
-static void clear_unsol_on_unused_pins(struct hda_codec *codec)
-{
-       const struct hda_pincfg *pin;
-       int i;
-
-       snd_array_for_each(&codec->init_pins, i, pin) {
-               hda_nid_t nid = pin->nid;
-               if (is_jack_detectable(codec, nid) &&
-                   !snd_hda_jack_tbl_get(codec, nid))
-                       snd_hda_codec_write_cache(codec, nid, 0,
-                                       AC_VERB_SET_UNSOLICITED_ENABLE, 0);
-       }
-}
-
-/**
- * snd_hda_gen_init - initialize the generic spec
- * @codec: the HDA codec
- *
- * This can be put as patch_ops init function.
- */
-int snd_hda_gen_init(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-
-       if (spec->init_hook)
-               spec->init_hook(codec);
-
-       if (!spec->skip_verbs)
-               snd_hda_apply_verbs(codec);
-
-       init_multi_out(codec);
-       init_extra_out(codec);
-       init_multi_io(codec);
-       init_aamix_paths(codec);
-       init_analog_input(codec);
-       init_input_src(codec);
-       init_digital(codec);
-
-       clear_unsol_on_unused_pins(codec);
-
-       sync_all_pin_power_ctls(codec);
-
-       /* call init functions of standard auto-mute helpers */
-       update_automute_all(codec);
-
-       snd_hda_regmap_sync(codec);
-
-       if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook)
-               snd_hda_sync_vmaster_hook(&spec->vmaster_mute);
-
-       hda_call_check_power_status(codec, 0x01);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_init);
-
-/**
- * snd_hda_gen_free - free the generic spec
- * @codec: the HDA codec
- *
- * This can be put as patch_ops free function.
- */
-void snd_hda_gen_free(struct hda_codec *codec)
-{
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE);
-       snd_hda_gen_spec_free(codec->spec);
-       kfree(codec->spec);
-       codec->spec = NULL;
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_free);
-
-/**
- * snd_hda_gen_check_power_status - check the loopback power save state
- * @codec: the HDA codec
- * @nid: NID to inspect
- *
- * This can be put as patch_ops check_power_status function.
- */
-int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       return snd_hda_check_amp_list_power(codec, &spec->loopback, nid);
-}
-EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status);
-
-
-/*
- * the generic codec support
- */
-
-static const struct hda_codec_ops generic_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = snd_hda_gen_init,
-       .free = snd_hda_gen_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .check_power_status = snd_hda_gen_check_power_status,
-};
-
-/*
- * snd_hda_parse_generic_codec - Generic codec parser
- * @codec: the HDA codec
- */
-static int snd_hda_parse_generic_codec(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       snd_hda_gen_spec_init(spec);
-       codec->spec = spec;
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
-       if (err < 0)
-               goto error;
-
-       err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
-       if (err < 0)
-               goto error;
-
-       codec->patch_ops = generic_patch_ops;
-       return 0;
-
-error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-static const struct hda_device_id snd_hda_id_generic[] = {
-       HDA_CODEC_ENTRY(0x1af40021, "Generic", snd_hda_parse_generic_codec), /* QEMU */
-       HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC, "Generic", snd_hda_parse_generic_codec),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_generic);
-
-static struct hda_codec_driver generic_driver = {
-       .id = snd_hda_id_generic,
-};
-
-module_hda_codec_driver(generic_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Generic HD-audio codec parser");
diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h
deleted file mode 100644 (file)
index 9612afa..0000000
+++ /dev/null
@@ -1,357 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * Generic BIOS auto-parser helper functions for HD-audio
- *
- * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de>
- */
-
-#ifndef __SOUND_HDA_GENERIC_H
-#define __SOUND_HDA_GENERIC_H
-
-#include <linux/leds.h>
-#include "hda_auto_parser.h"
-
-struct hda_jack_callback;
-
-/* table entry for multi-io paths */
-struct hda_multi_io {
-       hda_nid_t pin;          /* multi-io widget pin NID */
-       hda_nid_t dac;          /* DAC to be connected */
-       unsigned int ctl_in;    /* cached input-pin control value */
-};
-
-/* Widget connection path
- *
- * For output, stored in the order of DAC -> ... -> pin,
- * for input, pin -> ... -> ADC.
- *
- * idx[i] contains the source index number to select on of the widget path[i];
- * e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget
- * multi[] indicates whether it's a selector widget with multi-connectors
- * (i.e. the connection selection is mandatory)
- * vol_ctl and mute_ctl contains the NIDs for the assigned mixers
- */
-
-#define MAX_NID_PATH_DEPTH     10
-
-enum {
-       NID_PATH_VOL_CTL,
-       NID_PATH_MUTE_CTL,
-       NID_PATH_BOOST_CTL,
-       NID_PATH_NUM_CTLS
-};
-
-struct nid_path {
-       int depth;
-       hda_nid_t path[MAX_NID_PATH_DEPTH];
-       unsigned char idx[MAX_NID_PATH_DEPTH];
-       unsigned char multi[MAX_NID_PATH_DEPTH];
-       unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */
-       bool active:1;          /* activated by driver */
-       bool pin_enabled:1;     /* pins are enabled */
-       bool pin_fixed:1;       /* path with fixed pin */
-       bool stream_enabled:1;  /* stream is active */
-};
-
-/* mic/line-in auto switching entry */
-
-#define MAX_AUTO_MIC_PINS      3
-
-struct automic_entry {
-       hda_nid_t pin;          /* pin */
-       int idx;                /* imux index, -1 = invalid */
-       unsigned int attr;      /* pin attribute (INPUT_PIN_ATTR_*) */
-};
-
-/* active stream id */
-enum { STREAM_MULTI_OUT, STREAM_INDEP_HP };
-
-/* PCM hook action */
-enum {
-       HDA_GEN_PCM_ACT_OPEN,
-       HDA_GEN_PCM_ACT_PREPARE,
-       HDA_GEN_PCM_ACT_CLEANUP,
-       HDA_GEN_PCM_ACT_CLOSE,
-};
-
-/* DAC assignment badness table */
-struct badness_table {
-       int no_primary_dac;     /* no primary DAC */
-       int no_dac;             /* no secondary DACs */
-       int shared_primary;     /* primary DAC is shared with main output */
-       int shared_surr;        /* secondary DAC shared with main or primary */
-       int shared_clfe;        /* third DAC shared with main or primary */
-       int shared_surr_main;   /* secondary DAC sahred with main/DAC0 */
-};
-
-extern const struct badness_table hda_main_out_badness;
-extern const struct badness_table hda_extra_out_badness;
-
-struct hda_gen_spec {
-       char stream_name_analog[32];    /* analog PCM stream */
-       const struct hda_pcm_stream *stream_analog_playback;
-       const struct hda_pcm_stream *stream_analog_capture;
-
-       char stream_name_alt_analog[32]; /* alternative analog PCM stream */
-       const struct hda_pcm_stream *stream_analog_alt_playback;
-       const struct hda_pcm_stream *stream_analog_alt_capture;
-
-       char stream_name_digital[32];   /* digital PCM stream */
-       const struct hda_pcm_stream *stream_digital_playback;
-       const struct hda_pcm_stream *stream_digital_capture;
-
-       /* PCM */
-       unsigned int active_streams;
-       struct mutex pcm_mutex;
-
-       /* playback */
-       struct hda_multi_out multiout;  /* playback set-up
-                                        * max_channels, dacs must be set
-                                        * dig_out_nid and hp_nid are optional
-                                        */
-       hda_nid_t alt_dac_nid;
-       hda_nid_t follower_dig_outs[3]; /* optional - for auto-parsing */
-       int dig_out_type;
-
-       /* capture */
-       unsigned int num_adc_nids;
-       hda_nid_t adc_nids[AUTO_CFG_MAX_INS];
-       hda_nid_t dig_in_nid;           /* digital-in NID; optional */
-       hda_nid_t mixer_nid;            /* analog-mixer NID */
-       hda_nid_t mixer_merge_nid;      /* aamix merge-point NID (optional) */
-       const char *input_labels[HDA_MAX_NUM_INPUTS];
-       int input_label_idxs[HDA_MAX_NUM_INPUTS];
-
-       /* capture setup for dynamic dual-adc switch */
-       hda_nid_t cur_adc;
-       unsigned int cur_adc_stream_tag;
-       unsigned int cur_adc_format;
-
-       /* capture source */
-       struct hda_input_mux input_mux;
-       unsigned int cur_mux[3];
-
-       /* channel model */
-       /* min_channel_count contains the minimum channel count for primary
-        * outputs.  When multi_ios is set, the channels can be configured
-        * between min_channel_count and (min_channel_count + multi_ios * 2).
-        *
-        * ext_channel_count contains the current channel count of the primary
-        * out.  This varies in the range above.
-        *
-        * Meanwhile, const_channel_count is the channel count for all outputs
-        * including headphone and speakers.  It's a constant value, and the
-        * PCM is set up as max(ext_channel_count, const_channel_count).
-        */
-       int min_channel_count;          /* min. channel count for primary out */
-       int ext_channel_count;          /* current channel count for primary */
-       int const_channel_count;        /* channel count for all */
-
-       /* PCM information */
-       struct hda_pcm *pcm_rec[3];     /* used in build_pcms() */
-
-       /* dynamic controls, init_verbs and input_mux */
-       struct auto_pin_cfg autocfg;
-       struct snd_array kctls;
-       hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS];
-       hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS];
-       unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS];
-       /* shared hp/mic */
-       hda_nid_t shared_mic_vref_pin;
-       hda_nid_t hp_mic_pin;
-       int hp_mic_mux_idx;
-
-       /* DAC/ADC lists */
-       int num_all_dacs;
-       hda_nid_t all_dacs[16];
-       int num_all_adcs;
-       hda_nid_t all_adcs[AUTO_CFG_MAX_INS];
-
-       /* path list */
-       struct snd_array paths;
-
-       /* path indices */
-       int out_paths[AUTO_CFG_MAX_OUTS];
-       int hp_paths[AUTO_CFG_MAX_OUTS];
-       int speaker_paths[AUTO_CFG_MAX_OUTS];
-       int aamix_out_paths[3];
-       int digout_paths[AUTO_CFG_MAX_OUTS];
-       int input_paths[HDA_MAX_NUM_INPUTS][AUTO_CFG_MAX_INS];
-       int loopback_paths[HDA_MAX_NUM_INPUTS];
-       int loopback_merge_path;
-       int digin_path;
-
-       /* auto-mic stuff */
-       int am_num_entries;
-       struct automic_entry am_entry[MAX_AUTO_MIC_PINS];
-
-       /* for pin sensing */
-       /* current status; set in hda_generic.c */
-       unsigned int hp_jack_present:1;
-       unsigned int line_jack_present:1;
-       unsigned int speaker_muted:1; /* current status of speaker mute */
-       unsigned int line_out_muted:1; /* current status of LO mute */
-
-       /* internal states of automute / autoswitch behavior */
-       unsigned int auto_mic:1;
-       unsigned int automute_speaker:1; /* automute speaker outputs */
-       unsigned int automute_lo:1; /* automute LO outputs */
-
-       /* capabilities detected by parser */
-       unsigned int detect_hp:1;       /* Headphone detection enabled */
-       unsigned int detect_lo:1;       /* Line-out detection enabled */
-       unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */
-       unsigned int automute_lo_possible:1;      /* there are line outs and HP */
-
-       /* additional parameters set by codec drivers */
-       unsigned int master_mute:1;     /* master mute over all */
-       unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */
-       unsigned int line_in_auto_switch:1; /* allow line-in auto switch */
-       unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */
-
-       /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */
-       unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */
-       unsigned int suppress_auto_mic:1; /* suppress input jack auto switch */
-
-       /* other parse behavior flags */
-       unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */
-       unsigned int hp_mic:1; /* Allow HP as a mic-in */
-       unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */
-       unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */
-       unsigned int no_multi_io:1; /* Don't try multi I/O config */
-       unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */
-       unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */
-       unsigned int own_eapd_ctl:1; /* set EAPD by own function */
-       unsigned int keep_eapd_on:1; /* don't turn off EAPD automatically */
-       unsigned int vmaster_mute_led:1; /* add SPK-LED flag to vmaster mute switch */
-       unsigned int mic_mute_led:1; /* add MIC-LED flag to capture mute switch */
-       unsigned int indep_hp:1; /* independent HP supported */
-       unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */
-       unsigned int add_stereo_mix_input:2; /* add aamix as a capture src */
-       unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */
-       unsigned int power_down_unused:1; /* power down unused widgets */
-       unsigned int dac_min_mute:1; /* minimal = mute for DACs */
-       unsigned int suppress_vmaster:1; /* don't create vmaster kctls */
-
-       /* other internal flags */
-       unsigned int no_analog:1; /* digital I/O only */
-       unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */
-       unsigned int indep_hp_enabled:1; /* independent HP enabled */
-       unsigned int have_aamix_ctl:1;
-       unsigned int hp_mic_jack_modes:1;
-       unsigned int skip_verbs:1; /* don't apply verbs at snd_hda_gen_init() */
-
-       /* additional mute flags (only effective with auto_mute_via_amp=1) */
-       u64 mute_bits;
-
-       /* bitmask for skipping volume controls */
-       u64 out_vol_mask;
-
-       /* badness tables for output path evaluations */
-       const struct badness_table *main_out_badness;
-       const struct badness_table *extra_out_badness;
-
-       /* preferred pin/DAC pairs; an array of paired NIDs */
-       const hda_nid_t *preferred_dacs;
-
-       /* loopback mixing mode */
-       bool aamix_mode;
-
-       /* digital beep */
-       hda_nid_t beep_nid;
-
-       /* for virtual master */
-       hda_nid_t vmaster_nid;
-       unsigned int vmaster_tlv[4];
-       struct hda_vmaster_mute_hook vmaster_mute;
-
-       struct hda_loopback_check loopback;
-       struct snd_array loopback_list;
-
-       /* multi-io */
-       int multi_ios;
-       struct hda_multi_io multi_io[4];
-
-       /* hooks */
-       void (*init_hook)(struct hda_codec *codec);
-       void (*automute_hook)(struct hda_codec *codec);
-       void (*cap_sync_hook)(struct hda_codec *codec,
-                             struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol);
-
-       /* PCM hooks */
-       void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 struct snd_pcm_substream *substream,
-                                 int action);
-       void (*pcm_capture_hook)(struct hda_pcm_stream *hinfo,
-                                struct hda_codec *codec,
-                                struct snd_pcm_substream *substream,
-                                int action);
-
-       /* automute / autoswitch hooks */
-       void (*hp_automute_hook)(struct hda_codec *codec,
-                                struct hda_jack_callback *cb);
-       void (*line_automute_hook)(struct hda_codec *codec,
-                                  struct hda_jack_callback *cb);
-       void (*mic_autoswitch_hook)(struct hda_codec *codec,
-                                   struct hda_jack_callback *cb);
-
-       /* leds */
-       struct led_classdev *led_cdevs[NUM_AUDIO_LEDS];
-};
-
-/* values for add_stereo_mix_input flag */
-enum {
-       HDA_HINT_STEREO_MIX_DISABLE,    /* No stereo mix input */
-       HDA_HINT_STEREO_MIX_ENABLE,     /* Add stereo mix input */
-       HDA_HINT_STEREO_MIX_AUTO,       /* Add only if auto-mic is disabled */
-};
-
-int snd_hda_gen_spec_init(struct hda_gen_spec *spec);
-
-int snd_hda_gen_init(struct hda_codec *codec);
-void snd_hda_gen_free(struct hda_codec *codec);
-
-int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path);
-struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx);
-struct nid_path *
-snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
-                    hda_nid_t to_nid, int anchor_nid);
-void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
-                          bool enable, bool add_aamix);
-
-struct snd_kcontrol_new *
-snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
-                    const struct snd_kcontrol_new *temp);
-
-int snd_hda_gen_parse_auto_config(struct hda_codec *codec,
-                                 struct auto_pin_cfg *cfg);
-int snd_hda_gen_build_controls(struct hda_codec *codec);
-int snd_hda_gen_build_pcms(struct hda_codec *codec);
-
-/* standard jack event callbacks */
-void snd_hda_gen_hp_automute(struct hda_codec *codec,
-                            struct hda_jack_callback *jack);
-void snd_hda_gen_line_automute(struct hda_codec *codec,
-                              struct hda_jack_callback *jack);
-void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
-                               struct hda_jack_callback *jack);
-void snd_hda_gen_update_outputs(struct hda_codec *codec);
-
-int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid);
-unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
-                                          hda_nid_t nid,
-                                          unsigned int power_state);
-void snd_hda_gen_stream_pm(struct hda_codec *codec, hda_nid_t nid, bool on);
-int snd_hda_gen_fix_pin_power(struct hda_codec *codec, hda_nid_t pin);
-
-int snd_hda_gen_add_mute_led_cdev(struct hda_codec *codec,
-                                 int (*callback)(struct led_classdev *,
-                                                 enum led_brightness));
-int snd_hda_gen_add_micmute_led_cdev(struct hda_codec *codec,
-                                    int (*callback)(struct led_classdev *,
-                                                    enum led_brightness));
-bool snd_hda_gen_shutup_speakers(struct hda_codec *codec);
-
-#endif /* __SOUND_HDA_GENERIC_H */
diff --git a/sound/pci/hda/hp_x360_helper.c b/sound/pci/hda/hp_x360_helper.c
deleted file mode 100644 (file)
index 969542c..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Fixes for HP X360 laptops with top B&O speakers
- * to be included from codec driver
- */
-
-static void alc295_fixup_hp_top_speakers(struct hda_codec *codec,
-               const struct hda_fixup *fix, int action)
-{
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x17, 0x90170110 },
-               { }
-       };
-       static const struct coef_fw alc295_hp_speakers_coefs[] = {
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003f), WRITE_COEF(0x28, 0x1000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0004), WRITE_COEF(0x28, 0x0600), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0006), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0xc0c0), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0008), WRITE_COEF(0x28, 0xb000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x002e), WRITE_COEF(0x28, 0x0800), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x00c1), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x0320), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0039), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003b), WRITE_COEF(0x28, 0xffff), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003c), WRITE_COEF(0x28, 0xffd0), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0080), WRITE_COEF(0x28, 0x0880), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x0dfe), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0018), WRITE_COEF(0x28, 0x0219), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x005d), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x9142), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c0), WRITE_COEF(0x28, 0x01ce), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c1), WRITE_COEF(0x28, 0xed0c), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c2), WRITE_COEF(0x28, 0x1c00), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c3), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c4), WRITE_COEF(0x28, 0x0200), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c5), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c6), WRITE_COEF(0x28, 0x0399), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c7), WRITE_COEF(0x28, 0x2330), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c8), WRITE_COEF(0x28, 0x1e5d), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c9), WRITE_COEF(0x28, 0x6eff), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00ca), WRITE_COEF(0x28, 0x01c0), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cb), WRITE_COEF(0x28, 0xed0c), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cc), WRITE_COEF(0x28, 0x1c00), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cd), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00ce), WRITE_COEF(0x28, 0x0200), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cf), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d0), WRITE_COEF(0x28, 0x0399), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d1), WRITE_COEF(0x28, 0x2330), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d2), WRITE_COEF(0x28, 0x1e5d), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d3), WRITE_COEF(0x28, 0x6eff), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0062), WRITE_COEF(0x28, 0x8000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0063), WRITE_COEF(0x28, 0x5f5f), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0064), WRITE_COEF(0x28, 0x1000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0065), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0066), WRITE_COEF(0x28, 0x4004), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0067), WRITE_COEF(0x28, 0x0802), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0068), WRITE_COEF(0x28, 0x890f), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0069), WRITE_COEF(0x28, 0xe021), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0070), WRITE_COEF(0x28, 0x8012), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0071), WRITE_COEF(0x28, 0x3450), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0072), WRITE_COEF(0x28, 0x0123), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0073), WRITE_COEF(0x28, 0x4543), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0074), WRITE_COEF(0x28, 0x2100), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0075), WRITE_COEF(0x28, 0x4321), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0076), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0050), WRITE_COEF(0x28, 0x8200), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0051), WRITE_COEF(0x28, 0x0707), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0052), WRITE_COEF(0x28, 0x4090), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0090), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x721f), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0012), WRITE_COEF(0x28, 0xebeb), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x009e), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0060), WRITE_COEF(0x28, 0x2213), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0006), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003f), WRITE_COEF(0x28, 0x3000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0004), WRITE_COEF(0x28, 0x0500), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0040), WRITE_COEF(0x28, 0x800c), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0046), WRITE_COEF(0x28, 0xc22e), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x004b), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024),
-               WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0050), WRITE_COEF(0x28, 0x82ec), WRITE_COEF(0x29, 0xb024),
-       };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               alc295_fixup_disable_dac3(codec, fix, action);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               alc_process_coef_fw(codec, alc295_hp_speakers_coefs);
-               break;
-       }
-}
diff --git a/sound/pci/hda/ideapad_hotkey_led_helper.c b/sound/pci/hda/ideapad_hotkey_led_helper.c
deleted file mode 100644 (file)
index c10d979..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Ideapad helper functions for Lenovo Ideapad LED control,
- * It should be included from codec driver.
- */
-
-#if IS_ENABLED(CONFIG_IDEAPAD_LAPTOP)
-
-#include <linux/acpi.h>
-#include <linux/leds.h>
-
-static bool is_ideapad(struct hda_codec *codec)
-{
-       return (codec->core.subsystem_id >> 16 == 0x17aa) &&
-              (acpi_dev_found("LHK2019") || acpi_dev_found("VPC2004"));
-}
-
-static void hda_fixup_ideapad_acpi(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               if (!is_ideapad(codec))
-                       return;
-               snd_hda_gen_add_mute_led_cdev(codec, NULL);
-               snd_hda_gen_add_micmute_led_cdev(codec, NULL);
-       }
-}
-
-#else /* CONFIG_IDEAPAD_LAPTOP */
-
-static void hda_fixup_ideapad_acpi(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-}
-
-#endif /* CONFIG_IDEAPAD_LAPTOP */
diff --git a/sound/pci/hda/ideapad_s740_helper.c b/sound/pci/hda/ideapad_s740_helper.c
deleted file mode 100644 (file)
index 564b908..0000000
+++ /dev/null
@@ -1,492 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Fixes for Lenovo Ideapad S740, to be included from codec driver */
-
-static const struct hda_verb alc285_ideapad_s740_coefs[] = {
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x10 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0320 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0041 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0041 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001d },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x004e },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001d },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x004e },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0042 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x007f },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x003c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0011 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x002a },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x000c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x002a },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0046 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x000f },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0046 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0044 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0044 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0009 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x004c },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001b },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0019 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0025 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0018 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0037 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x001a },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0040 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0016 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0076 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0017 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0010 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0015 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0007 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0086 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0001 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x29 },
-{ 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0002 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-{ 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-{}
-};
-
-static void alc285_fixup_ideapad_s740_coef(struct hda_codec *codec,
-                                          const struct hda_fixup *fix,
-                                          int action)
-{
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_add_verbs(codec, alc285_ideapad_s740_coefs);
-               break;
-       }
-}
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
deleted file mode 100644 (file)
index 56354fe..0000000
+++ /dev/null
@@ -1,1176 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * HD audio interface patch for AD1882, AD1884, AD1981HD, AD1983, AD1984,
- *   AD1986A, AD1988
- *
- * Copyright (c) 2005-2007 Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-
-#include <sound/core.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_beep.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-
-struct ad198x_spec {
-       struct hda_gen_spec gen;
-
-       /* for auto parser */
-       int smux_paths[4];
-       unsigned int cur_smux;
-       hda_nid_t eapd_nid;
-
-       unsigned int beep_amp;  /* beep amp value, set via set_beep_amp() */
-       int num_smux_conns;
-};
-
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-/* additional beep mixers; the actual parameters are overwritten at build */
-static const struct snd_kcontrol_new ad_beep_mixer[] = {
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT),
-       { } /* end */
-};
-
-#define set_beep_amp(spec, nid, idx, dir) \
-       ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */
-#else
-#define set_beep_amp(spec, nid, idx, dir) /* NOP */
-#endif
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-static int create_beep_ctls(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       const struct snd_kcontrol_new *knew;
-
-       if (!spec->beep_amp)
-               return 0;
-
-       for (knew = ad_beep_mixer ; knew->name; knew++) {
-               int err;
-               struct snd_kcontrol *kctl;
-               kctl = snd_ctl_new1(knew, codec);
-               if (!kctl)
-                       return -ENOMEM;
-               kctl->private_value = spec->beep_amp;
-               err = snd_hda_ctl_add(codec, 0, kctl);
-               if (err < 0)
-                       return err;
-       }
-       return 0;
-}
-#else
-#define create_beep_ctls(codec)                0
-#endif
-
-static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front,
-                               hda_nid_t hp)
-{
-       if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD)
-               snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE,
-                           !codec->inv_eapd ? 0x00 : 0x02);
-       if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD)
-               snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE,
-                           !codec->inv_eapd ? 0x00 : 0x02);
-}
-
-static void ad198x_power_eapd(struct hda_codec *codec)
-{
-       /* We currently only handle front, HP */
-       switch (codec->core.vendor_id) {
-       case 0x11d41882:
-       case 0x11d4882a:
-       case 0x11d41884:
-       case 0x11d41984:
-       case 0x11d41883:
-       case 0x11d4184a:
-       case 0x11d4194a:
-       case 0x11d4194b:
-       case 0x11d41988:
-       case 0x11d4198b:
-       case 0x11d4989a:
-       case 0x11d4989b:
-               ad198x_power_eapd_write(codec, 0x12, 0x11);
-               break;
-       case 0x11d41981:
-       case 0x11d41983:
-               ad198x_power_eapd_write(codec, 0x05, 0x06);
-               break;
-       case 0x11d41986:
-               ad198x_power_eapd_write(codec, 0x1b, 0x1a);
-               break;
-       }
-}
-
-static int ad198x_suspend(struct hda_codec *codec)
-{
-       snd_hda_shutup_pins(codec);
-       ad198x_power_eapd(codec);
-       return 0;
-}
-
-/* follow EAPD via vmaster hook */
-static void ad_vmaster_eapd_hook(void *private_data, int enabled)
-{
-       struct hda_codec *codec = private_data;
-       struct ad198x_spec *spec = codec->spec;
-
-       if (!spec->eapd_nid)
-               return;
-       if (codec->inv_eapd)
-               enabled = !enabled;
-       snd_hda_codec_write_cache(codec, spec->eapd_nid, 0,
-                                  AC_VERB_SET_EAPD_BTLENABLE,
-                                  enabled ? 0x02 : 0x00);
-}
-
-/*
- * Automatic parse of I/O pins from the BIOS configuration
- */
-
-static int ad198x_auto_build_controls(struct hda_codec *codec)
-{
-       int err;
-
-       err = snd_hda_gen_build_controls(codec);
-       if (err < 0)
-               return err;
-       err = create_beep_ctls(codec);
-       if (err < 0)
-               return err;
-       return 0;
-}
-
-static const struct hda_codec_ops ad198x_auto_patch_ops = {
-       .build_controls = ad198x_auto_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = snd_hda_gen_init,
-       .free = snd_hda_gen_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .check_power_status = snd_hda_gen_check_power_status,
-       .suspend = ad198x_suspend,
-};
-
-
-static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp)
-{
-       struct ad198x_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-       int err;
-
-       codec->spdif_status_reset = 1;
-       codec->no_trigger_sense = 1;
-       codec->no_sticky_stream = 1;
-
-       spec->gen.indep_hp = indep_hp;
-       if (!spec->gen.add_stereo_mix_input)
-               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
-
-       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
-       if (err < 0)
-               return err;
-       err = snd_hda_gen_parse_auto_config(codec, cfg);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-/*
- * AD1986A specific
- */
-
-static int alloc_ad_spec(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       codec->spec = spec;
-       snd_hda_gen_spec_init(&spec->gen);
-       codec->patch_ops = ad198x_auto_patch_ops;
-       return 0;
-}
-
-/*
- * AD1986A fixup codes
- */
-
-/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */
-static void ad_fixup_inv_jack_detect(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               codec->inv_jack_detect = 1;
-               spec->gen.keep_eapd_on = 1;
-               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
-               spec->eapd_nid = 0x1b;
-       }
-}
-
-/* Toshiba Satellite L40 implements EAPD in a standard way unlike others */
-static void ad1986a_fixup_eapd(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               codec->inv_eapd = 0;
-               spec->gen.keep_eapd_on = 1;
-               spec->eapd_nid = 0x1b;
-       }
-}
-
-/* enable stereo-mix input for avoiding regression on KDE (bko#88251) */
-static void ad1986a_fixup_eapd_mix_in(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               ad1986a_fixup_eapd(codec, fix, action);
-               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_ENABLE;
-       }
-}
-
-enum {
-       AD1986A_FIXUP_INV_JACK_DETECT,
-       AD1986A_FIXUP_ULTRA,
-       AD1986A_FIXUP_SAMSUNG,
-       AD1986A_FIXUP_3STACK,
-       AD1986A_FIXUP_LAPTOP,
-       AD1986A_FIXUP_LAPTOP_IMIC,
-       AD1986A_FIXUP_EAPD,
-       AD1986A_FIXUP_EAPD_MIX_IN,
-       AD1986A_FIXUP_EASYNOTE,
-};
-
-static const struct hda_fixup ad1986a_fixups[] = {
-       [AD1986A_FIXUP_INV_JACK_DETECT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad_fixup_inv_jack_detect,
-       },
-       [AD1986A_FIXUP_ULTRA] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x90170110 }, /* speaker */
-                       { 0x1d, 0x90a7013e }, /* int mic */
-                       {}
-               },
-       },
-       [AD1986A_FIXUP_SAMSUNG] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x90170110 }, /* speaker */
-                       { 0x1d, 0x90a7013e }, /* int mic */
-                       { 0x20, 0x411111f0 }, /* N/A */
-                       { 0x24, 0x411111f0 }, /* N/A */
-                       {}
-               },
-       },
-       [AD1986A_FIXUP_3STACK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x02214021 }, /* headphone */
-                       { 0x1b, 0x01014011 }, /* front */
-                       { 0x1c, 0x01813030 }, /* line-in */
-                       { 0x1d, 0x01a19020 }, /* rear mic */
-                       { 0x1e, 0x411111f0 }, /* N/A */
-                       { 0x1f, 0x02a190f0 }, /* mic */
-                       { 0x20, 0x411111f0 }, /* N/A */
-                       {}
-               },
-       },
-       [AD1986A_FIXUP_LAPTOP] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x02214021 }, /* headphone */
-                       { 0x1b, 0x90170110 }, /* speaker */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x411111f0 }, /* N/A */
-                       { 0x1e, 0x411111f0 }, /* N/A */
-                       { 0x1f, 0x02a191f0 }, /* mic */
-                       { 0x20, 0x411111f0 }, /* N/A */
-                       {}
-               },
-       },
-       [AD1986A_FIXUP_LAPTOP_IMIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1d, 0x90a7013e }, /* int mic */
-                       {}
-               },
-               .chained_before = 1,
-               .chain_id = AD1986A_FIXUP_LAPTOP,
-       },
-       [AD1986A_FIXUP_EAPD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad1986a_fixup_eapd,
-       },
-       [AD1986A_FIXUP_EAPD_MIX_IN] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad1986a_fixup_eapd_mix_in,
-       },
-       [AD1986A_FIXUP_EASYNOTE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x0421402f }, /* headphone */
-                       { 0x1b, 0x90170110 }, /* speaker */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x90a70130 }, /* int mic */
-                       { 0x1e, 0x411111f0 }, /* N/A */
-                       { 0x1f, 0x04a19040 }, /* mic */
-                       { 0x20, 0x411111f0 }, /* N/A */
-                       { 0x21, 0x411111f0 }, /* N/A */
-                       { 0x22, 0x411111f0 }, /* N/A */
-                       { 0x23, 0x411111f0 }, /* N/A */
-                       { 0x24, 0x411111f0 }, /* N/A */
-                       { 0x25, 0x411111f0 }, /* N/A */
-                       {}
-               },
-               .chained = true,
-               .chain_id = AD1986A_FIXUP_EAPD_MIX_IN,
-       },
-};
-
-static const struct hda_quirk ad1986a_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
-       SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9V", AD1986A_FIXUP_LAPTOP_IMIC),
-       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
-       SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
-       SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
-       SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK),
-       SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP),
-       SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG),
-       SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA),
-       SND_PCI_QUIRK(0x1631, 0xc022, "PackardBell EasyNote MX65", AD1986A_FIXUP_EASYNOTE),
-       SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT),
-       SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK),
-       SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK),
-       {}
-};
-
-static const struct hda_model_fixup ad1986a_fixup_models[] = {
-       { .id = AD1986A_FIXUP_3STACK, .name = "3stack" },
-       { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
-       { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
-       { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
-       { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
-       {}
-};
-
-/*
- */
-static int patch_ad1986a(struct hda_codec *codec)
-{
-       int err;
-       struct ad198x_spec *spec;
-       static const hda_nid_t preferred_pairs[] = {
-               0x1a, 0x03,
-               0x1b, 0x03,
-               0x1c, 0x04,
-               0x1d, 0x05,
-               0x1e, 0x03,
-               0
-       };
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       /* AD1986A has the inverted EAPD implementation */
-       codec->inv_eapd = 1;
-
-       spec->gen.mixer_nid = 0x07;
-       spec->gen.beep_nid = 0x19;
-       set_beep_amp(spec, 0x18, 0, HDA_OUTPUT);
-
-       /* AD1986A has a hardware problem that it can't share a stream
-        * with multiple output pins.  The copy of front to surrounds
-        * causes noisy or silent outputs at a certain timing, e.g.
-        * changing the volume.
-        * So, let's disable the shared stream.
-        */
-       spec->gen.multiout.no_share_stream = 1;
-       /* give fixed DAC/pin pairs */
-       spec->gen.preferred_dacs = preferred_pairs;
-
-       /* AD1986A can't manage the dynamic pin on/off smoothly */
-       spec->gen.auto_mute_via_amp = 1;
-
-       snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl,
-                          ad1986a_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = ad198x_parse_auto_config(codec, false);
-       if (err < 0) {
-               snd_hda_gen_free(codec);
-               return err;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-
-/*
- * AD1983 specific
- */
-
-/*
- * SPDIF mux control for AD1983 auto-parser
- */
-static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
-                                     struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       static const char * const texts2[] = { "PCM", "ADC" };
-       static const char * const texts3[] = { "PCM", "ADC1", "ADC2" };
-       int num_conns = spec->num_smux_conns;
-
-       if (num_conns == 2)
-               return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2);
-       else if (num_conns == 3)
-               return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3);
-       else
-               return -EINVAL;
-}
-
-static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->cur_smux;
-       return 0;
-}
-
-static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int val = ucontrol->value.enumerated.item[0];
-       hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
-       int num_conns = spec->num_smux_conns;
-
-       if (val >= num_conns)
-               return -EINVAL;
-       if (spec->cur_smux == val)
-               return 0;
-       spec->cur_smux = val;
-       snd_hda_codec_write_cache(codec, dig_out, 0,
-                                 AC_VERB_SET_CONNECT_SEL, val);
-       return 1;
-}
-
-static const struct snd_kcontrol_new ad1983_auto_smux_mixer = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Playback Source",
-       .info = ad1983_auto_smux_enum_info,
-       .get = ad1983_auto_smux_enum_get,
-       .put = ad1983_auto_smux_enum_put,
-};
-
-static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       hda_nid_t dig_out = spec->gen.multiout.dig_out_nid;
-       int num_conns;
-
-       if (!dig_out)
-               return 0;
-       num_conns = snd_hda_get_num_conns(codec, dig_out);
-       if (num_conns != 2 && num_conns != 3)
-               return 0;
-       spec->num_smux_conns = num_conns;
-       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer))
-               return -ENOMEM;
-       return 0;
-}
-
-static int patch_ad1983(struct hda_codec *codec)
-{
-       static const hda_nid_t conn_0c[] = { 0x08 };
-       static const hda_nid_t conn_0d[] = { 0x09 };
-       struct ad198x_spec *spec;
-       int err;
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       spec->gen.mixer_nid = 0x0e;
-       spec->gen.beep_nid = 0x10;
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       /* limit the loopback routes not to confuse the parser */
-       snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c);
-       snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d);
-
-       err = ad198x_parse_auto_config(codec, false);
-       if (err < 0)
-               goto error;
-       err = ad1983_add_spdif_mux_ctl(codec);
-       if (err < 0)
-               goto error;
-       return 0;
-
- error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-
-/*
- * AD1981 HD specific
- */
-
-static void ad1981_fixup_hp_eapd(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
-               spec->eapd_nid = 0x05;
-       }
-}
-
-/* set the upper-limit for mixer amp to 0dB for avoiding the possible
- * damage by overloading
- */
-static void ad1981_fixup_amp_override(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-}
-
-enum {
-       AD1981_FIXUP_AMP_OVERRIDE,
-       AD1981_FIXUP_HP_EAPD,
-};
-
-static const struct hda_fixup ad1981_fixups[] = {
-       [AD1981_FIXUP_AMP_OVERRIDE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad1981_fixup_amp_override,
-       },
-       [AD1981_FIXUP_HP_EAPD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad1981_fixup_hp_eapd,
-               .chained = true,
-               .chain_id = AD1981_FIXUP_AMP_OVERRIDE,
-       },
-};
-
-static const struct hda_quirk ad1981_fixup_tbl[] = {
-       SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
-       SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD),
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE),
-       /* HP nx6320 (reversed SSID, H/W bug) */
-       SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD),
-       {}
-};
-
-static int patch_ad1981(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err;
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return -ENOMEM;
-       spec = codec->spec;
-
-       spec->gen.mixer_nid = 0x0e;
-       spec->gen.beep_nid = 0x10;
-       set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT);
-
-       snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = ad198x_parse_auto_config(codec, false);
-       if (err < 0)
-               goto error;
-       err = ad1983_add_spdif_mux_ctl(codec);
-       if (err < 0)
-               goto error;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-
-/*
- * AD1988
- *
- * Output pins and routes
- *
- *        Pin               Mix     Sel     DAC (*)
- * port-A 0x11 (mute/hp) <- 0x22 <- 0x37 <- 03/04/06
- * port-B 0x14 (mute/hp) <- 0x2b <- 0x30 <- 03/04/06
- * port-C 0x15 (mute)    <- 0x2c <- 0x31 <- 05/0a
- * port-D 0x12 (mute/hp) <- 0x29         <- 04
- * port-E 0x17 (mute/hp) <- 0x26 <- 0x32 <- 05/0a
- * port-F 0x16 (mute)    <- 0x2a         <- 06
- * port-G 0x24 (mute)    <- 0x27         <- 05
- * port-H 0x25 (mute)    <- 0x28         <- 0a
- * mono   0x13 (mute/amp)<- 0x1e <- 0x36 <- 03/04/06
- *
- * DAC0 = 03h, DAC1 = 04h, DAC2 = 05h, DAC3 = 06h, DAC4 = 0ah
- * (*) DAC2/3/4 are swapped to DAC3/4/2 on AD198A rev.2 due to a h/w bug.
- *
- * Input pins and routes
- *
- *        pin     boost   mix input # / adc input #
- * port-A 0x11 -> 0x38 -> mix 2, ADC 0
- * port-B 0x14 -> 0x39 -> mix 0, ADC 1
- * port-C 0x15 -> 0x3a -> 33:0 - mix 1, ADC 2
- * port-D 0x12 -> 0x3d -> mix 3, ADC 8
- * port-E 0x17 -> 0x3c -> 34:0 - mix 4, ADC 4
- * port-F 0x16 -> 0x3b -> mix 5, ADC 3
- * port-G 0x24 -> N/A  -> 33:1 - mix 1, 34:1 - mix 4, ADC 6
- * port-H 0x25 -> N/A  -> 33:2 - mix 1, 34:2 - mix 4, ADC 7
- *
- *
- * DAC assignment
- *   6stack - front/surr/CLFE/side/opt DACs - 04/06/05/0a/03
- *   3stack - front/surr/CLFE/opt DACs - 04/05/0a/03
- *
- * Inputs of Analog Mix (0x20)
- *   0:Port-B (front mic)
- *   1:Port-C/G/H (line-in)
- *   2:Port-A
- *   3:Port-D (line-in/2)
- *   4:Port-E/G/H (mic-in)
- *   5:Port-F (mic2-in)
- *   6:CD
- *   7:Beep
- *
- * ADC selection
- *   0:Port-A
- *   1:Port-B (front mic-in)
- *   2:Port-C (line-in)
- *   3:Port-F (mic2-in)
- *   4:Port-E (mic-in)
- *   5:CD
- *   6:Port-G
- *   7:Port-H
- *   8:Port-D (line-in/2)
- *   9:Mix
- *
- * Proposed pin assignments by the datasheet
- *
- * 6-stack
- * Port-A front headphone
- *      B front mic-in
- *      C rear line-in
- *      D rear front-out
- *      E rear mic-in
- *      F rear surround
- *      G rear CLFE
- *      H rear side
- *
- * 3-stack
- * Port-A front headphone
- *      B front mic
- *      C rear line-in/surround
- *      D rear front-out
- *      E rear mic-in/CLFE
- *
- * laptop
- * Port-A headphone
- *      B mic-in
- *      C docking station
- *      D internal speaker (with EAPD)
- *      E/F quad mic array
- */
-
-static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol,
-                                     struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       static const char * const texts[] = {
-               "PCM", "ADC1", "ADC2", "ADC3",
-       };
-       int num_conns = spec->num_smux_conns;
-
-       if (num_conns > 4)
-               num_conns = 4;
-       return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts);
-}
-
-static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->cur_smux;
-       return 0;
-}
-
-static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ad198x_spec *spec = codec->spec;
-       unsigned int val = ucontrol->value.enumerated.item[0];
-       struct nid_path *path;
-       int num_conns = spec->num_smux_conns;
-
-       if (val >= num_conns)
-               return -EINVAL;
-       if (spec->cur_smux == val)
-               return 0;
-
-       mutex_lock(&codec->control_mutex);
-       path = snd_hda_get_path_from_idx(codec,
-                                        spec->smux_paths[spec->cur_smux]);
-       if (path)
-               snd_hda_activate_path(codec, path, false, true);
-       path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]);
-       if (path)
-               snd_hda_activate_path(codec, path, true, true);
-       spec->cur_smux = val;
-       mutex_unlock(&codec->control_mutex);
-       return 1;
-}
-
-static const struct snd_kcontrol_new ad1988_auto_smux_mixer = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Playback Source",
-       .info = ad1988_auto_smux_enum_info,
-       .get = ad1988_auto_smux_enum_get,
-       .put = ad1988_auto_smux_enum_put,
-};
-
-static int ad1988_auto_init(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       int i, err;
-
-       err = snd_hda_gen_init(codec);
-       if (err < 0)
-               return err;
-       if (!spec->gen.autocfg.dig_outs)
-               return 0;
-
-       for (i = 0; i < 4; i++) {
-               struct nid_path *path;
-               path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]);
-               if (path)
-                       snd_hda_activate_path(codec, path, path->active, false);
-       }
-
-       return 0;
-}
-
-static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec = codec->spec;
-       int i, num_conns;
-       /* we create four static faked paths, since AD codecs have odd
-        * widget connections regarding the SPDIF out source
-        */
-       static const struct nid_path fake_paths[4] = {
-               {
-                       .depth = 3,
-                       .path = { 0x02, 0x1d, 0x1b },
-                       .idx = { 0, 0, 0 },
-                       .multi = { 0, 0, 0 },
-               },
-               {
-                       .depth = 4,
-                       .path = { 0x08, 0x0b, 0x1d, 0x1b },
-                       .idx = { 0, 0, 1, 0 },
-                       .multi = { 0, 1, 0, 0 },
-               },
-               {
-                       .depth = 4,
-                       .path = { 0x09, 0x0b, 0x1d, 0x1b },
-                       .idx = { 0, 1, 1, 0 },
-                       .multi = { 0, 1, 0, 0 },
-               },
-               {
-                       .depth = 4,
-                       .path = { 0x0f, 0x0b, 0x1d, 0x1b },
-                       .idx = { 0, 2, 1, 0 },
-                       .multi = { 0, 1, 0, 0 },
-               },
-       };
-
-       /* SPDIF source mux appears to be present only on AD1988A */
-       if (!spec->gen.autocfg.dig_outs ||
-           get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX)
-               return 0;
-
-       num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1;
-       if (num_conns != 3 && num_conns != 4)
-               return 0;
-       spec->num_smux_conns = num_conns;
-
-       for (i = 0; i < num_conns; i++) {
-               struct nid_path *path = snd_array_new(&spec->gen.paths);
-               if (!path)
-                       return -ENOMEM;
-               *path = fake_paths[i];
-               if (!i)
-                       path->active = 1;
-               spec->smux_paths[i] = snd_hda_get_path_idx(codec, path);
-       }
-
-       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer))
-               return -ENOMEM;
-
-       codec->patch_ops.init = ad1988_auto_init;
-
-       return 0;
-}
-
-/*
- */
-
-enum {
-       AD1988_FIXUP_6STACK_DIG,
-};
-
-static const struct hda_fixup ad1988_fixups[] = {
-       [AD1988_FIXUP_6STACK_DIG] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x11, 0x02214130 }, /* front-hp */
-                       { 0x12, 0x01014010 }, /* line-out */
-                       { 0x14, 0x02a19122 }, /* front-mic */
-                       { 0x15, 0x01813021 }, /* line-in */
-                       { 0x16, 0x01011012 }, /* line-out */
-                       { 0x17, 0x01a19020 }, /* mic */
-                       { 0x1b, 0x0145f1f0 }, /* SPDIF */
-                       { 0x24, 0x01016011 }, /* line-out */
-                       { 0x25, 0x01012013 }, /* line-out */
-                       { }
-               }
-       },
-};
-
-static const struct hda_model_fixup ad1988_fixup_models[] = {
-       { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" },
-       {}
-};
-
-static int patch_ad1988(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err;
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       spec->gen.mixer_nid = 0x20;
-       spec->gen.mixer_merge_nid = 0x21;
-       spec->gen.beep_nid = 0x10;
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = ad198x_parse_auto_config(codec, true);
-       if (err < 0)
-               goto error;
-       err = ad1988_add_spdif_mux_ctl(codec);
-       if (err < 0)
-               goto error;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-
-/*
- * AD1884 / AD1984
- *
- * port-B - front line/mic-in
- * port-E - aux in/out
- * port-F - aux in/out
- * port-C - rear line/mic-in
- * port-D - rear line/hp-out
- * port-A - front line/hp-out
- *
- * AD1984 = AD1884 + two digital mic-ins
- *
- * AD1883 / AD1884A / AD1984A / AD1984B
- *
- * port-B (0x14) - front mic-in
- * port-E (0x1c) - rear mic-in
- * port-F (0x16) - CD / ext out
- * port-C (0x15) - rear line-in
- * port-D (0x12) - rear line-out
- * port-A (0x11) - front hp-out
- *
- * AD1984A = AD1884A + digital-mic
- * AD1883 = equivalent with AD1984A
- * AD1984B = AD1984A + extra SPDIF-out
- */
-
-/* set the upper-limit for mixer amp to 0dB for avoiding the possible
- * damage by overloading
- */
-static void ad1884_fixup_amp_override(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT,
-                                         (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (1 << AC_AMPCAP_MUTE_SHIFT));
-}
-
-/* toggle GPIO1 according to the mute state */
-static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled)
-{
-       struct hda_codec *codec = private_data;
-       struct ad198x_spec *spec = codec->spec;
-
-       if (spec->eapd_nid)
-               ad_vmaster_eapd_hook(private_data, enabled);
-       snd_hda_codec_write_cache(codec, 0x01, 0,
-                                  AC_VERB_SET_GPIO_DATA,
-                                  enabled ? 0x00 : 0x02);
-}
-
-static void ad1884_fixup_hp_eapd(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook;
-               spec->gen.own_eapd_ctl = 1;
-               snd_hda_codec_write_cache(codec, 0x01, 0,
-                                         AC_VERB_SET_GPIO_MASK, 0x02);
-               snd_hda_codec_write_cache(codec, 0x01, 0,
-                                         AC_VERB_SET_GPIO_DIRECTION, 0x02);
-               snd_hda_codec_write_cache(codec, 0x01, 0,
-                                         AC_VERB_SET_GPIO_DATA, 0x02);
-               break;
-       case HDA_FIXUP_ACT_PROBE:
-               if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT)
-                       spec->eapd_nid = spec->gen.autocfg.line_out_pins[0];
-               else
-                       spec->eapd_nid = spec->gen.autocfg.speaker_pins[0];
-               break;
-       }
-}
-
-static void ad1884_fixup_thinkpad(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       struct ad198x_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.keep_eapd_on = 1;
-               spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook;
-               spec->eapd_nid = 0x12;
-               /* Analog PC Beeper - allow firmware/ACPI beeps */
-               spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT);
-               spec->gen.beep_nid = 0; /* no digital beep */
-       }
-}
-
-/* set magic COEFs for dmic */
-static const struct hda_verb ad1884_dmic_init_verbs[] = {
-       {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7},
-       {0x01, AC_VERB_SET_PROC_COEF, 0x08},
-       {}
-};
-
-enum {
-       AD1884_FIXUP_AMP_OVERRIDE,
-       AD1884_FIXUP_HP_EAPD,
-       AD1884_FIXUP_DMIC_COEF,
-       AD1884_FIXUP_THINKPAD,
-       AD1884_FIXUP_HP_TOUCHSMART,
-};
-
-static const struct hda_fixup ad1884_fixups[] = {
-       [AD1884_FIXUP_AMP_OVERRIDE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad1884_fixup_amp_override,
-       },
-       [AD1884_FIXUP_HP_EAPD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad1884_fixup_hp_eapd,
-               .chained = true,
-               .chain_id = AD1884_FIXUP_AMP_OVERRIDE,
-       },
-       [AD1884_FIXUP_DMIC_COEF] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = ad1884_dmic_init_verbs,
-       },
-       [AD1884_FIXUP_THINKPAD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = ad1884_fixup_thinkpad,
-               .chained = true,
-               .chain_id = AD1884_FIXUP_DMIC_COEF,
-       },
-       [AD1884_FIXUP_HP_TOUCHSMART] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = ad1884_dmic_init_verbs,
-               .chained = true,
-               .chain_id = AD1884_FIXUP_HP_EAPD,
-       },
-};
-
-static const struct hda_quirk ad1884_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART),
-       SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD),
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD),
-       {}
-};
-
-
-static int patch_ad1884(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err;
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       spec->gen.mixer_nid = 0x20;
-       spec->gen.mixer_merge_nid = 0x21;
-       spec->gen.beep_nid = 0x10;
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-
-       snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = ad198x_parse_auto_config(codec, true);
-       if (err < 0)
-               goto error;
-       err = ad1983_add_spdif_mux_ctl(codec);
-       if (err < 0)
-               goto error;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-/*
- * AD1882 / AD1882A
- *
- * port-A - front hp-out
- * port-B - front mic-in
- * port-C - rear line-in, shared surr-out (3stack)
- * port-D - rear line-out
- * port-E - rear mic-in, shared clfe-out (3stack)
- * port-F - rear surr-out (6stack)
- * port-G - rear clfe-out (6stack)
- */
-
-static int patch_ad1882(struct hda_codec *codec)
-{
-       struct ad198x_spec *spec;
-       int err;
-
-       err = alloc_ad_spec(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       spec->gen.mixer_nid = 0x20;
-       spec->gen.mixer_merge_nid = 0x21;
-       spec->gen.beep_nid = 0x10;
-       set_beep_amp(spec, 0x10, 0, HDA_OUTPUT);
-       err = ad198x_parse_auto_config(codec, true);
-       if (err < 0)
-               goto error;
-       err = ad1988_add_spdif_mux_ctl(codec);
-       if (err < 0)
-               goto error;
-       return 0;
-
- error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_analog[] = {
-       HDA_CODEC_ENTRY(0x11d4184a, "AD1884A", patch_ad1884),
-       HDA_CODEC_ENTRY(0x11d41882, "AD1882", patch_ad1882),
-       HDA_CODEC_ENTRY(0x11d41883, "AD1883", patch_ad1884),
-       HDA_CODEC_ENTRY(0x11d41884, "AD1884", patch_ad1884),
-       HDA_CODEC_ENTRY(0x11d4194a, "AD1984A", patch_ad1884),
-       HDA_CODEC_ENTRY(0x11d4194b, "AD1984B", patch_ad1884),
-       HDA_CODEC_ENTRY(0x11d41981, "AD1981", patch_ad1981),
-       HDA_CODEC_ENTRY(0x11d41983, "AD1983", patch_ad1983),
-       HDA_CODEC_ENTRY(0x11d41984, "AD1984", patch_ad1884),
-       HDA_CODEC_ENTRY(0x11d41986, "AD1986A", patch_ad1986a),
-       HDA_CODEC_ENTRY(0x11d41988, "AD1988", patch_ad1988),
-       HDA_CODEC_ENTRY(0x11d4198b, "AD1988B", patch_ad1988),
-       HDA_CODEC_ENTRY(0x11d4882a, "AD1882A", patch_ad1882),
-       HDA_CODEC_ENTRY(0x11d4989a, "AD1989A", patch_ad1988),
-       HDA_CODEC_ENTRY(0x11d4989b, "AD1989B", patch_ad1988),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_analog);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Analog Devices HD-audio codec");
-
-static struct hda_codec_driver analog_driver = {
-       .id = snd_hda_id_analog,
-};
-
-module_hda_codec_driver(analog_driver);
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c
deleted file mode 100644 (file)
index 1818ce6..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * HD audio interface patch for Creative X-Fi CA0110-IBG chip
- *
- * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-
-static const struct hda_codec_ops ca0110_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = snd_hda_gen_init,
-       .free = snd_hda_gen_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-};
-
-static int ca0110_parse_auto_config(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec = codec->spec;
-       int err;
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0);
-       if (err < 0)
-               return err;
-       err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-
-static int patch_ca0110(struct hda_codec *codec)
-{
-       struct hda_gen_spec *spec;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       snd_hda_gen_spec_init(spec);
-       codec->spec = spec;
-       codec->patch_ops = ca0110_patch_ops;
-
-       spec->multi_cap_vol = 1;
-       codec->bus->core.needs_damn_long_delay = 1;
-
-       err = ca0110_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_ca0110[] = {
-       HDA_CODEC_ENTRY(0x1102000a, "CA0110-IBG", patch_ca0110),
-       HDA_CODEC_ENTRY(0x1102000b, "CA0110-IBG", patch_ca0110),
-       HDA_CODEC_ENTRY(0x1102000d, "SB0880 X-Fi", patch_ca0110),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0110);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec");
-
-static struct hda_codec_driver ca0110_driver = {
-       .id = snd_hda_id_ca0110,
-};
-
-module_hda_codec_driver(ca0110_driver);
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
deleted file mode 100644 (file)
index 686ce09..0000000
+++ /dev/null
@@ -1,10123 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * HD audio interface patch for Creative CA0132 chip
- *
- * Copyright (c) 2011, Creative Technology Ltd.
- *
- * Based on patch_ca0110.c
- * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/firmware.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/io.h>
-#include <linux/pci.h>
-#include <asm/io.h>
-#include <sound/core.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-
-#include "ca0132_regs.h"
-
-/* Enable this to see controls for tuning purpose. */
-#define ENABLE_TUNING_CONTROLS
-
-#ifdef ENABLE_TUNING_CONTROLS
-#include <sound/tlv.h>
-#endif
-
-#define FLOAT_ZERO     0x00000000
-#define FLOAT_ONE      0x3f800000
-#define FLOAT_TWO      0x40000000
-#define FLOAT_THREE     0x40400000
-#define FLOAT_FIVE     0x40a00000
-#define FLOAT_SIX       0x40c00000
-#define FLOAT_EIGHT     0x41000000
-#define FLOAT_MINUS_5  0xc0a00000
-
-#define UNSOL_TAG_DSP  0x16
-
-#define DSP_DMA_WRITE_BUFLEN_INIT (1UL<<18)
-#define DSP_DMA_WRITE_BUFLEN_OVLY (1UL<<15)
-
-#define DMA_TRANSFER_FRAME_SIZE_NWORDS         8
-#define DMA_TRANSFER_MAX_FRAME_SIZE_NWORDS     32
-#define DMA_OVERLAY_FRAME_SIZE_NWORDS          2
-
-#define MASTERCONTROL                          0x80
-#define MASTERCONTROL_ALLOC_DMA_CHAN           10
-#define MASTERCONTROL_QUERY_SPEAKER_EQ_ADDRESS 60
-
-#define WIDGET_CHIP_CTRL      0x15
-#define WIDGET_DSP_CTRL       0x16
-
-#define MEM_CONNID_MICIN1     3
-#define MEM_CONNID_MICIN2     5
-#define MEM_CONNID_MICOUT1    12
-#define MEM_CONNID_MICOUT2    14
-#define MEM_CONNID_WUH        10
-#define MEM_CONNID_DSP        16
-#define MEM_CONNID_DMIC       100
-
-#define SCP_SET    0
-#define SCP_GET    1
-
-#define EFX_FILE   "ctefx.bin"
-#define DESKTOP_EFX_FILE   "ctefx-desktop.bin"
-#define R3DI_EFX_FILE  "ctefx-r3di.bin"
-
-#ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP
-MODULE_FIRMWARE(EFX_FILE);
-MODULE_FIRMWARE(DESKTOP_EFX_FILE);
-MODULE_FIRMWARE(R3DI_EFX_FILE);
-#endif
-
-static const char *const dirstr[2] = { "Playback", "Capture" };
-
-#define NUM_OF_OUTPUTS 2
-static const char *const out_type_str[2] = { "Speakers", "Headphone" };
-enum {
-       SPEAKER_OUT,
-       HEADPHONE_OUT,
-};
-
-enum {
-       DIGITAL_MIC,
-       LINE_MIC_IN
-};
-
-/* Strings for Input Source Enum Control */
-static const char *const in_src_str[3] = { "Microphone", "Line In", "Front Microphone" };
-#define IN_SRC_NUM_OF_INPUTS 3
-enum {
-       REAR_MIC,
-       REAR_LINE_IN,
-       FRONT_MIC,
-};
-
-enum {
-#define VNODE_START_NID    0x80
-       VNID_SPK = VNODE_START_NID,                     /* Speaker vnid */
-       VNID_MIC,
-       VNID_HP_SEL,
-       VNID_AMIC1_SEL,
-       VNID_HP_ASEL,
-       VNID_AMIC1_ASEL,
-       VNODE_END_NID,
-#define VNODES_COUNT  (VNODE_END_NID - VNODE_START_NID)
-
-#define EFFECT_START_NID    0x90
-#define OUT_EFFECT_START_NID    EFFECT_START_NID
-       SURROUND = OUT_EFFECT_START_NID,
-       CRYSTALIZER,
-       DIALOG_PLUS,
-       SMART_VOLUME,
-       X_BASS,
-       EQUALIZER,
-       OUT_EFFECT_END_NID,
-#define OUT_EFFECTS_COUNT  (OUT_EFFECT_END_NID - OUT_EFFECT_START_NID)
-
-#define IN_EFFECT_START_NID  OUT_EFFECT_END_NID
-       ECHO_CANCELLATION = IN_EFFECT_START_NID,
-       VOICE_FOCUS,
-       MIC_SVM,
-       NOISE_REDUCTION,
-       IN_EFFECT_END_NID,
-#define IN_EFFECTS_COUNT  (IN_EFFECT_END_NID - IN_EFFECT_START_NID)
-
-       VOICEFX = IN_EFFECT_END_NID,
-       PLAY_ENHANCEMENT,
-       CRYSTAL_VOICE,
-       EFFECT_END_NID,
-       OUTPUT_SOURCE_ENUM,
-       INPUT_SOURCE_ENUM,
-       XBASS_XOVER,
-       EQ_PRESET_ENUM,
-       SMART_VOLUME_ENUM,
-       MIC_BOOST_ENUM,
-       AE5_HEADPHONE_GAIN_ENUM,
-       AE5_SOUND_FILTER_ENUM,
-       ZXR_HEADPHONE_GAIN,
-       SPEAKER_CHANNEL_CFG_ENUM,
-       SPEAKER_FULL_RANGE_FRONT,
-       SPEAKER_FULL_RANGE_REAR,
-       BASS_REDIRECTION,
-       BASS_REDIRECTION_XOVER,
-#define EFFECTS_COUNT  (EFFECT_END_NID - EFFECT_START_NID)
-};
-
-/* Effects values size*/
-#define EFFECT_VALS_MAX_COUNT 12
-
-/*
- * Default values for the effect slider controls, they are in order of their
- * effect NID's. Surround, Crystalizer, Dialog Plus, Smart Volume, and then
- * X-bass.
- */
-static const unsigned int effect_slider_defaults[] = {67, 65, 50, 74, 50};
-/* Amount of effect level sliders for ca0132_alt controls. */
-#define EFFECT_LEVEL_SLIDERS 5
-
-/* Latency introduced by DSP blocks in milliseconds. */
-#define DSP_CAPTURE_INIT_LATENCY        0
-#define DSP_CRYSTAL_VOICE_LATENCY       124
-#define DSP_PLAYBACK_INIT_LATENCY       13
-#define DSP_PLAY_ENHANCEMENT_LATENCY    30
-#define DSP_SPEAKER_OUT_LATENCY         7
-
-struct ct_effect {
-       const char *name;
-       hda_nid_t nid;
-       int mid; /*effect module ID*/
-       int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/
-       int direct; /* 0:output; 1:input*/
-       int params; /* number of default non-on/off params */
-       /*effect default values, 1st is on/off. */
-       unsigned int def_vals[EFFECT_VALS_MAX_COUNT];
-};
-
-#define EFX_DIR_OUT 0
-#define EFX_DIR_IN  1
-
-static const struct ct_effect ca0132_effects[EFFECTS_COUNT] = {
-       { .name = "Surround",
-         .nid = SURROUND,
-         .mid = 0x96,
-         .reqs = {0, 1},
-         .direct = EFX_DIR_OUT,
-         .params = 1,
-         .def_vals = {0x3F800000, 0x3F2B851F}
-       },
-       { .name = "Crystalizer",
-         .nid = CRYSTALIZER,
-         .mid = 0x96,
-         .reqs = {7, 8},
-         .direct = EFX_DIR_OUT,
-         .params = 1,
-         .def_vals = {0x3F800000, 0x3F266666}
-       },
-       { .name = "Dialog Plus",
-         .nid = DIALOG_PLUS,
-         .mid = 0x96,
-         .reqs = {2, 3},
-         .direct = EFX_DIR_OUT,
-         .params = 1,
-         .def_vals = {0x00000000, 0x3F000000}
-       },
-       { .name = "Smart Volume",
-         .nid = SMART_VOLUME,
-         .mid = 0x96,
-         .reqs = {4, 5, 6},
-         .direct = EFX_DIR_OUT,
-         .params = 2,
-         .def_vals = {0x3F800000, 0x3F3D70A4, 0x00000000}
-       },
-       { .name = "X-Bass",
-         .nid = X_BASS,
-         .mid = 0x96,
-         .reqs = {24, 23, 25},
-         .direct = EFX_DIR_OUT,
-         .params = 2,
-         .def_vals = {0x3F800000, 0x42A00000, 0x3F000000}
-       },
-       { .name = "Equalizer",
-         .nid = EQUALIZER,
-         .mid = 0x96,
-         .reqs = {9, 10, 11, 12, 13, 14,
-                       15, 16, 17, 18, 19, 20},
-         .direct = EFX_DIR_OUT,
-         .params = 11,
-         .def_vals = {0x00000000, 0x00000000, 0x00000000, 0x00000000,
-                      0x00000000, 0x00000000, 0x00000000, 0x00000000,
-                      0x00000000, 0x00000000, 0x00000000, 0x00000000}
-       },
-       { .name = "Echo Cancellation",
-         .nid = ECHO_CANCELLATION,
-         .mid = 0x95,
-         .reqs = {0, 1, 2, 3},
-         .direct = EFX_DIR_IN,
-         .params = 3,
-         .def_vals = {0x00000000, 0x3F3A9692, 0x00000000, 0x00000000}
-       },
-       { .name = "Voice Focus",
-         .nid = VOICE_FOCUS,
-         .mid = 0x95,
-         .reqs = {6, 7, 8, 9},
-         .direct = EFX_DIR_IN,
-         .params = 3,
-         .def_vals = {0x3F800000, 0x3D7DF3B6, 0x41F00000, 0x41F00000}
-       },
-       { .name = "Mic SVM",
-         .nid = MIC_SVM,
-         .mid = 0x95,
-         .reqs = {44, 45},
-         .direct = EFX_DIR_IN,
-         .params = 1,
-         .def_vals = {0x00000000, 0x3F3D70A4}
-       },
-       { .name = "Noise Reduction",
-         .nid = NOISE_REDUCTION,
-         .mid = 0x95,
-         .reqs = {4, 5},
-         .direct = EFX_DIR_IN,
-         .params = 1,
-         .def_vals = {0x3F800000, 0x3F000000}
-       },
-       { .name = "VoiceFX",
-         .nid = VOICEFX,
-         .mid = 0x95,
-         .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18},
-         .direct = EFX_DIR_IN,
-         .params = 8,
-         .def_vals = {0x00000000, 0x43C80000, 0x44AF0000, 0x44FA0000,
-                      0x3F800000, 0x3F800000, 0x3F800000, 0x00000000,
-                      0x00000000}
-       }
-};
-
-/* Tuning controls */
-#ifdef ENABLE_TUNING_CONTROLS
-
-enum {
-#define TUNING_CTL_START_NID  0xC0
-       WEDGE_ANGLE = TUNING_CTL_START_NID,
-       SVM_LEVEL,
-       EQUALIZER_BAND_0,
-       EQUALIZER_BAND_1,
-       EQUALIZER_BAND_2,
-       EQUALIZER_BAND_3,
-       EQUALIZER_BAND_4,
-       EQUALIZER_BAND_5,
-       EQUALIZER_BAND_6,
-       EQUALIZER_BAND_7,
-       EQUALIZER_BAND_8,
-       EQUALIZER_BAND_9,
-       TUNING_CTL_END_NID
-#define TUNING_CTLS_COUNT  (TUNING_CTL_END_NID - TUNING_CTL_START_NID)
-};
-
-struct ct_tuning_ctl {
-       const char *name;
-       hda_nid_t parent_nid;
-       hda_nid_t nid;
-       int mid; /*effect module ID*/
-       int req; /*effect module request*/
-       int direct; /* 0:output; 1:input*/
-       unsigned int def_val;/*effect default values*/
-};
-
-static const struct ct_tuning_ctl ca0132_tuning_ctls[] = {
-       { .name = "Wedge Angle",
-         .parent_nid = VOICE_FOCUS,
-         .nid = WEDGE_ANGLE,
-         .mid = 0x95,
-         .req = 8,
-         .direct = EFX_DIR_IN,
-         .def_val = 0x41F00000
-       },
-       { .name = "SVM Level",
-         .parent_nid = MIC_SVM,
-         .nid = SVM_LEVEL,
-         .mid = 0x95,
-         .req = 45,
-         .direct = EFX_DIR_IN,
-         .def_val = 0x3F3D70A4
-       },
-       { .name = "EQ Band0",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_0,
-         .mid = 0x96,
-         .req = 11,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band1",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_1,
-         .mid = 0x96,
-         .req = 12,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band2",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_2,
-         .mid = 0x96,
-         .req = 13,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band3",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_3,
-         .mid = 0x96,
-         .req = 14,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band4",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_4,
-         .mid = 0x96,
-         .req = 15,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band5",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_5,
-         .mid = 0x96,
-         .req = 16,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band6",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_6,
-         .mid = 0x96,
-         .req = 17,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band7",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_7,
-         .mid = 0x96,
-         .req = 18,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band8",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_8,
-         .mid = 0x96,
-         .req = 19,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       },
-       { .name = "EQ Band9",
-         .parent_nid = EQUALIZER,
-         .nid = EQUALIZER_BAND_9,
-         .mid = 0x96,
-         .req = 20,
-         .direct = EFX_DIR_OUT,
-         .def_val = 0x00000000
-       }
-};
-#endif
-
-/* Voice FX Presets */
-#define VOICEFX_MAX_PARAM_COUNT 9
-
-struct ct_voicefx {
-       const char *name;
-       hda_nid_t nid;
-       int mid;
-       int reqs[VOICEFX_MAX_PARAM_COUNT]; /*effect module request*/
-};
-
-struct ct_voicefx_preset {
-       const char *name; /*preset name*/
-       unsigned int vals[VOICEFX_MAX_PARAM_COUNT];
-};
-
-static const struct ct_voicefx ca0132_voicefx = {
-       .name = "VoiceFX Capture Switch",
-       .nid = VOICEFX,
-       .mid = 0x95,
-       .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18}
-};
-
-static const struct ct_voicefx_preset ca0132_voicefx_presets[] = {
-       { .name = "Neutral",
-         .vals = { 0x00000000, 0x43C80000, 0x44AF0000,
-                   0x44FA0000, 0x3F800000, 0x3F800000,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       },
-       { .name = "Female2Male",
-         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
-                   0x44FA0000, 0x3F19999A, 0x3F866666,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       },
-       { .name = "Male2Female",
-         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
-                   0x450AC000, 0x4017AE14, 0x3F6B851F,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       },
-       { .name = "ScrappyKid",
-         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
-                   0x44FA0000, 0x40400000, 0x3F28F5C3,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       },
-       { .name = "Elderly",
-         .vals = { 0x3F800000, 0x44324000, 0x44BB8000,
-                   0x44E10000, 0x3FB33333, 0x3FB9999A,
-                   0x3F800000, 0x3E3A2E43, 0x00000000 }
-       },
-       { .name = "Orc",
-         .vals = { 0x3F800000, 0x43EA0000, 0x44A52000,
-                   0x45098000, 0x3F266666, 0x3FC00000,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       },
-       { .name = "Elf",
-         .vals = { 0x3F800000, 0x43C70000, 0x44AE6000,
-                   0x45193000, 0x3F8E147B, 0x3F75C28F,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       },
-       { .name = "Dwarf",
-         .vals = { 0x3F800000, 0x43930000, 0x44BEE000,
-                   0x45007000, 0x3F451EB8, 0x3F7851EC,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       },
-       { .name = "AlienBrute",
-         .vals = { 0x3F800000, 0x43BFC5AC, 0x44B28FDF,
-                   0x451F6000, 0x3F266666, 0x3FA7D945,
-                   0x3F800000, 0x3CF5C28F, 0x00000000 }
-       },
-       { .name = "Robot",
-         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
-                   0x44FA0000, 0x3FB2718B, 0x3F800000,
-                   0xBC07010E, 0x00000000, 0x00000000 }
-       },
-       { .name = "Marine",
-         .vals = { 0x3F800000, 0x43C20000, 0x44906000,
-                   0x44E70000, 0x3F4CCCCD, 0x3F8A3D71,
-                   0x3F0A3D71, 0x00000000, 0x00000000 }
-       },
-       { .name = "Emo",
-         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
-                   0x44FA0000, 0x3F800000, 0x3F800000,
-                   0x3E4CCCCD, 0x00000000, 0x00000000 }
-       },
-       { .name = "DeepVoice",
-         .vals = { 0x3F800000, 0x43A9C5AC, 0x44AA4FDF,
-                   0x44FFC000, 0x3EDBB56F, 0x3F99C4CA,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       },
-       { .name = "Munchkin",
-         .vals = { 0x3F800000, 0x43C80000, 0x44AF0000,
-                   0x44FA0000, 0x3F800000, 0x3F1A043C,
-                   0x3F800000, 0x00000000, 0x00000000 }
-       }
-};
-
-/* ca0132 EQ presets, taken from Windows Sound Blaster Z Driver */
-
-#define EQ_PRESET_MAX_PARAM_COUNT 11
-
-struct ct_eq {
-       const char *name;
-       hda_nid_t nid;
-       int mid;
-       int reqs[EQ_PRESET_MAX_PARAM_COUNT]; /*effect module request*/
-};
-
-struct ct_eq_preset {
-       const char *name; /*preset name*/
-       unsigned int vals[EQ_PRESET_MAX_PARAM_COUNT];
-};
-
-static const struct ct_eq ca0132_alt_eq_enum = {
-       .name = "FX: Equalizer Preset Switch",
-       .nid = EQ_PRESET_ENUM,
-       .mid = 0x96,
-       .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}
-};
-
-
-static const struct ct_eq_preset ca0132_alt_eq_presets[] = {
-       { .name = "Flat",
-        .vals = { 0x00000000, 0x00000000, 0x00000000,
-                  0x00000000, 0x00000000, 0x00000000,
-                  0x00000000, 0x00000000, 0x00000000,
-                  0x00000000, 0x00000000            }
-       },
-       { .name = "Acoustic",
-        .vals = { 0x00000000, 0x00000000, 0x3F8CCCCD,
-                  0x40000000, 0x00000000, 0x00000000,
-                  0x00000000, 0x00000000, 0x40000000,
-                  0x40000000, 0x40000000            }
-       },
-       { .name = "Classical",
-        .vals = { 0x00000000, 0x00000000, 0x40C00000,
-                  0x40C00000, 0x40466666, 0x00000000,
-                  0x00000000, 0x00000000, 0x00000000,
-                  0x40466666, 0x40466666            }
-       },
-       { .name = "Country",
-        .vals = { 0x00000000, 0xBF99999A, 0x00000000,
-                  0x3FA66666, 0x3FA66666, 0x3F8CCCCD,
-                  0x00000000, 0x00000000, 0x40000000,
-                  0x40466666, 0x40800000            }
-       },
-       { .name = "Dance",
-        .vals = { 0x00000000, 0xBF99999A, 0x40000000,
-                  0x40466666, 0x40866666, 0xBF99999A,
-                  0xBF99999A, 0x00000000, 0x00000000,
-                  0x40800000, 0x40800000            }
-       },
-       { .name = "Jazz",
-        .vals = { 0x00000000, 0x00000000, 0x00000000,
-                  0x3F8CCCCD, 0x40800000, 0x40800000,
-                  0x40800000, 0x00000000, 0x3F8CCCCD,
-                  0x40466666, 0x40466666            }
-       },
-       { .name = "New Age",
-        .vals = { 0x00000000, 0x00000000, 0x40000000,
-                  0x40000000, 0x00000000, 0x00000000,
-                  0x00000000, 0x3F8CCCCD, 0x40000000,
-                  0x40000000, 0x40000000            }
-       },
-       { .name = "Pop",
-        .vals = { 0x00000000, 0xBFCCCCCD, 0x00000000,
-                  0x40000000, 0x40000000, 0x00000000,
-                  0xBF99999A, 0xBF99999A, 0x00000000,
-                  0x40466666, 0x40C00000            }
-       },
-       { .name = "Rock",
-        .vals = { 0x00000000, 0xBF99999A, 0xBF99999A,
-                  0x3F8CCCCD, 0x40000000, 0xBF99999A,
-                  0xBF99999A, 0x00000000, 0x00000000,
-                  0x40800000, 0x40800000            }
-       },
-       { .name = "Vocal",
-        .vals = { 0x00000000, 0xC0000000, 0xBF99999A,
-                  0xBF99999A, 0x00000000, 0x40466666,
-                  0x40800000, 0x40466666, 0x00000000,
-                  0x00000000, 0x3F8CCCCD            }
-       }
-};
-
-/*
- * DSP reqs for handling full-range speakers/bass redirection. If a speaker is
- * set as not being full range, and bass redirection is enabled, all
- * frequencies below the crossover frequency are redirected to the LFE
- * channel. If the surround configuration has no LFE channel, this can't be
- * enabled. X-Bass must be disabled when using these.
- */
-enum speaker_range_reqs {
-       SPEAKER_BASS_REDIRECT            = 0x15,
-       SPEAKER_BASS_REDIRECT_XOVER_FREQ = 0x16,
-       /* Between 0x16-0x1a are the X-Bass reqs. */
-       SPEAKER_FULL_RANGE_FRONT_L_R     = 0x1a,
-       SPEAKER_FULL_RANGE_CENTER_LFE    = 0x1b,
-       SPEAKER_FULL_RANGE_REAR_L_R      = 0x1c,
-       SPEAKER_FULL_RANGE_SURROUND_L_R  = 0x1d,
-       SPEAKER_BASS_REDIRECT_SUB_GAIN   = 0x1e,
-};
-
-/*
- * Definitions for the DSP req's to handle speaker tuning. These all belong to
- * module ID 0x96, the output effects module.
- */
-enum speaker_tuning_reqs {
-       /*
-        * Currently, this value is always set to 0.0f. However, on Windows,
-        * when selecting certain headphone profiles on the new Sound Blaster
-        * connect software, the QUERY_SPEAKER_EQ_ADDRESS req on mid 0x80 is
-        * sent. This gets the speaker EQ address area, which is then used to
-        * send over (presumably) an equalizer profile for the specific
-        * headphone setup. It is sent using the same method the DSP
-        * firmware is uploaded with, which I believe is why the 'ctspeq.bin'
-        * file exists in linux firmware tree but goes unused. It would also
-        * explain why the QUERY_SPEAKER_EQ_ADDRESS req is defined but unused.
-        * Once this profile is sent over, SPEAKER_TUNING_USE_SPEAKER_EQ is
-        * set to 1.0f.
-        */
-       SPEAKER_TUNING_USE_SPEAKER_EQ           = 0x1f,
-       SPEAKER_TUNING_ENABLE_CENTER_EQ         = 0x20,
-       SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL     = 0x21,
-       SPEAKER_TUNING_FRONT_RIGHT_VOL_LEVEL    = 0x22,
-       SPEAKER_TUNING_CENTER_VOL_LEVEL         = 0x23,
-       SPEAKER_TUNING_LFE_VOL_LEVEL            = 0x24,
-       SPEAKER_TUNING_REAR_LEFT_VOL_LEVEL      = 0x25,
-       SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL     = 0x26,
-       SPEAKER_TUNING_SURROUND_LEFT_VOL_LEVEL  = 0x27,
-       SPEAKER_TUNING_SURROUND_RIGHT_VOL_LEVEL = 0x28,
-       /*
-        * Inversion is used when setting headphone virtualization to line
-        * out. Not sure why this is, but it's the only place it's ever used.
-        */
-       SPEAKER_TUNING_FRONT_LEFT_INVERT        = 0x29,
-       SPEAKER_TUNING_FRONT_RIGHT_INVERT       = 0x2a,
-       SPEAKER_TUNING_CENTER_INVERT            = 0x2b,
-       SPEAKER_TUNING_LFE_INVERT               = 0x2c,
-       SPEAKER_TUNING_REAR_LEFT_INVERT         = 0x2d,
-       SPEAKER_TUNING_REAR_RIGHT_INVERT        = 0x2e,
-       SPEAKER_TUNING_SURROUND_LEFT_INVERT     = 0x2f,
-       SPEAKER_TUNING_SURROUND_RIGHT_INVERT    = 0x30,
-       /* Delay is used when setting surround speaker distance in Windows. */
-       SPEAKER_TUNING_FRONT_LEFT_DELAY         = 0x31,
-       SPEAKER_TUNING_FRONT_RIGHT_DELAY        = 0x32,
-       SPEAKER_TUNING_CENTER_DELAY             = 0x33,
-       SPEAKER_TUNING_LFE_DELAY                = 0x34,
-       SPEAKER_TUNING_REAR_LEFT_DELAY          = 0x35,
-       SPEAKER_TUNING_REAR_RIGHT_DELAY         = 0x36,
-       SPEAKER_TUNING_SURROUND_LEFT_DELAY      = 0x37,
-       SPEAKER_TUNING_SURROUND_RIGHT_DELAY     = 0x38,
-       /* Of these two, only mute seems to ever be used. */
-       SPEAKER_TUNING_MAIN_VOLUME              = 0x39,
-       SPEAKER_TUNING_MUTE                     = 0x3a,
-};
-
-/* Surround output channel count configuration structures. */
-#define SPEAKER_CHANNEL_CFG_COUNT 5
-enum {
-       SPEAKER_CHANNELS_2_0,
-       SPEAKER_CHANNELS_2_1,
-       SPEAKER_CHANNELS_4_0,
-       SPEAKER_CHANNELS_4_1,
-       SPEAKER_CHANNELS_5_1,
-};
-
-struct ca0132_alt_speaker_channel_cfg {
-       const char *name;
-       unsigned int val;
-};
-
-static const struct ca0132_alt_speaker_channel_cfg speaker_channel_cfgs[] = {
-       { .name = "2.0",
-         .val = FLOAT_ONE
-       },
-       { .name = "2.1",
-         .val = FLOAT_TWO
-       },
-       { .name = "4.0",
-         .val = FLOAT_FIVE
-       },
-       { .name = "4.1",
-         .val = FLOAT_SIX
-       },
-       { .name = "5.1",
-         .val = FLOAT_EIGHT
-       }
-};
-
-/*
- * DSP volume setting structs. Req 1 is left volume, req 2 is right volume,
- * and I don't know what the third req is, but it's always zero. I assume it's
- * some sort of update or set command to tell the DSP there's new volume info.
- */
-#define DSP_VOL_OUT 0
-#define DSP_VOL_IN  1
-
-struct ct_dsp_volume_ctl {
-       hda_nid_t vnid;
-       int mid; /* module ID*/
-       unsigned int reqs[3]; /* scp req ID */
-};
-
-static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = {
-       { .vnid = VNID_SPK,
-         .mid = 0x32,
-         .reqs = {3, 4, 2}
-       },
-       { .vnid = VNID_MIC,
-         .mid = 0x37,
-         .reqs = {2, 3, 1}
-       }
-};
-
-/* Values for ca0113_mmio_command_set for selecting output. */
-#define AE_CA0113_OUT_SET_COMMANDS 6
-struct ae_ca0113_output_set {
-       unsigned int group[AE_CA0113_OUT_SET_COMMANDS];
-       unsigned int target[AE_CA0113_OUT_SET_COMMANDS];
-       unsigned int vals[NUM_OF_OUTPUTS][AE_CA0113_OUT_SET_COMMANDS];
-};
-
-static const struct ae_ca0113_output_set ae5_ca0113_output_presets = {
-       .group =  { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
-       .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
-                   /* Speakers. */
-       .vals =   { { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f },
-                   /* Headphones. */
-                   { 0x3f, 0x3f, 0x00, 0x00, 0x00, 0x00 } },
-};
-
-static const struct ae_ca0113_output_set ae7_ca0113_output_presets = {
-       .group  = { 0x30, 0x30, 0x48, 0x48, 0x48, 0x30 },
-       .target = { 0x2e, 0x30, 0x0d, 0x17, 0x19, 0x32 },
-                   /* Speakers. */
-       .vals   = { { 0x00, 0x00, 0x40, 0x00, 0x00, 0x3f },
-                   /* Headphones. */
-                   { 0x3f, 0x3f, 0x00, 0x00, 0x02, 0x00 } },
-};
-
-/* ae5 ca0113 command sequences to set headphone gain levels. */
-#define AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS 4
-struct ae5_headphone_gain_set {
-       const char *name;
-       unsigned int vals[AE5_HEADPHONE_GAIN_PRESET_MAX_COMMANDS];
-};
-
-static const struct ae5_headphone_gain_set ae5_headphone_gain_presets[] = {
-       { .name = "Low (16-31",
-         .vals = { 0xff, 0x2c, 0xf5, 0x32 }
-       },
-       { .name = "Medium (32-149",
-         .vals = { 0x38, 0xa8, 0x3e, 0x4c }
-       },
-       { .name = "High (150-600",
-         .vals = { 0xff, 0xff, 0xff, 0x7f }
-       }
-};
-
-struct ae5_filter_set {
-       const char *name;
-       unsigned int val;
-};
-
-static const struct ae5_filter_set ae5_filter_presets[] = {
-       { .name = "Slow Roll Off",
-         .val = 0xa0
-       },
-       { .name = "Minimum Phase",
-         .val = 0xc0
-       },
-       { .name = "Fast Roll Off",
-         .val = 0x80
-       }
-};
-
-/*
- * Data structures for storing audio router remapping data. These are used to
- * remap a currently active streams ports.
- */
-struct chipio_stream_remap_data {
-       unsigned int stream_id;
-       unsigned int count;
-
-       unsigned int offset[16];
-       unsigned int value[16];
-};
-
-static const struct chipio_stream_remap_data stream_remap_data[] = {
-       { .stream_id = 0x14,
-         .count     = 0x04,
-         .offset    = { 0x00, 0x04, 0x08, 0x0c },
-         .value     = { 0x0001f8c0, 0x0001f9c1, 0x0001fac6, 0x0001fbc7 },
-       },
-       { .stream_id = 0x0c,
-         .count     = 0x0c,
-         .offset    = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, 0x18, 0x1c,
-                        0x20, 0x24, 0x28, 0x2c },
-         .value     = { 0x0001e0c0, 0x0001e1c1, 0x0001e4c2, 0x0001e5c3,
-                        0x0001e2c4, 0x0001e3c5, 0x0001e8c6, 0x0001e9c7,
-                        0x0001ecc8, 0x0001edc9, 0x0001eaca, 0x0001ebcb },
-       },
-       { .stream_id = 0x0c,
-         .count     = 0x08,
-         .offset    = { 0x08, 0x0c, 0x10, 0x14, 0x20, 0x24, 0x28, 0x2c },
-         .value     = { 0x000140c2, 0x000141c3, 0x000150c4, 0x000151c5,
-                        0x000142c8, 0x000143c9, 0x000152ca, 0x000153cb },
-       }
-};
-
-enum hda_cmd_vendor_io {
-       /* for DspIO node */
-       VENDOR_DSPIO_SCP_WRITE_DATA_LOW      = 0x000,
-       VENDOR_DSPIO_SCP_WRITE_DATA_HIGH     = 0x100,
-
-       VENDOR_DSPIO_STATUS                  = 0xF01,
-       VENDOR_DSPIO_SCP_POST_READ_DATA      = 0x702,
-       VENDOR_DSPIO_SCP_READ_DATA           = 0xF02,
-       VENDOR_DSPIO_DSP_INIT                = 0x703,
-       VENDOR_DSPIO_SCP_POST_COUNT_QUERY    = 0x704,
-       VENDOR_DSPIO_SCP_READ_COUNT          = 0xF04,
-
-       /* for ChipIO node */
-       VENDOR_CHIPIO_ADDRESS_LOW            = 0x000,
-       VENDOR_CHIPIO_ADDRESS_HIGH           = 0x100,
-       VENDOR_CHIPIO_STREAM_FORMAT          = 0x200,
-       VENDOR_CHIPIO_DATA_LOW               = 0x300,
-       VENDOR_CHIPIO_DATA_HIGH              = 0x400,
-
-       VENDOR_CHIPIO_8051_WRITE_DIRECT      = 0x500,
-       VENDOR_CHIPIO_8051_READ_DIRECT       = 0xD00,
-
-       VENDOR_CHIPIO_GET_PARAMETER          = 0xF00,
-       VENDOR_CHIPIO_STATUS                 = 0xF01,
-       VENDOR_CHIPIO_HIC_POST_READ          = 0x702,
-       VENDOR_CHIPIO_HIC_READ_DATA          = 0xF03,
-
-       VENDOR_CHIPIO_8051_DATA_WRITE        = 0x707,
-       VENDOR_CHIPIO_8051_DATA_READ         = 0xF07,
-       VENDOR_CHIPIO_8051_PMEM_READ         = 0xF08,
-       VENDOR_CHIPIO_8051_IRAM_WRITE        = 0x709,
-       VENDOR_CHIPIO_8051_IRAM_READ         = 0xF09,
-
-       VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE   = 0x70A,
-       VENDOR_CHIPIO_CT_EXTENSIONS_GET      = 0xF0A,
-
-       VENDOR_CHIPIO_PLL_PMU_WRITE          = 0x70C,
-       VENDOR_CHIPIO_PLL_PMU_READ           = 0xF0C,
-       VENDOR_CHIPIO_8051_ADDRESS_LOW       = 0x70D,
-       VENDOR_CHIPIO_8051_ADDRESS_HIGH      = 0x70E,
-       VENDOR_CHIPIO_FLAG_SET               = 0x70F,
-       VENDOR_CHIPIO_FLAGS_GET              = 0xF0F,
-       VENDOR_CHIPIO_PARAM_SET              = 0x710,
-       VENDOR_CHIPIO_PARAM_GET              = 0xF10,
-
-       VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET  = 0x711,
-       VENDOR_CHIPIO_PORT_ALLOC_SET         = 0x712,
-       VENDOR_CHIPIO_PORT_ALLOC_GET         = 0xF12,
-       VENDOR_CHIPIO_PORT_FREE_SET          = 0x713,
-
-       VENDOR_CHIPIO_PARAM_EX_ID_GET        = 0xF17,
-       VENDOR_CHIPIO_PARAM_EX_ID_SET        = 0x717,
-       VENDOR_CHIPIO_PARAM_EX_VALUE_GET     = 0xF18,
-       VENDOR_CHIPIO_PARAM_EX_VALUE_SET     = 0x718,
-
-       VENDOR_CHIPIO_DMIC_CTL_SET           = 0x788,
-       VENDOR_CHIPIO_DMIC_CTL_GET           = 0xF88,
-       VENDOR_CHIPIO_DMIC_PIN_SET           = 0x789,
-       VENDOR_CHIPIO_DMIC_PIN_GET           = 0xF89,
-       VENDOR_CHIPIO_DMIC_MCLK_SET          = 0x78A,
-       VENDOR_CHIPIO_DMIC_MCLK_GET          = 0xF8A,
-
-       VENDOR_CHIPIO_EAPD_SEL_SET           = 0x78D
-};
-
-/*
- *  Control flag IDs
- */
-enum control_flag_id {
-       /* Connection manager stream setup is bypassed/enabled */
-       CONTROL_FLAG_C_MGR                  = 0,
-       /* DSP DMA is bypassed/enabled */
-       CONTROL_FLAG_DMA                    = 1,
-       /* 8051 'idle' mode is disabled/enabled */
-       CONTROL_FLAG_IDLE_ENABLE            = 2,
-       /* Tracker for the SPDIF-in path is bypassed/enabled */
-       CONTROL_FLAG_TRACKER                = 3,
-       /* DigitalOut to Spdif2Out connection is disabled/enabled */
-       CONTROL_FLAG_SPDIF2OUT              = 4,
-       /* Digital Microphone is disabled/enabled */
-       CONTROL_FLAG_DMIC                   = 5,
-       /* ADC_B rate is 48 kHz/96 kHz */
-       CONTROL_FLAG_ADC_B_96KHZ            = 6,
-       /* ADC_C rate is 48 kHz/96 kHz */
-       CONTROL_FLAG_ADC_C_96KHZ            = 7,
-       /* DAC rate is 48 kHz/96 kHz (affects all DACs) */
-       CONTROL_FLAG_DAC_96KHZ              = 8,
-       /* DSP rate is 48 kHz/96 kHz */
-       CONTROL_FLAG_DSP_96KHZ              = 9,
-       /* SRC clock is 98 MHz/196 MHz (196 MHz forces rate to 96 KHz) */
-       CONTROL_FLAG_SRC_CLOCK_196MHZ       = 10,
-       /* SRC rate is 48 kHz/96 kHz (48 kHz disabled when clock is 196 MHz) */
-       CONTROL_FLAG_SRC_RATE_96KHZ         = 11,
-       /* Decode Loop (DSP->SRC->DSP) is disabled/enabled */
-       CONTROL_FLAG_DECODE_LOOP            = 12,
-       /* De-emphasis filter on DAC-1 disabled/enabled */
-       CONTROL_FLAG_DAC1_DEEMPHASIS        = 13,
-       /* De-emphasis filter on DAC-2 disabled/enabled */
-       CONTROL_FLAG_DAC2_DEEMPHASIS        = 14,
-       /* De-emphasis filter on DAC-3 disabled/enabled */
-       CONTROL_FLAG_DAC3_DEEMPHASIS        = 15,
-       /* High-pass filter on ADC_B disabled/enabled */
-       CONTROL_FLAG_ADC_B_HIGH_PASS        = 16,
-       /* High-pass filter on ADC_C disabled/enabled */
-       CONTROL_FLAG_ADC_C_HIGH_PASS        = 17,
-       /* Common mode on Port_A disabled/enabled */
-       CONTROL_FLAG_PORT_A_COMMON_MODE     = 18,
-       /* Common mode on Port_D disabled/enabled */
-       CONTROL_FLAG_PORT_D_COMMON_MODE     = 19,
-       /* Impedance for ramp generator on Port_A 16 Ohm/10K Ohm */
-       CONTROL_FLAG_PORT_A_10KOHM_LOAD     = 20,
-       /* Impedance for ramp generator on Port_D, 16 Ohm/10K Ohm */
-       CONTROL_FLAG_PORT_D_10KOHM_LOAD     = 21,
-       /* ASI rate is 48kHz/96kHz */
-       CONTROL_FLAG_ASI_96KHZ              = 22,
-       /* DAC power settings able to control attached ports no/yes */
-       CONTROL_FLAG_DACS_CONTROL_PORTS     = 23,
-       /* Clock Stop OK reporting is disabled/enabled */
-       CONTROL_FLAG_CONTROL_STOP_OK_ENABLE = 24,
-       /* Number of control flags */
-       CONTROL_FLAGS_MAX = (CONTROL_FLAG_CONTROL_STOP_OK_ENABLE+1)
-};
-
-/*
- * Control parameter IDs
- */
-enum control_param_id {
-       /* 0: None, 1: Mic1In*/
-       CONTROL_PARAM_VIP_SOURCE               = 1,
-       /* 0: force HDA, 1: allow DSP if HDA Spdif1Out stream is idle */
-       CONTROL_PARAM_SPDIF1_SOURCE            = 2,
-       /* Port A output stage gain setting to use when 16 Ohm output
-        * impedance is selected*/
-       CONTROL_PARAM_PORTA_160OHM_GAIN        = 8,
-       /* Port D output stage gain setting to use when 16 Ohm output
-        * impedance is selected*/
-       CONTROL_PARAM_PORTD_160OHM_GAIN        = 10,
-
-       /*
-        * This control param name was found in the 8051 memory, and makes
-        * sense given the fact the AE-5 uses it and has the ASI flag set.
-        */
-       CONTROL_PARAM_ASI                      = 23,
-
-       /* Stream Control */
-
-       /* Select stream with the given ID */
-       CONTROL_PARAM_STREAM_ID                = 24,
-       /* Source connection point for the selected stream */
-       CONTROL_PARAM_STREAM_SOURCE_CONN_POINT = 25,
-       /* Destination connection point for the selected stream */
-       CONTROL_PARAM_STREAM_DEST_CONN_POINT   = 26,
-       /* Number of audio channels in the selected stream */
-       CONTROL_PARAM_STREAMS_CHANNELS         = 27,
-       /*Enable control for the selected stream */
-       CONTROL_PARAM_STREAM_CONTROL           = 28,
-
-       /* Connection Point Control */
-
-       /* Select connection point with the given ID */
-       CONTROL_PARAM_CONN_POINT_ID            = 29,
-       /* Connection point sample rate */
-       CONTROL_PARAM_CONN_POINT_SAMPLE_RATE   = 30,
-
-       /* Node Control */
-
-       /* Select HDA node with the given ID */
-       CONTROL_PARAM_NODE_ID                  = 31
-};
-
-/*
- *  Dsp Io Status codes
- */
-enum hda_vendor_status_dspio {
-       /* Success */
-       VENDOR_STATUS_DSPIO_OK                       = 0x00,
-       /* Busy, unable to accept new command, the host must retry */
-       VENDOR_STATUS_DSPIO_BUSY                     = 0x01,
-       /* SCP command queue is full */
-       VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL   = 0x02,
-       /* SCP response queue is empty */
-       VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY = 0x03
-};
-
-/*
- *  Chip Io Status codes
- */
-enum hda_vendor_status_chipio {
-       /* Success */
-       VENDOR_STATUS_CHIPIO_OK   = 0x00,
-       /* Busy, unable to accept new command, the host must retry */
-       VENDOR_STATUS_CHIPIO_BUSY = 0x01
-};
-
-/*
- *  CA0132 sample rate
- */
-enum ca0132_sample_rate {
-       SR_6_000        = 0x00,
-       SR_8_000        = 0x01,
-       SR_9_600        = 0x02,
-       SR_11_025       = 0x03,
-       SR_16_000       = 0x04,
-       SR_22_050       = 0x05,
-       SR_24_000       = 0x06,
-       SR_32_000       = 0x07,
-       SR_44_100       = 0x08,
-       SR_48_000       = 0x09,
-       SR_88_200       = 0x0A,
-       SR_96_000       = 0x0B,
-       SR_144_000      = 0x0C,
-       SR_176_400      = 0x0D,
-       SR_192_000      = 0x0E,
-       SR_384_000      = 0x0F,
-
-       SR_COUNT        = 0x10,
-
-       SR_RATE_UNKNOWN = 0x1F
-};
-
-enum dsp_download_state {
-       DSP_DOWNLOAD_FAILED = -1,
-       DSP_DOWNLOAD_INIT   = 0,
-       DSP_DOWNLOADING     = 1,
-       DSP_DOWNLOADED      = 2
-};
-
-/* retrieve parameters from hda format */
-#define get_hdafmt_chs(fmt)    (fmt & 0xf)
-#define get_hdafmt_bits(fmt)   ((fmt >> 4) & 0x7)
-#define get_hdafmt_rate(fmt)   ((fmt >> 8) & 0x7f)
-#define get_hdafmt_type(fmt)   ((fmt >> 15) & 0x1)
-
-/*
- * CA0132 specific
- */
-
-struct ca0132_spec {
-       const struct snd_kcontrol_new *mixers[5];
-       unsigned int num_mixers;
-       const struct hda_verb *base_init_verbs;
-       const struct hda_verb *base_exit_verbs;
-       const struct hda_verb *chip_init_verbs;
-       const struct hda_verb *desktop_init_verbs;
-       struct hda_verb *spec_init_verbs;
-       struct auto_pin_cfg autocfg;
-
-       /* Nodes configurations */
-       struct hda_multi_out multiout;
-       hda_nid_t out_pins[AUTO_CFG_MAX_OUTS];
-       hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
-       unsigned int num_outputs;
-       hda_nid_t input_pins[AUTO_PIN_LAST];
-       hda_nid_t adcs[AUTO_PIN_LAST];
-       hda_nid_t dig_out;
-       hda_nid_t dig_in;
-       unsigned int num_inputs;
-       hda_nid_t shared_mic_nid;
-       hda_nid_t shared_out_nid;
-       hda_nid_t unsol_tag_hp;
-       hda_nid_t unsol_tag_front_hp; /* for desktop ca0132 codecs */
-       hda_nid_t unsol_tag_amic1;
-
-       /* chip access */
-       struct mutex chipio_mutex; /* chip access mutex */
-       u32 curr_chip_addx;
-
-       /* DSP download related */
-       enum dsp_download_state dsp_state;
-       unsigned int dsp_stream_id;
-       unsigned int wait_scp;
-       unsigned int wait_scp_header;
-       unsigned int wait_num_data;
-       unsigned int scp_resp_header;
-       unsigned int scp_resp_data[4];
-       unsigned int scp_resp_count;
-       bool startup_check_entered;
-       bool dsp_reload;
-
-       /* mixer and effects related */
-       unsigned char dmic_ctl;
-       int cur_out_type;
-       int cur_mic_type;
-       long vnode_lvol[VNODES_COUNT];
-       long vnode_rvol[VNODES_COUNT];
-       long vnode_lswitch[VNODES_COUNT];
-       long vnode_rswitch[VNODES_COUNT];
-       long effects_switch[EFFECTS_COUNT];
-       long voicefx_val;
-       long cur_mic_boost;
-       /* ca0132_alt control related values */
-       unsigned char in_enum_val;
-       unsigned char out_enum_val;
-       unsigned char channel_cfg_val;
-       unsigned char speaker_range_val[2];
-       unsigned char mic_boost_enum_val;
-       unsigned char smart_volume_setting;
-       unsigned char bass_redirection_val;
-       long bass_redirect_xover_freq;
-       long fx_ctl_val[EFFECT_LEVEL_SLIDERS];
-       long xbass_xover_freq;
-       long eq_preset_val;
-       unsigned int tlv[4];
-       struct hda_vmaster_mute_hook vmaster_mute;
-       /* AE-5 Control values */
-       unsigned char ae5_headphone_gain_val;
-       unsigned char ae5_filter_val;
-       /* ZxR Control Values */
-       unsigned char zxr_gain_set;
-
-       struct hda_codec *codec;
-       struct delayed_work unsol_hp_work;
-
-#ifdef ENABLE_TUNING_CONTROLS
-       long cur_ctl_vals[TUNING_CTLS_COUNT];
-#endif
-       /*
-        * The Recon3D, Sound Blaster Z, Sound Blaster ZxR, and Sound Blaster
-        * AE-5 all use PCI region 2 to toggle GPIO and other currently unknown
-        * things.
-        */
-       bool use_pci_mmio;
-       void __iomem *mem_base;
-
-       /*
-        * Whether or not to use the alt functions like alt_select_out,
-        * alt_select_in, etc. Only used on desktop codecs for now, because of
-        * surround sound support.
-        */
-       bool use_alt_functions;
-
-       /*
-        * Whether or not to use alt controls:  volume effect sliders, EQ
-        * presets, smart volume presets, and new control names with FX prefix.
-        * Renames PlayEnhancement and CrystalVoice too.
-        */
-       bool use_alt_controls;
-};
-
-/*
- * CA0132 quirks table
- */
-enum {
-       QUIRK_ALIENWARE,
-       QUIRK_ALIENWARE_M17XR4,
-       QUIRK_SBZ,
-       QUIRK_ZXR,
-       QUIRK_ZXR_DBPRO,
-       QUIRK_R3DI,
-       QUIRK_R3D,
-       QUIRK_AE5,
-       QUIRK_AE7,
-       QUIRK_NONE = HDA_FIXUP_ID_NOT_SET,
-};
-
-#ifdef CONFIG_PCI
-#define ca0132_quirk(spec)             ((spec)->codec->fixup_id)
-#define ca0132_use_pci_mmio(spec)      ((spec)->use_pci_mmio)
-#define ca0132_use_alt_functions(spec) ((spec)->use_alt_functions)
-#define ca0132_use_alt_controls(spec)  ((spec)->use_alt_controls)
-#else
-#define ca0132_quirk(spec)             ({ (void)(spec); QUIRK_NONE; })
-#define ca0132_use_alt_functions(spec) ({ (void)(spec); false; })
-#define ca0132_use_pci_mmio(spec)      ({ (void)(spec); false; })
-#define ca0132_use_alt_controls(spec)  ({ (void)(spec); false; })
-#endif
-
-static const struct hda_pintbl alienware_pincfgs[] = {
-       { 0x0b, 0x90170110 }, /* Builtin Speaker */
-       { 0x0c, 0x411111f0 }, /* N/A */
-       { 0x0d, 0x411111f0 }, /* N/A */
-       { 0x0e, 0x411111f0 }, /* N/A */
-       { 0x0f, 0x0321101f }, /* HP */
-       { 0x10, 0x411111f0 }, /* Headset?  disabled for now */
-       { 0x11, 0x03a11021 }, /* Mic */
-       { 0x12, 0xd5a30140 }, /* Builtin Mic */
-       { 0x13, 0x411111f0 }, /* N/A */
-       { 0x18, 0x411111f0 }, /* N/A */
-       {}
-};
-
-/* Sound Blaster Z pin configs taken from Windows Driver */
-static const struct hda_pintbl sbz_pincfgs[] = {
-       { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
-       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
-       { 0x0d, 0x014510f0 }, /* Digital Out */
-       { 0x0e, 0x01c510f0 }, /* SPDIF In */
-       { 0x0f, 0x0221701f }, /* Port A -- BackPanel HP */
-       { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
-       { 0x11, 0x01017014 }, /* Port B -- LineMicIn2 / Rear L/R */
-       { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
-       { 0x13, 0x908700f0 }, /* What U Hear In*/
-       { 0x18, 0x50d000f0 }, /* N/A */
-       {}
-};
-
-/* Sound Blaster ZxR pin configs taken from Windows Driver */
-static const struct hda_pintbl zxr_pincfgs[] = {
-       { 0x0b, 0x01047110 }, /* Port G -- Lineout FRONT L/R */
-       { 0x0c, 0x414510f0 }, /* SPDIF Out 1 - Disabled*/
-       { 0x0d, 0x014510f0 }, /* Digital Out */
-       { 0x0e, 0x41c520f0 }, /* SPDIF In - Disabled*/
-       { 0x0f, 0x0122711f }, /* Port A -- BackPanel HP */
-       { 0x10, 0x01017111 }, /* Port D -- Center/LFE */
-       { 0x11, 0x01017114 }, /* Port B -- LineMicIn2 / Rear L/R */
-       { 0x12, 0x01a271f0 }, /* Port C -- LineIn1 */
-       { 0x13, 0x908700f0 }, /* What U Hear In*/
-       { 0x18, 0x50d000f0 }, /* N/A */
-       {}
-};
-
-/* Recon3D pin configs taken from Windows Driver */
-static const struct hda_pintbl r3d_pincfgs[] = {
-       { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
-       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
-       { 0x0d, 0x014510f0 }, /* Digital Out */
-       { 0x0e, 0x01c520f0 }, /* SPDIF In */
-       { 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
-       { 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
-       { 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
-       { 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
-       { 0x13, 0x908700f0 }, /* What U Hear In*/
-       { 0x18, 0x50d000f0 }, /* N/A */
-       {}
-};
-
-/* Sound Blaster AE-5 pin configs taken from Windows Driver */
-static const struct hda_pintbl ae5_pincfgs[] = {
-       { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */
-       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
-       { 0x0d, 0x014510f0 }, /* Digital Out */
-       { 0x0e, 0x01c510f0 }, /* SPDIF In */
-       { 0x0f, 0x01017114 }, /* Port A -- Rear L/R. */
-       { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */
-       { 0x11, 0x012170ff }, /* Port B -- LineMicIn2 / Rear Headphone */
-       { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */
-       { 0x13, 0x908700f0 }, /* What U Hear In*/
-       { 0x18, 0x50d000f0 }, /* N/A */
-       {}
-};
-
-/* Recon3D integrated pin configs taken from Windows Driver */
-static const struct hda_pintbl r3di_pincfgs[] = {
-       { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */
-       { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */
-       { 0x0d, 0x014510f0 }, /* Digital Out */
-       { 0x0e, 0x41c520f0 }, /* SPDIF In */
-       { 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */
-       { 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */
-       { 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */
-       { 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */
-       { 0x13, 0x908700f0 }, /* What U Hear In*/
-       { 0x18, 0x500000f0 }, /* N/A */
-       {}
-};
-
-static const struct hda_pintbl ae7_pincfgs[] = {
-       { 0x0b, 0x01017010 },
-       { 0x0c, 0x014510f0 },
-       { 0x0d, 0x414510f0 },
-       { 0x0e, 0x01c520f0 },
-       { 0x0f, 0x01017114 },
-       { 0x10, 0x01017011 },
-       { 0x11, 0x018170ff },
-       { 0x12, 0x01a170f0 },
-       { 0x13, 0x908700f0 },
-       { 0x18, 0x500000f0 },
-       {}
-};
-
-static const struct hda_quirk ca0132_quirks[] = {
-       SND_PCI_QUIRK(0x1028, 0x057b, "Alienware M17x R4", QUIRK_ALIENWARE_M17XR4),
-       SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE),
-       SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE),
-       SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE),
-       SND_PCI_QUIRK(0x1102, 0x0010, "Sound Blaster Z", QUIRK_SBZ),
-       SND_PCI_QUIRK(0x1102, 0x0023, "Sound Blaster Z", QUIRK_SBZ),
-       SND_PCI_QUIRK(0x1102, 0x0027, "Sound Blaster Z", QUIRK_SBZ),
-       SND_PCI_QUIRK(0x1102, 0x0033, "Sound Blaster ZxR", QUIRK_SBZ),
-       SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI),
-       SND_PCI_QUIRK(0x1458, 0xA026, "Gigabyte G1.Sniper Z97", QUIRK_R3DI),
-       SND_PCI_QUIRK(0x1458, 0xA036, "Gigabyte GA-Z170X-Gaming 7", QUIRK_R3DI),
-       SND_PCI_QUIRK(0x3842, 0x1038, "EVGA X99 Classified", QUIRK_R3DI),
-       SND_PCI_QUIRK(0x3842, 0x104b, "EVGA X299 Dark", QUIRK_R3DI),
-       SND_PCI_QUIRK(0x3842, 0x1055, "EVGA Z390 DARK", QUIRK_R3DI),
-       SND_PCI_QUIRK(0x1102, 0x0013, "Recon3D", QUIRK_R3D),
-       SND_PCI_QUIRK(0x1102, 0x0018, "Recon3D", QUIRK_R3D),
-       SND_PCI_QUIRK(0x1102, 0x0051, "Sound Blaster AE-5", QUIRK_AE5),
-       SND_PCI_QUIRK(0x1102, 0x0191, "Sound Blaster AE-5 Plus", QUIRK_AE5),
-       SND_PCI_QUIRK(0x1102, 0x0081, "Sound Blaster AE-7", QUIRK_AE7),
-       {}
-};
-
-static const struct hda_model_fixup ca0132_quirk_models[] = {
-       { .id = QUIRK_ALIENWARE, .name = "alienware" },
-       { .id = QUIRK_ALIENWARE_M17XR4, .name = "alienware-m17xr4" },
-       { .id = QUIRK_SBZ, .name = "sbz" },
-       { .id = QUIRK_ZXR, .name = "zxr" },
-       { .id = QUIRK_ZXR_DBPRO, .name = "zxr-dbpro" },
-       { .id = QUIRK_R3DI, .name = "r3di" },
-       { .id = QUIRK_R3D, .name = "r3d" },
-       { .id = QUIRK_AE5, .name = "ae5" },
-       { .id = QUIRK_AE7, .name = "ae7" },
-       {}
-};
-
-/* Output selection quirk info structures. */
-#define MAX_QUIRK_MMIO_GPIO_SET_VALS 3
-#define MAX_QUIRK_SCP_SET_VALS 2
-struct ca0132_alt_out_set_info {
-       unsigned int dac2port; /* ParamID 0x0d value. */
-
-       bool has_hda_gpio;
-       char hda_gpio_pin;
-       char hda_gpio_set;
-
-       unsigned int mmio_gpio_count;
-       char mmio_gpio_pin[MAX_QUIRK_MMIO_GPIO_SET_VALS];
-       char mmio_gpio_set[MAX_QUIRK_MMIO_GPIO_SET_VALS];
-
-       unsigned int scp_cmds_count;
-       unsigned int scp_cmd_mid[MAX_QUIRK_SCP_SET_VALS];
-       unsigned int scp_cmd_req[MAX_QUIRK_SCP_SET_VALS];
-       unsigned int scp_cmd_val[MAX_QUIRK_SCP_SET_VALS];
-
-       bool has_chipio_write;
-       unsigned int chipio_write_addr;
-       unsigned int chipio_write_data;
-};
-
-struct ca0132_alt_out_set_quirk_data {
-       int quirk_id;
-
-       bool has_headphone_gain;
-       bool is_ae_series;
-
-       struct ca0132_alt_out_set_info out_set_info[NUM_OF_OUTPUTS];
-};
-
-static const struct ca0132_alt_out_set_quirk_data quirk_out_set_data[] = {
-       { .quirk_id = QUIRK_R3DI,
-         .has_headphone_gain = false,
-         .is_ae_series       = false,
-         .out_set_info = {
-               /* Speakers. */
-               { .dac2port         = 0x24,
-                 .has_hda_gpio     = true,
-                 .hda_gpio_pin     = 2,
-                 .hda_gpio_set     = 1,
-                 .mmio_gpio_count  = 0,
-                 .scp_cmds_count   = 0,
-                 .has_chipio_write = false,
-               },
-               /* Headphones. */
-               { .dac2port         = 0x21,
-                 .has_hda_gpio     = true,
-                 .hda_gpio_pin     = 2,
-                 .hda_gpio_set     = 0,
-                 .mmio_gpio_count  = 0,
-                 .scp_cmds_count   = 0,
-                 .has_chipio_write = false,
-               } },
-       },
-       { .quirk_id = QUIRK_R3D,
-         .has_headphone_gain = false,
-         .is_ae_series       = false,
-         .out_set_info = {
-               /* Speakers. */
-               { .dac2port         = 0x24,
-                 .has_hda_gpio     = false,
-                 .mmio_gpio_count  = 1,
-                 .mmio_gpio_pin    = { 1 },
-                 .mmio_gpio_set    = { 1 },
-                 .scp_cmds_count   = 0,
-                 .has_chipio_write = false,
-               },
-               /* Headphones. */
-               { .dac2port         = 0x21,
-                 .has_hda_gpio     = false,
-                 .mmio_gpio_count  = 1,
-                 .mmio_gpio_pin    = { 1 },
-                 .mmio_gpio_set    = { 0 },
-                 .scp_cmds_count   = 0,
-                 .has_chipio_write = false,
-               } },
-       },
-       { .quirk_id = QUIRK_SBZ,
-         .has_headphone_gain = false,
-         .is_ae_series       = false,
-         .out_set_info = {
-               /* Speakers. */
-               { .dac2port         = 0x18,
-                 .has_hda_gpio     = false,
-                 .mmio_gpio_count  = 3,
-                 .mmio_gpio_pin    = { 7, 4, 1 },
-                 .mmio_gpio_set    = { 0, 1, 1 },
-                 .scp_cmds_count   = 0,
-                 .has_chipio_write = false, },
-               /* Headphones. */
-               { .dac2port         = 0x12,
-                 .has_hda_gpio     = false,
-                 .mmio_gpio_count  = 3,
-                 .mmio_gpio_pin    = { 7, 4, 1 },
-                 .mmio_gpio_set    = { 1, 1, 0 },
-                 .scp_cmds_count   = 0,
-                 .has_chipio_write = false,
-               } },
-       },
-       { .quirk_id = QUIRK_ZXR,
-         .has_headphone_gain = true,
-         .is_ae_series       = false,
-         .out_set_info = {
-               /* Speakers. */
-               { .dac2port         = 0x24,
-                 .has_hda_gpio     = false,
-                 .mmio_gpio_count  = 3,
-                 .mmio_gpio_pin    = { 2, 3, 5 },
-                 .mmio_gpio_set    = { 1, 1, 0 },
-                 .scp_cmds_count   = 0,
-                 .has_chipio_write = false,
-               },
-               /* Headphones. */
-               { .dac2port         = 0x21,
-                 .has_hda_gpio     = false,
-                 .mmio_gpio_count  = 3,
-                 .mmio_gpio_pin    = { 2, 3, 5 },
-                 .mmio_gpio_set    = { 0, 1, 1 },
-                 .scp_cmds_count   = 0,
-                 .has_chipio_write = false,
-               } },
-       },
-       { .quirk_id = QUIRK_AE5,
-         .has_headphone_gain = true,
-         .is_ae_series       = true,
-         .out_set_info = {
-               /* Speakers. */
-               { .dac2port          = 0xa4,
-                 .has_hda_gpio      = false,
-                 .mmio_gpio_count   = 0,
-                 .scp_cmds_count    = 2,
-                 .scp_cmd_mid       = { 0x96, 0x96 },
-                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
-                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
-                 .scp_cmd_val       = { FLOAT_ZERO, FLOAT_ZERO },
-                 .has_chipio_write  = true,
-                 .chipio_write_addr = 0x0018b03c,
-                 .chipio_write_data = 0x00000012
-               },
-               /* Headphones. */
-               { .dac2port          = 0xa1,
-                 .has_hda_gpio      = false,
-                 .mmio_gpio_count   = 0,
-                 .scp_cmds_count    = 2,
-                 .scp_cmd_mid       = { 0x96, 0x96 },
-                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
-                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
-                 .scp_cmd_val       = { FLOAT_ONE, FLOAT_ONE },
-                 .has_chipio_write  = true,
-                 .chipio_write_addr = 0x0018b03c,
-                 .chipio_write_data = 0x00000012
-               } },
-       },
-       { .quirk_id = QUIRK_AE7,
-         .has_headphone_gain = true,
-         .is_ae_series       = true,
-         .out_set_info = {
-               /* Speakers. */
-               { .dac2port          = 0x58,
-                 .has_hda_gpio      = false,
-                 .mmio_gpio_count   = 1,
-                 .mmio_gpio_pin     = { 0 },
-                 .mmio_gpio_set     = { 1 },
-                 .scp_cmds_count    = 2,
-                 .scp_cmd_mid       = { 0x96, 0x96 },
-                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
-                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
-                 .scp_cmd_val       = { FLOAT_ZERO, FLOAT_ZERO },
-                 .has_chipio_write  = true,
-                 .chipio_write_addr = 0x0018b03c,
-                 .chipio_write_data = 0x00000000
-               },
-               /* Headphones. */
-               { .dac2port          = 0x58,
-                 .has_hda_gpio      = false,
-                 .mmio_gpio_count   = 1,
-                 .mmio_gpio_pin     = { 0 },
-                 .mmio_gpio_set     = { 1 },
-                 .scp_cmds_count    = 2,
-                 .scp_cmd_mid       = { 0x96, 0x96 },
-                 .scp_cmd_req       = { SPEAKER_TUNING_FRONT_LEFT_INVERT,
-                                        SPEAKER_TUNING_FRONT_RIGHT_INVERT },
-                 .scp_cmd_val       = { FLOAT_ONE, FLOAT_ONE },
-                 .has_chipio_write  = true,
-                 .chipio_write_addr = 0x0018b03c,
-                 .chipio_write_data = 0x00000010
-               } },
-       }
-};
-
-/*
- * CA0132 codec access
- */
-static unsigned int codec_send_command(struct hda_codec *codec, hda_nid_t nid,
-               unsigned int verb, unsigned int parm, unsigned int *res)
-{
-       unsigned int response;
-       response = snd_hda_codec_read(codec, nid, 0, verb, parm);
-       *res = response;
-
-       return ((response == -1) ? -1 : 0);
-}
-
-static int codec_set_converter_format(struct hda_codec *codec, hda_nid_t nid,
-               unsigned short converter_format, unsigned int *res)
-{
-       return codec_send_command(codec, nid, VENDOR_CHIPIO_STREAM_FORMAT,
-                               converter_format & 0xffff, res);
-}
-
-static int codec_set_converter_stream_channel(struct hda_codec *codec,
-                               hda_nid_t nid, unsigned char stream,
-                               unsigned char channel, unsigned int *res)
-{
-       unsigned char converter_stream_channel = 0;
-
-       converter_stream_channel = (stream << 4) | (channel & 0x0f);
-       return codec_send_command(codec, nid, AC_VERB_SET_CHANNEL_STREAMID,
-                               converter_stream_channel, res);
-}
-
-/* Chip access helper function */
-static int chipio_send(struct hda_codec *codec,
-                      unsigned int reg,
-                      unsigned int data)
-{
-       unsigned int res;
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-       /* send bits of data specified by reg */
-       do {
-               res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
-                                        reg, data);
-               if (res == VENDOR_STATUS_CHIPIO_OK)
-                       return 0;
-               msleep(20);
-       } while (time_before(jiffies, timeout));
-
-       return -EIO;
-}
-
-/*
- * Write chip address through the vendor widget -- NOT protected by the Mutex!
- */
-static int chipio_write_address(struct hda_codec *codec,
-                               unsigned int chip_addx)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int res;
-
-       if (spec->curr_chip_addx == chip_addx)
-                       return 0;
-
-       /* send low 16 bits of the address */
-       res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW,
-                         chip_addx & 0xffff);
-
-       if (res != -EIO) {
-               /* send high 16 bits of the address */
-               res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_HIGH,
-                                 chip_addx >> 16);
-       }
-
-       spec->curr_chip_addx = (res < 0) ? ~0U : chip_addx;
-
-       return res;
-}
-
-/*
- * Write data through the vendor widget -- NOT protected by the Mutex!
- */
-static int chipio_write_data(struct hda_codec *codec, unsigned int data)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int res;
-
-       /* send low 16 bits of the data */
-       res = chipio_send(codec, VENDOR_CHIPIO_DATA_LOW, data & 0xffff);
-
-       if (res != -EIO) {
-               /* send high 16 bits of the data */
-               res = chipio_send(codec, VENDOR_CHIPIO_DATA_HIGH,
-                                 data >> 16);
-       }
-
-       /*If no error encountered, automatically increment the address
-       as per chip behaviour*/
-       spec->curr_chip_addx = (res != -EIO) ?
-                                       (spec->curr_chip_addx + 4) : ~0U;
-       return res;
-}
-
-/*
- * Write multiple data through the vendor widget -- NOT protected by the Mutex!
- */
-static int chipio_write_data_multiple(struct hda_codec *codec,
-                                     const u32 *data,
-                                     unsigned int count)
-{
-       int status = 0;
-
-       if (data == NULL) {
-               codec_dbg(codec, "chipio_write_data null ptr\n");
-               return -EINVAL;
-       }
-
-       while ((count-- != 0) && (status == 0))
-               status = chipio_write_data(codec, *data++);
-
-       return status;
-}
-
-
-/*
- * Read data through the vendor widget -- NOT protected by the Mutex!
- */
-static int chipio_read_data(struct hda_codec *codec, unsigned int *data)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int res;
-
-       /* post read */
-       res = chipio_send(codec, VENDOR_CHIPIO_HIC_POST_READ, 0);
-
-       if (res != -EIO) {
-               /* read status */
-               res = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
-       }
-
-       if (res != -EIO) {
-               /* read data */
-               *data = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
-                                          VENDOR_CHIPIO_HIC_READ_DATA,
-                                          0);
-       }
-
-       /*If no error encountered, automatically increment the address
-       as per chip behaviour*/
-       spec->curr_chip_addx = (res != -EIO) ?
-                                       (spec->curr_chip_addx + 4) : ~0U;
-       return res;
-}
-
-/*
- * Write given value to the given address through the chip I/O widget.
- * protected by the Mutex
- */
-static int chipio_write(struct hda_codec *codec,
-               unsigned int chip_addx, const unsigned int data)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int err;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       /* write the address, and if successful proceed to write data */
-       err = chipio_write_address(codec, chip_addx);
-       if (err < 0)
-               goto exit;
-
-       err = chipio_write_data(codec, data);
-       if (err < 0)
-               goto exit;
-
-exit:
-       mutex_unlock(&spec->chipio_mutex);
-       return err;
-}
-
-/*
- * Write given value to the given address through the chip I/O widget.
- * not protected by the Mutex
- */
-static int chipio_write_no_mutex(struct hda_codec *codec,
-               unsigned int chip_addx, const unsigned int data)
-{
-       int err;
-
-
-       /* write the address, and if successful proceed to write data */
-       err = chipio_write_address(codec, chip_addx);
-       if (err < 0)
-               goto exit;
-
-       err = chipio_write_data(codec, data);
-       if (err < 0)
-               goto exit;
-
-exit:
-       return err;
-}
-
-/*
- * Write multiple values to the given address through the chip I/O widget.
- * protected by the Mutex
- */
-static int chipio_write_multiple(struct hda_codec *codec,
-                                u32 chip_addx,
-                                const u32 *data,
-                                unsigned int count)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int status;
-
-       mutex_lock(&spec->chipio_mutex);
-       status = chipio_write_address(codec, chip_addx);
-       if (status < 0)
-               goto error;
-
-       status = chipio_write_data_multiple(codec, data, count);
-error:
-       mutex_unlock(&spec->chipio_mutex);
-
-       return status;
-}
-
-/*
- * Read the given address through the chip I/O widget
- * protected by the Mutex
- */
-static int chipio_read(struct hda_codec *codec,
-               unsigned int chip_addx, unsigned int *data)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int err;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       /* write the address, and if successful proceed to write data */
-       err = chipio_write_address(codec, chip_addx);
-       if (err < 0)
-               goto exit;
-
-       err = chipio_read_data(codec, data);
-       if (err < 0)
-               goto exit;
-
-exit:
-       mutex_unlock(&spec->chipio_mutex);
-       return err;
-}
-
-/*
- * Set chip control flags through the chip I/O widget.
- */
-static void chipio_set_control_flag(struct hda_codec *codec,
-                                   enum control_flag_id flag_id,
-                                   bool flag_state)
-{
-       unsigned int val;
-       unsigned int flag_bit;
-
-       flag_bit = (flag_state ? 1 : 0);
-       val = (flag_bit << 7) | (flag_id);
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_FLAG_SET, val);
-}
-
-/*
- * Set chip parameters through the chip I/O widget.
- */
-static void chipio_set_control_param(struct hda_codec *codec,
-               enum control_param_id param_id, int param_val)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int val;
-
-       if ((param_id < 32) && (param_val < 8)) {
-               val = (param_val << 5) | (param_id);
-               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                                   VENDOR_CHIPIO_PARAM_SET, val);
-       } else {
-               mutex_lock(&spec->chipio_mutex);
-               if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) {
-                       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                                           VENDOR_CHIPIO_PARAM_EX_ID_SET,
-                                           param_id);
-                       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                                           VENDOR_CHIPIO_PARAM_EX_VALUE_SET,
-                                           param_val);
-               }
-               mutex_unlock(&spec->chipio_mutex);
-       }
-}
-
-/*
- * Set chip parameters through the chip I/O widget. NO MUTEX.
- */
-static void chipio_set_control_param_no_mutex(struct hda_codec *codec,
-               enum control_param_id param_id, int param_val)
-{
-       int val;
-
-       if ((param_id < 32) && (param_val < 8)) {
-               val = (param_val << 5) | (param_id);
-               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                                   VENDOR_CHIPIO_PARAM_SET, val);
-       } else {
-               if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) {
-                       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                                           VENDOR_CHIPIO_PARAM_EX_ID_SET,
-                                           param_id);
-                       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                                           VENDOR_CHIPIO_PARAM_EX_VALUE_SET,
-                                           param_val);
-               }
-       }
-}
-/*
- * Connect stream to a source point, and then connect
- * that source point to a destination point.
- */
-static void chipio_set_stream_source_dest(struct hda_codec *codec,
-                               int streamid, int source_point, int dest_point)
-{
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_STREAM_ID, streamid);
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_STREAM_SOURCE_CONN_POINT, source_point);
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_STREAM_DEST_CONN_POINT, dest_point);
-}
-
-/*
- * Set number of channels in the selected stream.
- */
-static void chipio_set_stream_channels(struct hda_codec *codec,
-                               int streamid, unsigned int channels)
-{
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_STREAM_ID, streamid);
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_STREAMS_CHANNELS, channels);
-}
-
-/*
- * Enable/Disable audio stream.
- */
-static void chipio_set_stream_control(struct hda_codec *codec,
-                               int streamid, int enable)
-{
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_STREAM_ID, streamid);
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_STREAM_CONTROL, enable);
-}
-
-/*
- * Get ChipIO audio stream's status.
- */
-static void chipio_get_stream_control(struct hda_codec *codec,
-                               int streamid, unsigned int *enable)
-{
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_STREAM_ID, streamid);
-       *enable = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
-                          VENDOR_CHIPIO_PARAM_GET,
-                          CONTROL_PARAM_STREAM_CONTROL);
-}
-
-/*
- * Set sampling rate of the connection point. NO MUTEX.
- */
-static void chipio_set_conn_rate_no_mutex(struct hda_codec *codec,
-                               int connid, enum ca0132_sample_rate rate)
-{
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_CONN_POINT_ID, connid);
-       chipio_set_control_param_no_mutex(codec,
-                       CONTROL_PARAM_CONN_POINT_SAMPLE_RATE, rate);
-}
-
-/*
- * Set sampling rate of the connection point.
- */
-static void chipio_set_conn_rate(struct hda_codec *codec,
-                               int connid, enum ca0132_sample_rate rate)
-{
-       chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_ID, connid);
-       chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_SAMPLE_RATE,
-                                rate);
-}
-
-/*
- * Writes to the 8051's internal address space directly instead of indirectly,
- * giving access to the special function registers located at addresses
- * 0x80-0xFF.
- */
-static void chipio_8051_write_direct(struct hda_codec *codec,
-               unsigned int addr, unsigned int data)
-{
-       unsigned int verb;
-
-       verb = VENDOR_CHIPIO_8051_WRITE_DIRECT | data;
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, verb, addr);
-}
-
-/*
- * Writes to the 8051's exram, which has 16-bits of address space.
- * Data at addresses 0x2000-0x7fff is mirrored to 0x8000-0xdfff.
- * Data at 0x8000-0xdfff can also be used as program memory for the 8051 by
- * setting the pmem bank selection SFR.
- * 0xe000-0xffff is always mapped as program memory, with only 0xf000-0xffff
- * being writable.
- */
-static void chipio_8051_set_address(struct hda_codec *codec, unsigned int addr)
-{
-       unsigned int tmp;
-
-       /* Lower 8-bits. */
-       tmp = addr & 0xff;
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_8051_ADDRESS_LOW, tmp);
-
-       /* Upper 8-bits. */
-       tmp = (addr >> 8) & 0xff;
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_8051_ADDRESS_HIGH, tmp);
-}
-
-static void chipio_8051_set_data(struct hda_codec *codec, unsigned int data)
-{
-       /* 8-bits of data. */
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_8051_DATA_WRITE, data & 0xff);
-}
-
-static unsigned int chipio_8051_get_data(struct hda_codec *codec)
-{
-       return snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
-                                  VENDOR_CHIPIO_8051_DATA_READ, 0);
-}
-
-/* PLL_PMU writes share the lower address register of the 8051 exram writes. */
-static void chipio_8051_set_data_pll(struct hda_codec *codec, unsigned int data)
-{
-       /* 8-bits of data. */
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_PLL_PMU_WRITE, data & 0xff);
-}
-
-static void chipio_8051_write_exram(struct hda_codec *codec,
-               unsigned int addr, unsigned int data)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       chipio_8051_set_address(codec, addr);
-       chipio_8051_set_data(codec, data);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-static void chipio_8051_write_exram_no_mutex(struct hda_codec *codec,
-               unsigned int addr, unsigned int data)
-{
-       chipio_8051_set_address(codec, addr);
-       chipio_8051_set_data(codec, data);
-}
-
-/* Readback data from the 8051's exram. No mutex. */
-static void chipio_8051_read_exram(struct hda_codec *codec,
-               unsigned int addr, unsigned int *data)
-{
-       chipio_8051_set_address(codec, addr);
-       *data = chipio_8051_get_data(codec);
-}
-
-static void chipio_8051_write_pll_pmu(struct hda_codec *codec,
-               unsigned int addr, unsigned int data)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       chipio_8051_set_address(codec, addr & 0xff);
-       chipio_8051_set_data_pll(codec, data);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-static void chipio_8051_write_pll_pmu_no_mutex(struct hda_codec *codec,
-               unsigned int addr, unsigned int data)
-{
-       chipio_8051_set_address(codec, addr & 0xff);
-       chipio_8051_set_data_pll(codec, data);
-}
-
-/*
- * Enable clocks.
- */
-static void chipio_enable_clocks(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       chipio_8051_write_pll_pmu_no_mutex(codec, 0x00, 0xff);
-       chipio_8051_write_pll_pmu_no_mutex(codec, 0x05, 0x0b);
-       chipio_8051_write_pll_pmu_no_mutex(codec, 0x06, 0xff);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-/*
- * CA0132 DSP IO stuffs
- */
-static int dspio_send(struct hda_codec *codec, unsigned int reg,
-                     unsigned int data)
-{
-       int res;
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-       /* send bits of data specified by reg to dsp */
-       do {
-               res = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, reg, data);
-               if ((res >= 0) && (res != VENDOR_STATUS_DSPIO_BUSY))
-                       return res;
-               msleep(20);
-       } while (time_before(jiffies, timeout));
-
-       return -EIO;
-}
-
-/*
- * Wait for DSP to be ready for commands
- */
-static void dspio_write_wait(struct hda_codec *codec)
-{
-       int status;
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-
-       do {
-               status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
-                                               VENDOR_DSPIO_STATUS, 0);
-               if ((status == VENDOR_STATUS_DSPIO_OK) ||
-                   (status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY))
-                       break;
-               msleep(1);
-       } while (time_before(jiffies, timeout));
-}
-
-/*
- * Write SCP data to DSP
- */
-static int dspio_write(struct hda_codec *codec, unsigned int scp_data)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int status;
-
-       dspio_write_wait(codec);
-
-       mutex_lock(&spec->chipio_mutex);
-       status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_LOW,
-                           scp_data & 0xffff);
-       if (status < 0)
-               goto error;
-
-       status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_HIGH,
-                                   scp_data >> 16);
-       if (status < 0)
-               goto error;
-
-       /* OK, now check if the write itself has executed*/
-       status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
-                                   VENDOR_DSPIO_STATUS, 0);
-error:
-       mutex_unlock(&spec->chipio_mutex);
-
-       return (status == VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL) ?
-                       -EIO : 0;
-}
-
-/*
- * Write multiple SCP data to DSP
- */
-static int dspio_write_multiple(struct hda_codec *codec,
-                               unsigned int *buffer, unsigned int size)
-{
-       int status = 0;
-       unsigned int count;
-
-       if (buffer == NULL)
-               return -EINVAL;
-
-       count = 0;
-       while (count < size) {
-               status = dspio_write(codec, *buffer++);
-               if (status != 0)
-                       break;
-               count++;
-       }
-
-       return status;
-}
-
-static int dspio_read(struct hda_codec *codec, unsigned int *data)
-{
-       int status;
-
-       status = dspio_send(codec, VENDOR_DSPIO_SCP_POST_READ_DATA, 0);
-       if (status == -EIO)
-               return status;
-
-       status = dspio_send(codec, VENDOR_DSPIO_STATUS, 0);
-       if (status == -EIO ||
-           status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY)
-               return -EIO;
-
-       *data = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0,
-                                  VENDOR_DSPIO_SCP_READ_DATA, 0);
-
-       return 0;
-}
-
-static int dspio_read_multiple(struct hda_codec *codec, unsigned int *buffer,
-                              unsigned int *buf_size, unsigned int size_count)
-{
-       int status = 0;
-       unsigned int size = *buf_size;
-       unsigned int count;
-       unsigned int skip_count;
-       unsigned int dummy;
-
-       if (buffer == NULL)
-               return -1;
-
-       count = 0;
-       while (count < size && count < size_count) {
-               status = dspio_read(codec, buffer++);
-               if (status != 0)
-                       break;
-               count++;
-       }
-
-       skip_count = count;
-       if (status == 0) {
-               while (skip_count < size) {
-                       status = dspio_read(codec, &dummy);
-                       if (status != 0)
-                               break;
-                       skip_count++;
-               }
-       }
-       *buf_size = count;
-
-       return status;
-}
-
-/*
- * Construct the SCP header using corresponding fields
- */
-static inline unsigned int
-make_scp_header(unsigned int target_id, unsigned int source_id,
-               unsigned int get_flag, unsigned int req,
-               unsigned int device_flag, unsigned int resp_flag,
-               unsigned int error_flag, unsigned int data_size)
-{
-       unsigned int header = 0;
-
-       header = (data_size & 0x1f) << 27;
-       header |= (error_flag & 0x01) << 26;
-       header |= (resp_flag & 0x01) << 25;
-       header |= (device_flag & 0x01) << 24;
-       header |= (req & 0x7f) << 17;
-       header |= (get_flag & 0x01) << 16;
-       header |= (source_id & 0xff) << 8;
-       header |= target_id & 0xff;
-
-       return header;
-}
-
-/*
- * Extract corresponding fields from SCP header
- */
-static inline void
-extract_scp_header(unsigned int header,
-                  unsigned int *target_id, unsigned int *source_id,
-                  unsigned int *get_flag, unsigned int *req,
-                  unsigned int *device_flag, unsigned int *resp_flag,
-                  unsigned int *error_flag, unsigned int *data_size)
-{
-       if (data_size)
-               *data_size = (header >> 27) & 0x1f;
-       if (error_flag)
-               *error_flag = (header >> 26) & 0x01;
-       if (resp_flag)
-               *resp_flag = (header >> 25) & 0x01;
-       if (device_flag)
-               *device_flag = (header >> 24) & 0x01;
-       if (req)
-               *req = (header >> 17) & 0x7f;
-       if (get_flag)
-               *get_flag = (header >> 16) & 0x01;
-       if (source_id)
-               *source_id = (header >> 8) & 0xff;
-       if (target_id)
-               *target_id = header & 0xff;
-}
-
-#define SCP_MAX_DATA_WORDS  (16)
-
-/* Structure to contain any SCP message */
-struct scp_msg {
-       unsigned int hdr;
-       unsigned int data[SCP_MAX_DATA_WORDS];
-};
-
-static void dspio_clear_response_queue(struct hda_codec *codec)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-       unsigned int dummy = 0;
-       int status;
-
-       /* clear all from the response queue */
-       do {
-               status = dspio_read(codec, &dummy);
-       } while (status == 0 && time_before(jiffies, timeout));
-}
-
-static int dspio_get_response_data(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int data = 0;
-       unsigned int count;
-
-       if (dspio_read(codec, &data) < 0)
-               return -EIO;
-
-       if ((data & 0x00ffffff) == spec->wait_scp_header) {
-               spec->scp_resp_header = data;
-               spec->scp_resp_count = data >> 27;
-               count = spec->wait_num_data;
-               dspio_read_multiple(codec, spec->scp_resp_data,
-                                   &spec->scp_resp_count, count);
-               return 0;
-       }
-
-       return -EIO;
-}
-
-/*
- * Send SCP message to DSP
- */
-static int dspio_send_scp_message(struct hda_codec *codec,
-                                 unsigned char *send_buf,
-                                 unsigned int send_buf_size,
-                                 unsigned char *return_buf,
-                                 unsigned int return_buf_size,
-                                 unsigned int *bytes_returned)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int status;
-       unsigned int scp_send_size = 0;
-       unsigned int total_size;
-       bool waiting_for_resp = false;
-       unsigned int header;
-       struct scp_msg *ret_msg;
-       unsigned int resp_src_id, resp_target_id;
-       unsigned int data_size, src_id, target_id, get_flag, device_flag;
-
-       if (bytes_returned)
-               *bytes_returned = 0;
-
-       /* get scp header from buffer */
-       header = *((unsigned int *)send_buf);
-       extract_scp_header(header, &target_id, &src_id, &get_flag, NULL,
-                          &device_flag, NULL, NULL, &data_size);
-       scp_send_size = data_size + 1;
-       total_size = (scp_send_size * 4);
-
-       if (send_buf_size < total_size)
-               return -EINVAL;
-
-       if (get_flag || device_flag) {
-               if (!return_buf || return_buf_size < 4 || !bytes_returned)
-                       return -EINVAL;
-
-               spec->wait_scp_header = *((unsigned int *)send_buf);
-
-               /* swap source id with target id */
-               resp_target_id = src_id;
-               resp_src_id = target_id;
-               spec->wait_scp_header &= 0xffff0000;
-               spec->wait_scp_header |= (resp_src_id << 8) | (resp_target_id);
-               spec->wait_num_data = return_buf_size/sizeof(unsigned int) - 1;
-               spec->wait_scp = 1;
-               waiting_for_resp = true;
-       }
-
-       status = dspio_write_multiple(codec, (unsigned int *)send_buf,
-                                     scp_send_size);
-       if (status < 0) {
-               spec->wait_scp = 0;
-               return status;
-       }
-
-       if (waiting_for_resp) {
-               unsigned long timeout = jiffies + msecs_to_jiffies(1000);
-               memset(return_buf, 0, return_buf_size);
-               do {
-                       msleep(20);
-               } while (spec->wait_scp && time_before(jiffies, timeout));
-               waiting_for_resp = false;
-               if (!spec->wait_scp) {
-                       ret_msg = (struct scp_msg *)return_buf;
-                       memcpy(&ret_msg->hdr, &spec->scp_resp_header, 4);
-                       memcpy(&ret_msg->data, spec->scp_resp_data,
-                              spec->wait_num_data);
-                       *bytes_returned = (spec->scp_resp_count + 1) * 4;
-                       status = 0;
-               } else {
-                       status = -EIO;
-               }
-               spec->wait_scp = 0;
-       }
-
-       return status;
-}
-
-/**
- * dspio_scp - Prepare and send the SCP message to DSP
- * @codec: the HDA codec
- * @mod_id: ID of the DSP module to send the command
- * @src_id: ID of the source
- * @req: ID of request to send to the DSP module
- * @dir: SET or GET
- * @data: pointer to the data to send with the request, request specific
- * @len: length of the data, in bytes
- * @reply: point to the buffer to hold data returned for a reply
- * @reply_len: length of the reply buffer returned from GET
- *
- * Returns zero or a negative error code.
- */
-static int dspio_scp(struct hda_codec *codec,
-               int mod_id, int src_id, int req, int dir, const void *data,
-               unsigned int len, void *reply, unsigned int *reply_len)
-{
-       int status = 0;
-       struct scp_msg scp_send, scp_reply;
-       unsigned int ret_bytes, send_size, ret_size;
-       unsigned int send_get_flag, reply_resp_flag, reply_error_flag;
-       unsigned int reply_data_size;
-
-       memset(&scp_send, 0, sizeof(scp_send));
-       memset(&scp_reply, 0, sizeof(scp_reply));
-
-       if ((len != 0 && data == NULL) || (len > SCP_MAX_DATA_WORDS))
-               return -EINVAL;
-
-       if (dir == SCP_GET && reply == NULL) {
-               codec_dbg(codec, "dspio_scp get but has no buffer\n");
-               return -EINVAL;
-       }
-
-       if (reply != NULL && (reply_len == NULL || (*reply_len == 0))) {
-               codec_dbg(codec, "dspio_scp bad resp buf len parms\n");
-               return -EINVAL;
-       }
-
-       scp_send.hdr = make_scp_header(mod_id, src_id, (dir == SCP_GET), req,
-                                      0, 0, 0, len/sizeof(unsigned int));
-       if (data != NULL && len > 0) {
-               len = min((unsigned int)(sizeof(scp_send.data)), len);
-               memcpy(scp_send.data, data, len);
-       }
-
-       ret_bytes = 0;
-       send_size = sizeof(unsigned int) + len;
-       status = dspio_send_scp_message(codec, (unsigned char *)&scp_send,
-                                       send_size, (unsigned char *)&scp_reply,
-                                       sizeof(scp_reply), &ret_bytes);
-
-       if (status < 0) {
-               codec_dbg(codec, "dspio_scp: send scp msg failed\n");
-               return status;
-       }
-
-       /* extract send and reply headers members */
-       extract_scp_header(scp_send.hdr, NULL, NULL, &send_get_flag,
-                          NULL, NULL, NULL, NULL, NULL);
-       extract_scp_header(scp_reply.hdr, NULL, NULL, NULL, NULL, NULL,
-                          &reply_resp_flag, &reply_error_flag,
-                          &reply_data_size);
-
-       if (!send_get_flag)
-               return 0;
-
-       if (reply_resp_flag && !reply_error_flag) {
-               ret_size = (ret_bytes - sizeof(scp_reply.hdr))
-                                       / sizeof(unsigned int);
-
-               if (*reply_len < ret_size*sizeof(unsigned int)) {
-                       codec_dbg(codec, "reply too long for buf\n");
-                       return -EINVAL;
-               } else if (ret_size != reply_data_size) {
-                       codec_dbg(codec, "RetLen and HdrLen .NE.\n");
-                       return -EINVAL;
-               } else if (!reply) {
-                       codec_dbg(codec, "NULL reply\n");
-                       return -EINVAL;
-               } else {
-                       *reply_len = ret_size*sizeof(unsigned int);
-                       memcpy(reply, scp_reply.data, *reply_len);
-               }
-       } else {
-               codec_dbg(codec, "reply ill-formed or errflag set\n");
-               return -EIO;
-       }
-
-       return status;
-}
-
-/*
- * Set DSP parameters
- */
-static int dspio_set_param(struct hda_codec *codec, int mod_id,
-                       int src_id, int req, const void *data, unsigned int len)
-{
-       return dspio_scp(codec, mod_id, src_id, req, SCP_SET, data, len, NULL,
-                       NULL);
-}
-
-static int dspio_set_uint_param(struct hda_codec *codec, int mod_id,
-                       int req, const unsigned int data)
-{
-       return dspio_set_param(codec, mod_id, 0x20, req, &data,
-                       sizeof(unsigned int));
-}
-
-/*
- * Allocate a DSP DMA channel via an SCP message
- */
-static int dspio_alloc_dma_chan(struct hda_codec *codec, unsigned int *dma_chan)
-{
-       int status = 0;
-       unsigned int size = sizeof(*dma_chan);
-
-       codec_dbg(codec, "     dspio_alloc_dma_chan() -- begin\n");
-       status = dspio_scp(codec, MASTERCONTROL, 0x20,
-                       MASTERCONTROL_ALLOC_DMA_CHAN, SCP_GET, NULL, 0,
-                       dma_chan, &size);
-
-       if (status < 0) {
-               codec_dbg(codec, "dspio_alloc_dma_chan: SCP Failed\n");
-               return status;
-       }
-
-       if ((*dma_chan + 1) == 0) {
-               codec_dbg(codec, "no free dma channels to allocate\n");
-               return -EBUSY;
-       }
-
-       codec_dbg(codec, "dspio_alloc_dma_chan: chan=%d\n", *dma_chan);
-       codec_dbg(codec, "     dspio_alloc_dma_chan() -- complete\n");
-
-       return status;
-}
-
-/*
- * Free a DSP DMA via an SCP message
- */
-static int dspio_free_dma_chan(struct hda_codec *codec, unsigned int dma_chan)
-{
-       int status = 0;
-       unsigned int dummy = 0;
-
-       codec_dbg(codec, "     dspio_free_dma_chan() -- begin\n");
-       codec_dbg(codec, "dspio_free_dma_chan: chan=%d\n", dma_chan);
-
-       status = dspio_scp(codec, MASTERCONTROL, 0x20,
-                       MASTERCONTROL_ALLOC_DMA_CHAN, SCP_SET, &dma_chan,
-                       sizeof(dma_chan), NULL, &dummy);
-
-       if (status < 0) {
-               codec_dbg(codec, "dspio_free_dma_chan: SCP Failed\n");
-               return status;
-       }
-
-       codec_dbg(codec, "     dspio_free_dma_chan() -- complete\n");
-
-       return status;
-}
-
-/*
- * (Re)start the DSP
- */
-static int dsp_set_run_state(struct hda_codec *codec)
-{
-       unsigned int dbg_ctrl_reg;
-       unsigned int halt_state;
-       int err;
-
-       err = chipio_read(codec, DSP_DBGCNTL_INST_OFFSET, &dbg_ctrl_reg);
-       if (err < 0)
-               return err;
-
-       halt_state = (dbg_ctrl_reg & DSP_DBGCNTL_STATE_MASK) >>
-                     DSP_DBGCNTL_STATE_LOBIT;
-
-       if (halt_state != 0) {
-               dbg_ctrl_reg &= ~((halt_state << DSP_DBGCNTL_SS_LOBIT) &
-                                 DSP_DBGCNTL_SS_MASK);
-               err = chipio_write(codec, DSP_DBGCNTL_INST_OFFSET,
-                                  dbg_ctrl_reg);
-               if (err < 0)
-                       return err;
-
-               dbg_ctrl_reg |= (halt_state << DSP_DBGCNTL_EXEC_LOBIT) &
-                               DSP_DBGCNTL_EXEC_MASK;
-               err = chipio_write(codec, DSP_DBGCNTL_INST_OFFSET,
-                                  dbg_ctrl_reg);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-/*
- * Reset the DSP
- */
-static int dsp_reset(struct hda_codec *codec)
-{
-       unsigned int res;
-       int retry = 20;
-
-       codec_dbg(codec, "dsp_reset\n");
-       do {
-               res = dspio_send(codec, VENDOR_DSPIO_DSP_INIT, 0);
-               retry--;
-       } while (res == -EIO && retry);
-
-       if (!retry) {
-               codec_dbg(codec, "dsp_reset timeout\n");
-               return -EIO;
-       }
-
-       return 0;
-}
-
-/*
- * Convert chip address to DSP address
- */
-static unsigned int dsp_chip_to_dsp_addx(unsigned int chip_addx,
-                                       bool *code, bool *yram)
-{
-       *code = *yram = false;
-
-       if (UC_RANGE(chip_addx, 1)) {
-               *code = true;
-               return UC_OFF(chip_addx);
-       } else if (X_RANGE_ALL(chip_addx, 1)) {
-               return X_OFF(chip_addx);
-       } else if (Y_RANGE_ALL(chip_addx, 1)) {
-               *yram = true;
-               return Y_OFF(chip_addx);
-       }
-
-       return INVALID_CHIP_ADDRESS;
-}
-
-/*
- * Check if the DSP DMA is active
- */
-static bool dsp_is_dma_active(struct hda_codec *codec, unsigned int dma_chan)
-{
-       unsigned int dma_chnlstart_reg;
-
-       chipio_read(codec, DSPDMAC_CHNLSTART_INST_OFFSET, &dma_chnlstart_reg);
-
-       return ((dma_chnlstart_reg & (1 <<
-                       (DSPDMAC_CHNLSTART_EN_LOBIT + dma_chan))) != 0);
-}
-
-static int dsp_dma_setup_common(struct hda_codec *codec,
-                               unsigned int chip_addx,
-                               unsigned int dma_chan,
-                               unsigned int port_map_mask,
-                               bool ovly)
-{
-       int status = 0;
-       unsigned int chnl_prop;
-       unsigned int dsp_addx;
-       unsigned int active;
-       bool code, yram;
-
-       codec_dbg(codec, "-- dsp_dma_setup_common() -- Begin ---------\n");
-
-       if (dma_chan >= DSPDMAC_DMA_CFG_CHANNEL_COUNT) {
-               codec_dbg(codec, "dma chan num invalid\n");
-               return -EINVAL;
-       }
-
-       if (dsp_is_dma_active(codec, dma_chan)) {
-               codec_dbg(codec, "dma already active\n");
-               return -EBUSY;
-       }
-
-       dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram);
-
-       if (dsp_addx == INVALID_CHIP_ADDRESS) {
-               codec_dbg(codec, "invalid chip addr\n");
-               return -ENXIO;
-       }
-
-       chnl_prop = DSPDMAC_CHNLPROP_AC_MASK;
-       active = 0;
-
-       codec_dbg(codec, "   dsp_dma_setup_common()    start reg pgm\n");
-
-       if (ovly) {
-               status = chipio_read(codec, DSPDMAC_CHNLPROP_INST_OFFSET,
-                                    &chnl_prop);
-
-               if (status < 0) {
-                       codec_dbg(codec, "read CHNLPROP Reg fail\n");
-                       return status;
-               }
-               codec_dbg(codec, "dsp_dma_setup_common() Read CHNLPROP\n");
-       }
-
-       if (!code)
-               chnl_prop &= ~(1 << (DSPDMAC_CHNLPROP_MSPCE_LOBIT + dma_chan));
-       else
-               chnl_prop |=  (1 << (DSPDMAC_CHNLPROP_MSPCE_LOBIT + dma_chan));
-
-       chnl_prop &= ~(1 << (DSPDMAC_CHNLPROP_DCON_LOBIT + dma_chan));
-
-       status = chipio_write(codec, DSPDMAC_CHNLPROP_INST_OFFSET, chnl_prop);
-       if (status < 0) {
-               codec_dbg(codec, "write CHNLPROP Reg fail\n");
-               return status;
-       }
-       codec_dbg(codec, "   dsp_dma_setup_common()    Write CHNLPROP\n");
-
-       if (ovly) {
-               status = chipio_read(codec, DSPDMAC_ACTIVE_INST_OFFSET,
-                                    &active);
-
-               if (status < 0) {
-                       codec_dbg(codec, "read ACTIVE Reg fail\n");
-                       return status;
-               }
-               codec_dbg(codec, "dsp_dma_setup_common() Read ACTIVE\n");
-       }
-
-       active &= (~(1 << (DSPDMAC_ACTIVE_AAR_LOBIT + dma_chan))) &
-               DSPDMAC_ACTIVE_AAR_MASK;
-
-       status = chipio_write(codec, DSPDMAC_ACTIVE_INST_OFFSET, active);
-       if (status < 0) {
-               codec_dbg(codec, "write ACTIVE Reg fail\n");
-               return status;
-       }
-
-       codec_dbg(codec, "   dsp_dma_setup_common()    Write ACTIVE\n");
-
-       status = chipio_write(codec, DSPDMAC_AUDCHSEL_INST_OFFSET(dma_chan),
-                             port_map_mask);
-       if (status < 0) {
-               codec_dbg(codec, "write AUDCHSEL Reg fail\n");
-               return status;
-       }
-       codec_dbg(codec, "   dsp_dma_setup_common()    Write AUDCHSEL\n");
-
-       status = chipio_write(codec, DSPDMAC_IRQCNT_INST_OFFSET(dma_chan),
-                       DSPDMAC_IRQCNT_BICNT_MASK | DSPDMAC_IRQCNT_CICNT_MASK);
-       if (status < 0) {
-               codec_dbg(codec, "write IRQCNT Reg fail\n");
-               return status;
-       }
-       codec_dbg(codec, "   dsp_dma_setup_common()    Write IRQCNT\n");
-
-       codec_dbg(codec,
-                  "ChipA=0x%x,DspA=0x%x,dmaCh=%u, "
-                  "CHSEL=0x%x,CHPROP=0x%x,Active=0x%x\n",
-                  chip_addx, dsp_addx, dma_chan,
-                  port_map_mask, chnl_prop, active);
-
-       codec_dbg(codec, "-- dsp_dma_setup_common() -- Complete ------\n");
-
-       return 0;
-}
-
-/*
- * Setup the DSP DMA per-transfer-specific registers
- */
-static int dsp_dma_setup(struct hda_codec *codec,
-                       unsigned int chip_addx,
-                       unsigned int count,
-                       unsigned int dma_chan)
-{
-       int status = 0;
-       bool code, yram;
-       unsigned int dsp_addx;
-       unsigned int addr_field;
-       unsigned int incr_field;
-       unsigned int base_cnt;
-       unsigned int cur_cnt;
-       unsigned int dma_cfg = 0;
-       unsigned int adr_ofs = 0;
-       unsigned int xfr_cnt = 0;
-       const unsigned int max_dma_count = 1 << (DSPDMAC_XFRCNT_BCNT_HIBIT -
-                                               DSPDMAC_XFRCNT_BCNT_LOBIT + 1);
-
-       codec_dbg(codec, "-- dsp_dma_setup() -- Begin ---------\n");
-
-       if (count > max_dma_count) {
-               codec_dbg(codec, "count too big\n");
-               return -EINVAL;
-       }
-
-       dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram);
-       if (dsp_addx == INVALID_CHIP_ADDRESS) {
-               codec_dbg(codec, "invalid chip addr\n");
-               return -ENXIO;
-       }
-
-       codec_dbg(codec, "   dsp_dma_setup()    start reg pgm\n");
-
-       addr_field = dsp_addx << DSPDMAC_DMACFG_DBADR_LOBIT;
-       incr_field   = 0;
-
-       if (!code) {
-               addr_field <<= 1;
-               if (yram)
-                       addr_field |= (1 << DSPDMAC_DMACFG_DBADR_LOBIT);
-
-               incr_field  = (1 << DSPDMAC_DMACFG_AINCR_LOBIT);
-       }
-
-       dma_cfg = addr_field + incr_field;
-       status = chipio_write(codec, DSPDMAC_DMACFG_INST_OFFSET(dma_chan),
-                               dma_cfg);
-       if (status < 0) {
-               codec_dbg(codec, "write DMACFG Reg fail\n");
-               return status;
-       }
-       codec_dbg(codec, "   dsp_dma_setup()    Write DMACFG\n");
-
-       adr_ofs = (count - 1) << (DSPDMAC_DSPADROFS_BOFS_LOBIT +
-                                                       (code ? 0 : 1));
-
-       status = chipio_write(codec, DSPDMAC_DSPADROFS_INST_OFFSET(dma_chan),
-                               adr_ofs);
-       if (status < 0) {
-               codec_dbg(codec, "write DSPADROFS Reg fail\n");
-               return status;
-       }
-       codec_dbg(codec, "   dsp_dma_setup()    Write DSPADROFS\n");
-
-       base_cnt = (count - 1) << DSPDMAC_XFRCNT_BCNT_LOBIT;
-
-       cur_cnt  = (count - 1) << DSPDMAC_XFRCNT_CCNT_LOBIT;
-
-       xfr_cnt = base_cnt | cur_cnt;
-
-       status = chipio_write(codec,
-                               DSPDMAC_XFRCNT_INST_OFFSET(dma_chan), xfr_cnt);
-       if (status < 0) {
-               codec_dbg(codec, "write XFRCNT Reg fail\n");
-               return status;
-       }
-       codec_dbg(codec, "   dsp_dma_setup()    Write XFRCNT\n");
-
-       codec_dbg(codec,
-                  "ChipA=0x%x, cnt=0x%x, DMACFG=0x%x, "
-                  "ADROFS=0x%x, XFRCNT=0x%x\n",
-                  chip_addx, count, dma_cfg, adr_ofs, xfr_cnt);
-
-       codec_dbg(codec, "-- dsp_dma_setup() -- Complete ---------\n");
-
-       return 0;
-}
-
-/*
- * Start the DSP DMA
- */
-static int dsp_dma_start(struct hda_codec *codec,
-                        unsigned int dma_chan, bool ovly)
-{
-       unsigned int reg = 0;
-       int status = 0;
-
-       codec_dbg(codec, "-- dsp_dma_start() -- Begin ---------\n");
-
-       if (ovly) {
-               status = chipio_read(codec,
-                                    DSPDMAC_CHNLSTART_INST_OFFSET, &reg);
-
-               if (status < 0) {
-                       codec_dbg(codec, "read CHNLSTART reg fail\n");
-                       return status;
-               }
-               codec_dbg(codec, "-- dsp_dma_start()    Read CHNLSTART\n");
-
-               reg &= ~(DSPDMAC_CHNLSTART_EN_MASK |
-                               DSPDMAC_CHNLSTART_DIS_MASK);
-       }
-
-       status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET,
-                       reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_EN_LOBIT)));
-       if (status < 0) {
-               codec_dbg(codec, "write CHNLSTART reg fail\n");
-               return status;
-       }
-       codec_dbg(codec, "-- dsp_dma_start() -- Complete ---------\n");
-
-       return status;
-}
-
-/*
- * Stop the DSP DMA
- */
-static int dsp_dma_stop(struct hda_codec *codec,
-                       unsigned int dma_chan, bool ovly)
-{
-       unsigned int reg = 0;
-       int status = 0;
-
-       codec_dbg(codec, "-- dsp_dma_stop() -- Begin ---------\n");
-
-       if (ovly) {
-               status = chipio_read(codec,
-                                    DSPDMAC_CHNLSTART_INST_OFFSET, &reg);
-
-               if (status < 0) {
-                       codec_dbg(codec, "read CHNLSTART reg fail\n");
-                       return status;
-               }
-               codec_dbg(codec, "-- dsp_dma_stop()    Read CHNLSTART\n");
-               reg &= ~(DSPDMAC_CHNLSTART_EN_MASK |
-                               DSPDMAC_CHNLSTART_DIS_MASK);
-       }
-
-       status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET,
-                       reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_DIS_LOBIT)));
-       if (status < 0) {
-               codec_dbg(codec, "write CHNLSTART reg fail\n");
-               return status;
-       }
-       codec_dbg(codec, "-- dsp_dma_stop() -- Complete ---------\n");
-
-       return status;
-}
-
-/**
- * dsp_allocate_router_ports - Allocate router ports
- *
- * @codec: the HDA codec
- * @num_chans: number of channels in the stream
- * @ports_per_channel: number of ports per channel
- * @start_device: start device
- * @port_map: pointer to the port list to hold the allocated ports
- *
- * Returns zero or a negative error code.
- */
-static int dsp_allocate_router_ports(struct hda_codec *codec,
-                                    unsigned int num_chans,
-                                    unsigned int ports_per_channel,
-                                    unsigned int start_device,
-                                    unsigned int *port_map)
-{
-       int status = 0;
-       int res;
-       u8 val;
-
-       status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
-       if (status < 0)
-               return status;
-
-       val = start_device << 6;
-       val |= (ports_per_channel - 1) << 4;
-       val |= num_chans - 1;
-
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET,
-                           val);
-
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_PORT_ALLOC_SET,
-                           MEM_CONNID_DSP);
-
-       status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
-       if (status < 0)
-               return status;
-
-       res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0,
-                               VENDOR_CHIPIO_PORT_ALLOC_GET, 0);
-
-       *port_map = res;
-
-       return (res < 0) ? res : 0;
-}
-
-/*
- * Free router ports
- */
-static int dsp_free_router_ports(struct hda_codec *codec)
-{
-       int status = 0;
-
-       status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
-       if (status < 0)
-               return status;
-
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_PORT_FREE_SET,
-                           MEM_CONNID_DSP);
-
-       status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0);
-
-       return status;
-}
-
-/*
- * Allocate DSP ports for the download stream
- */
-static int dsp_allocate_ports(struct hda_codec *codec,
-                       unsigned int num_chans,
-                       unsigned int rate_multi, unsigned int *port_map)
-{
-       int status;
-
-       codec_dbg(codec, "     dsp_allocate_ports() -- begin\n");
-
-       if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) {
-               codec_dbg(codec, "bad rate multiple\n");
-               return -EINVAL;
-       }
-
-       status = dsp_allocate_router_ports(codec, num_chans,
-                                          rate_multi, 0, port_map);
-
-       codec_dbg(codec, "     dsp_allocate_ports() -- complete\n");
-
-       return status;
-}
-
-static int dsp_allocate_ports_format(struct hda_codec *codec,
-                       const unsigned short fmt,
-                       unsigned int *port_map)
-{
-       unsigned int num_chans;
-
-       unsigned int sample_rate_div = ((get_hdafmt_rate(fmt) >> 0) & 3) + 1;
-       unsigned int sample_rate_mul = ((get_hdafmt_rate(fmt) >> 3) & 3) + 1;
-       unsigned int rate_multi = sample_rate_mul / sample_rate_div;
-
-       if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) {
-               codec_dbg(codec, "bad rate multiple\n");
-               return -EINVAL;
-       }
-
-       num_chans = get_hdafmt_chs(fmt) + 1;
-
-       return dsp_allocate_ports(codec, num_chans, rate_multi, port_map);
-}
-
-/*
- * free DSP ports
- */
-static int dsp_free_ports(struct hda_codec *codec)
-{
-       int status;
-
-       codec_dbg(codec, "     dsp_free_ports() -- begin\n");
-
-       status = dsp_free_router_ports(codec);
-       if (status < 0) {
-               codec_dbg(codec, "free router ports fail\n");
-               return status;
-       }
-       codec_dbg(codec, "     dsp_free_ports() -- complete\n");
-
-       return status;
-}
-
-/*
- *  HDA DMA engine stuffs for DSP code download
- */
-struct dma_engine {
-       struct hda_codec *codec;
-       unsigned short m_converter_format;
-       struct snd_dma_buffer *dmab;
-       unsigned int buf_size;
-};
-
-
-enum dma_state {
-       DMA_STATE_STOP  = 0,
-       DMA_STATE_RUN   = 1
-};
-
-static int dma_convert_to_hda_format(struct hda_codec *codec,
-               unsigned int sample_rate,
-               unsigned short channels,
-               unsigned short *hda_format)
-{
-       unsigned int format_val;
-
-       format_val = snd_hdac_stream_format(channels, 32, sample_rate);
-
-       if (hda_format)
-               *hda_format = (unsigned short)format_val;
-
-       return 0;
-}
-
-/*
- *  Reset DMA for DSP download
- */
-static int dma_reset(struct dma_engine *dma)
-{
-       struct hda_codec *codec = dma->codec;
-       struct ca0132_spec *spec = codec->spec;
-       int status;
-
-       if (dma->dmab->area)
-               snd_hda_codec_load_dsp_cleanup(codec, dma->dmab);
-
-       status = snd_hda_codec_load_dsp_prepare(codec,
-                       dma->m_converter_format,
-                       dma->buf_size,
-                       dma->dmab);
-       if (status < 0)
-               return status;
-       spec->dsp_stream_id = status;
-       return 0;
-}
-
-static int dma_set_state(struct dma_engine *dma, enum dma_state state)
-{
-       bool cmd;
-
-       switch (state) {
-       case DMA_STATE_STOP:
-               cmd = false;
-               break;
-       case DMA_STATE_RUN:
-               cmd = true;
-               break;
-       default:
-               return 0;
-       }
-
-       snd_hda_codec_load_dsp_trigger(dma->codec, cmd);
-       return 0;
-}
-
-static unsigned int dma_get_buffer_size(struct dma_engine *dma)
-{
-       return dma->dmab->bytes;
-}
-
-static unsigned char *dma_get_buffer_addr(struct dma_engine *dma)
-{
-       return dma->dmab->area;
-}
-
-static int dma_xfer(struct dma_engine *dma,
-               const unsigned int *data,
-               unsigned int count)
-{
-       memcpy(dma->dmab->area, data, count);
-       return 0;
-}
-
-static void dma_get_converter_format(
-               struct dma_engine *dma,
-               unsigned short *format)
-{
-       if (format)
-               *format = dma->m_converter_format;
-}
-
-static unsigned int dma_get_stream_id(struct dma_engine *dma)
-{
-       struct ca0132_spec *spec = dma->codec->spec;
-
-       return spec->dsp_stream_id;
-}
-
-struct dsp_image_seg {
-       u32 magic;
-       u32 chip_addr;
-       u32 count;
-       u32 data[];
-};
-
-static const u32 g_magic_value = 0x4c46584d;
-static const u32 g_chip_addr_magic_value = 0xFFFFFF01;
-
-static bool is_valid(const struct dsp_image_seg *p)
-{
-       return p->magic == g_magic_value;
-}
-
-static bool is_hci_prog_list_seg(const struct dsp_image_seg *p)
-{
-       return g_chip_addr_magic_value == p->chip_addr;
-}
-
-static bool is_last(const struct dsp_image_seg *p)
-{
-       return p->count == 0;
-}
-
-static size_t dsp_sizeof(const struct dsp_image_seg *p)
-{
-       return struct_size(p, data, p->count);
-}
-
-static const struct dsp_image_seg *get_next_seg_ptr(
-                               const struct dsp_image_seg *p)
-{
-       return (struct dsp_image_seg *)((unsigned char *)(p) + dsp_sizeof(p));
-}
-
-/*
- * CA0132 chip DSP transfer stuffs.  For DSP download.
- */
-#define INVALID_DMA_CHANNEL (~0U)
-
-/*
- * Program a list of address/data pairs via the ChipIO widget.
- * The segment data is in the format of successive pairs of words.
- * These are repeated as indicated by the segment's count field.
- */
-static int dspxfr_hci_write(struct hda_codec *codec,
-                       const struct dsp_image_seg *fls)
-{
-       int status;
-       const u32 *data;
-       unsigned int count;
-
-       if (fls == NULL || fls->chip_addr != g_chip_addr_magic_value) {
-               codec_dbg(codec, "hci_write invalid params\n");
-               return -EINVAL;
-       }
-
-       count = fls->count;
-       data = (u32 *)(fls->data);
-       while (count >= 2) {
-               status = chipio_write(codec, data[0], data[1]);
-               if (status < 0) {
-                       codec_dbg(codec, "hci_write chipio failed\n");
-                       return status;
-               }
-               count -= 2;
-               data  += 2;
-       }
-       return 0;
-}
-
-/**
- * dspxfr_one_seg - Write a block of data into DSP code or data RAM using pre-allocated DMA engine.
- *
- * @codec: the HDA codec
- * @fls: pointer to a fast load image
- * @reloc: Relocation address for loading single-segment overlays, or 0 for
- *        no relocation
- * @dma_engine: pointer to DMA engine to be used for DSP download
- * @dma_chan: The number of DMA channels used for DSP download
- * @port_map_mask: port mapping
- * @ovly: TRUE if overlay format is required
- *
- * Returns zero or a negative error code.
- */
-static int dspxfr_one_seg(struct hda_codec *codec,
-                       const struct dsp_image_seg *fls,
-                       unsigned int reloc,
-                       struct dma_engine *dma_engine,
-                       unsigned int dma_chan,
-                       unsigned int port_map_mask,
-                       bool ovly)
-{
-       int status = 0;
-       bool comm_dma_setup_done = false;
-       const unsigned int *data;
-       unsigned int chip_addx;
-       unsigned int words_to_write;
-       unsigned int buffer_size_words;
-       unsigned char *buffer_addx;
-       unsigned short hda_format;
-       unsigned int sample_rate_div;
-       unsigned int sample_rate_mul;
-       unsigned int num_chans;
-       unsigned int hda_frame_size_words;
-       unsigned int remainder_words;
-       const u32 *data_remainder;
-       u32 chip_addx_remainder;
-       unsigned int run_size_words;
-       const struct dsp_image_seg *hci_write = NULL;
-       unsigned long timeout;
-       bool dma_active;
-
-       if (fls == NULL)
-               return -EINVAL;
-       if (is_hci_prog_list_seg(fls)) {
-               hci_write = fls;
-               fls = get_next_seg_ptr(fls);
-       }
-
-       if (hci_write && (!fls || is_last(fls))) {
-               codec_dbg(codec, "hci_write\n");
-               return dspxfr_hci_write(codec, hci_write);
-       }
-
-       if (fls == NULL || dma_engine == NULL || port_map_mask == 0) {
-               codec_dbg(codec, "Invalid Params\n");
-               return -EINVAL;
-       }
-
-       data = fls->data;
-       chip_addx = fls->chip_addr;
-       words_to_write = fls->count;
-
-       if (!words_to_write)
-               return hci_write ? dspxfr_hci_write(codec, hci_write) : 0;
-       if (reloc)
-               chip_addx = (chip_addx & (0xFFFF0000 << 2)) + (reloc << 2);
-
-       if (!UC_RANGE(chip_addx, words_to_write) &&
-           !X_RANGE_ALL(chip_addx, words_to_write) &&
-           !Y_RANGE_ALL(chip_addx, words_to_write)) {
-               codec_dbg(codec, "Invalid chip_addx Params\n");
-               return -EINVAL;
-       }
-
-       buffer_size_words = (unsigned int)dma_get_buffer_size(dma_engine) /
-                                       sizeof(u32);
-
-       buffer_addx = dma_get_buffer_addr(dma_engine);
-
-       if (buffer_addx == NULL) {
-               codec_dbg(codec, "dma_engine buffer NULL\n");
-               return -EINVAL;
-       }
-
-       dma_get_converter_format(dma_engine, &hda_format);
-       sample_rate_div = ((get_hdafmt_rate(hda_format) >> 0) & 3) + 1;
-       sample_rate_mul = ((get_hdafmt_rate(hda_format) >> 3) & 3) + 1;
-       num_chans = get_hdafmt_chs(hda_format) + 1;
-
-       hda_frame_size_words = ((sample_rate_div == 0) ? 0 :
-                       (num_chans * sample_rate_mul / sample_rate_div));
-
-       if (hda_frame_size_words == 0) {
-               codec_dbg(codec, "frmsz zero\n");
-               return -EINVAL;
-       }
-
-       buffer_size_words = min(buffer_size_words,
-                               (unsigned int)(UC_RANGE(chip_addx, 1) ?
-                               65536 : 32768));
-       buffer_size_words -= buffer_size_words % hda_frame_size_words;
-       codec_dbg(codec,
-                  "chpadr=0x%08x frmsz=%u nchan=%u "
-                  "rate_mul=%u div=%u bufsz=%u\n",
-                  chip_addx, hda_frame_size_words, num_chans,
-                  sample_rate_mul, sample_rate_div, buffer_size_words);
-
-       if (buffer_size_words < hda_frame_size_words) {
-               codec_dbg(codec, "dspxfr_one_seg:failed\n");
-               return -EINVAL;
-       }
-
-       remainder_words = words_to_write % hda_frame_size_words;
-       data_remainder = data;
-       chip_addx_remainder = chip_addx;
-
-       data += remainder_words;
-       chip_addx += remainder_words*sizeof(u32);
-       words_to_write -= remainder_words;
-
-       while (words_to_write != 0) {
-               run_size_words = min(buffer_size_words, words_to_write);
-               codec_dbg(codec, "dspxfr (seg loop)cnt=%u rs=%u remainder=%u\n",
-                           words_to_write, run_size_words, remainder_words);
-               dma_xfer(dma_engine, data, run_size_words*sizeof(u32));
-               if (!comm_dma_setup_done) {
-                       status = dsp_dma_stop(codec, dma_chan, ovly);
-                       if (status < 0)
-                               return status;
-                       status = dsp_dma_setup_common(codec, chip_addx,
-                                               dma_chan, port_map_mask, ovly);
-                       if (status < 0)
-                               return status;
-                       comm_dma_setup_done = true;
-               }
-
-               status = dsp_dma_setup(codec, chip_addx,
-                                               run_size_words, dma_chan);
-               if (status < 0)
-                       return status;
-               status = dsp_dma_start(codec, dma_chan, ovly);
-               if (status < 0)
-                       return status;
-               if (!dsp_is_dma_active(codec, dma_chan)) {
-                       codec_dbg(codec, "dspxfr:DMA did not start\n");
-                       return -EIO;
-               }
-               status = dma_set_state(dma_engine, DMA_STATE_RUN);
-               if (status < 0)
-                       return status;
-               if (remainder_words != 0) {
-                       status = chipio_write_multiple(codec,
-                                               chip_addx_remainder,
-                                               data_remainder,
-                                               remainder_words);
-                       if (status < 0)
-                               return status;
-                       remainder_words = 0;
-               }
-               if (hci_write) {
-                       status = dspxfr_hci_write(codec, hci_write);
-                       if (status < 0)
-                               return status;
-                       hci_write = NULL;
-               }
-
-               timeout = jiffies + msecs_to_jiffies(2000);
-               do {
-                       dma_active = dsp_is_dma_active(codec, dma_chan);
-                       if (!dma_active)
-                               break;
-                       msleep(20);
-               } while (time_before(jiffies, timeout));
-               if (dma_active)
-                       break;
-
-               codec_dbg(codec, "+++++ DMA complete\n");
-               dma_set_state(dma_engine, DMA_STATE_STOP);
-               status = dma_reset(dma_engine);
-
-               if (status < 0)
-                       return status;
-
-               data += run_size_words;
-               chip_addx += run_size_words*sizeof(u32);
-               words_to_write -= run_size_words;
-       }
-
-       if (remainder_words != 0) {
-               status = chipio_write_multiple(codec, chip_addx_remainder,
-                                       data_remainder, remainder_words);
-       }
-
-       return status;
-}
-
-/**
- * dspxfr_image - Write the entire DSP image of a DSP code/data overlay to DSP memories
- *
- * @codec: the HDA codec
- * @fls_data: pointer to a fast load image
- * @reloc: Relocation address for loading single-segment overlays, or 0 for
- *        no relocation
- * @sample_rate: sampling rate of the stream used for DSP download
- * @channels: channels of the stream used for DSP download
- * @ovly: TRUE if overlay format is required
- *
- * Returns zero or a negative error code.
- */
-static int dspxfr_image(struct hda_codec *codec,
-                       const struct dsp_image_seg *fls_data,
-                       unsigned int reloc,
-                       unsigned int sample_rate,
-                       unsigned short channels,
-                       bool ovly)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int status;
-       unsigned short hda_format = 0;
-       unsigned int response;
-       unsigned char stream_id = 0;
-       struct dma_engine *dma_engine;
-       unsigned int dma_chan;
-       unsigned int port_map_mask;
-
-       if (fls_data == NULL)
-               return -EINVAL;
-
-       dma_engine = kzalloc(sizeof(*dma_engine), GFP_KERNEL);
-       if (!dma_engine)
-               return -ENOMEM;
-
-       dma_engine->dmab = kzalloc(sizeof(*dma_engine->dmab), GFP_KERNEL);
-       if (!dma_engine->dmab) {
-               kfree(dma_engine);
-               return -ENOMEM;
-       }
-
-       dma_engine->codec = codec;
-       dma_convert_to_hda_format(codec, sample_rate, channels, &hda_format);
-       dma_engine->m_converter_format = hda_format;
-       dma_engine->buf_size = (ovly ? DSP_DMA_WRITE_BUFLEN_OVLY :
-                       DSP_DMA_WRITE_BUFLEN_INIT) * 2;
-
-       dma_chan = ovly ? INVALID_DMA_CHANNEL : 0;
-
-       status = codec_set_converter_format(codec, WIDGET_CHIP_CTRL,
-                                       hda_format, &response);
-
-       if (status < 0) {
-               codec_dbg(codec, "set converter format fail\n");
-               goto exit;
-       }
-
-       status = snd_hda_codec_load_dsp_prepare(codec,
-                               dma_engine->m_converter_format,
-                               dma_engine->buf_size,
-                               dma_engine->dmab);
-       if (status < 0)
-               goto exit;
-       spec->dsp_stream_id = status;
-
-       if (ovly) {
-               status = dspio_alloc_dma_chan(codec, &dma_chan);
-               if (status < 0) {
-                       codec_dbg(codec, "alloc dmachan fail\n");
-                       dma_chan = INVALID_DMA_CHANNEL;
-                       goto exit;
-               }
-       }
-
-       port_map_mask = 0;
-       status = dsp_allocate_ports_format(codec, hda_format,
-                                       &port_map_mask);
-       if (status < 0) {
-               codec_dbg(codec, "alloc ports fail\n");
-               goto exit;
-       }
-
-       stream_id = dma_get_stream_id(dma_engine);
-       status = codec_set_converter_stream_channel(codec,
-                       WIDGET_CHIP_CTRL, stream_id, 0, &response);
-       if (status < 0) {
-               codec_dbg(codec, "set stream chan fail\n");
-               goto exit;
-       }
-
-       while ((fls_data != NULL) && !is_last(fls_data)) {
-               if (!is_valid(fls_data)) {
-                       codec_dbg(codec, "FLS check fail\n");
-                       status = -EINVAL;
-                       goto exit;
-               }
-               status = dspxfr_one_seg(codec, fls_data, reloc,
-                                       dma_engine, dma_chan,
-                                       port_map_mask, ovly);
-               if (status < 0)
-                       break;
-
-               if (is_hci_prog_list_seg(fls_data))
-                       fls_data = get_next_seg_ptr(fls_data);
-
-               if ((fls_data != NULL) && !is_last(fls_data))
-                       fls_data = get_next_seg_ptr(fls_data);
-       }
-
-       if (port_map_mask != 0)
-               status = dsp_free_ports(codec);
-
-       if (status < 0)
-               goto exit;
-
-       status = codec_set_converter_stream_channel(codec,
-                               WIDGET_CHIP_CTRL, 0, 0, &response);
-
-exit:
-       if (ovly && (dma_chan != INVALID_DMA_CHANNEL))
-               dspio_free_dma_chan(codec, dma_chan);
-
-       if (dma_engine->dmab->area)
-               snd_hda_codec_load_dsp_cleanup(codec, dma_engine->dmab);
-       kfree(dma_engine->dmab);
-       kfree(dma_engine);
-
-       return status;
-}
-
-/*
- * CA0132 DSP download stuffs.
- */
-static void dspload_post_setup(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       codec_dbg(codec, "---- dspload_post_setup ------\n");
-       if (!ca0132_use_alt_functions(spec)) {
-               /*set DSP speaker to 2.0 configuration*/
-               chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080);
-               chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x19), 0x3f800000);
-
-               /*update write pointer*/
-               chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x29), 0x00000002);
-       }
-}
-
-/**
- * dspload_image - Download DSP from a DSP Image Fast Load structure.
- *
- * @codec: the HDA codec
- * @fls: pointer to a fast load image
- * @ovly: TRUE if overlay format is required
- * @reloc: Relocation address for loading single-segment overlays, or 0 for
- *        no relocation
- * @autostart: TRUE if DSP starts after loading; ignored if ovly is TRUE
- * @router_chans: number of audio router channels to be allocated (0 means use
- *               internal defaults; max is 32)
- *
- * Download DSP from a DSP Image Fast Load structure. This structure is a
- * linear, non-constant sized element array of structures, each of which
- * contain the count of the data to be loaded, the data itself, and the
- * corresponding starting chip address of the starting data location.
- * Returns zero or a negative error code.
- */
-static int dspload_image(struct hda_codec *codec,
-                       const struct dsp_image_seg *fls,
-                       bool ovly,
-                       unsigned int reloc,
-                       bool autostart,
-                       int router_chans)
-{
-       int status = 0;
-       unsigned int sample_rate;
-       unsigned short channels;
-
-       codec_dbg(codec, "---- dspload_image begin ------\n");
-       if (router_chans == 0) {
-               if (!ovly)
-                       router_chans = DMA_TRANSFER_FRAME_SIZE_NWORDS;
-               else
-                       router_chans = DMA_OVERLAY_FRAME_SIZE_NWORDS;
-       }
-
-       sample_rate = 48000;
-       channels = (unsigned short)router_chans;
-
-       while (channels > 16) {
-               sample_rate *= 2;
-               channels /= 2;
-       }
-
-       do {
-               codec_dbg(codec, "Ready to program DMA\n");
-               if (!ovly)
-                       status = dsp_reset(codec);
-
-               if (status < 0)
-                       break;
-
-               codec_dbg(codec, "dsp_reset() complete\n");
-               status = dspxfr_image(codec, fls, reloc, sample_rate, channels,
-                                     ovly);
-
-               if (status < 0)
-                       break;
-
-               codec_dbg(codec, "dspxfr_image() complete\n");
-               if (autostart && !ovly) {
-                       dspload_post_setup(codec);
-                       status = dsp_set_run_state(codec);
-               }
-
-               codec_dbg(codec, "LOAD FINISHED\n");
-       } while (0);
-
-       return status;
-}
-
-#ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP
-static bool dspload_is_loaded(struct hda_codec *codec)
-{
-       unsigned int data = 0;
-       int status = 0;
-
-       status = chipio_read(codec, 0x40004, &data);
-       if ((status < 0) || (data != 1))
-               return false;
-
-       return true;
-}
-#else
-#define dspload_is_loaded(codec)       false
-#endif
-
-static bool dspload_wait_loaded(struct hda_codec *codec)
-{
-       unsigned long timeout = jiffies + msecs_to_jiffies(2000);
-
-       do {
-               if (dspload_is_loaded(codec)) {
-                       codec_info(codec, "ca0132 DSP downloaded and running\n");
-                       return true;
-               }
-               msleep(20);
-       } while (time_before(jiffies, timeout));
-
-       codec_err(codec, "ca0132 failed to download DSP\n");
-       return false;
-}
-
-/*
- * ca0113 related functions. The ca0113 acts as the HDA bus for the pci-e
- * based cards, and has a second mmio region, region2, that's used for special
- * commands.
- */
-
-/*
- * For cards with PCI-E region2 (Sound Blaster Z/ZxR, Recon3D, and AE-5)
- * the mmio address 0x320 is used to set GPIO pins. The format for the data
- * The first eight bits are just the number of the pin. So far, I've only seen
- * this number go to 7.
- * AE-5 note: The AE-5 seems to use pins 2 and 3 to somehow set the color value
- * of the on-card LED. It seems to use pin 2 for data, then toggles 3 to on and
- * then off to send that bit.
- */
-static void ca0113_mmio_gpio_set(struct hda_codec *codec, unsigned int gpio_pin,
-               bool enable)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned short gpio_data;
-
-       gpio_data = gpio_pin & 0xF;
-       gpio_data |= ((enable << 8) & 0x100);
-
-       writew(gpio_data, spec->mem_base + 0x320);
-}
-
-/*
- * Special pci region2 commands that are only used by the AE-5. They follow
- * a set format, and require reads at certain points to seemingly 'clear'
- * the response data. My first tests didn't do these reads, and would cause
- * the card to get locked up until the memory was read. These commands
- * seem to work with three distinct values that I've taken to calling group,
- * target-id, and value.
- */
-static void ca0113_mmio_command_set(struct hda_codec *codec, unsigned int group,
-               unsigned int target, unsigned int value)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int write_val;
-
-       writel(0x0000007e, spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-       writel(0x0000005a, spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-
-       writel(0x00800005, spec->mem_base + 0x20c);
-       writel(group, spec->mem_base + 0x804);
-
-       writel(0x00800005, spec->mem_base + 0x20c);
-       write_val = (target & 0xff);
-       write_val |= (value << 8);
-
-
-       writel(write_val, spec->mem_base + 0x204);
-       /*
-        * Need delay here or else it goes too fast and works inconsistently.
-        */
-       msleep(20);
-
-       readl(spec->mem_base + 0x860);
-       readl(spec->mem_base + 0x854);
-       readl(spec->mem_base + 0x840);
-
-       writel(0x00800004, spec->mem_base + 0x20c);
-       writel(0x00000000, spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-}
-
-/*
- * This second type of command is used for setting the sound filter type.
- */
-static void ca0113_mmio_command_set_type2(struct hda_codec *codec,
-               unsigned int group, unsigned int target, unsigned int value)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int write_val;
-
-       writel(0x0000007e, spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-       writel(0x0000005a, spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-
-       writel(0x00800003, spec->mem_base + 0x20c);
-       writel(group, spec->mem_base + 0x804);
-
-       writel(0x00800005, spec->mem_base + 0x20c);
-       write_val = (target & 0xff);
-       write_val |= (value << 8);
-
-
-       writel(write_val, spec->mem_base + 0x204);
-       msleep(20);
-       readl(spec->mem_base + 0x860);
-       readl(spec->mem_base + 0x854);
-       readl(spec->mem_base + 0x840);
-
-       writel(0x00800004, spec->mem_base + 0x20c);
-       writel(0x00000000, spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-       readl(spec->mem_base + 0x210);
-}
-
-/*
- * Setup GPIO for the other variants of Core3D.
- */
-
-/*
- * Sets up the GPIO pins so that they are discoverable. If this isn't done,
- * the card shows as having no GPIO pins.
- */
-static void ca0132_gpio_init(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-       case QUIRK_AE5:
-       case QUIRK_AE7:
-               snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
-               snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
-               snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23);
-               break;
-       case QUIRK_R3DI:
-               snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
-               snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5B);
-               break;
-       default:
-               break;
-       }
-
-}
-
-/* Sets the GPIO for audio output. */
-static void ca0132_gpio_setup(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_DIRECTION, 0x07);
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_MASK, 0x07);
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_DATA, 0x04);
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_DATA, 0x06);
-               break;
-       case QUIRK_R3DI:
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_DIRECTION, 0x1E);
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_MASK, 0x1F);
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_DATA, 0x0C);
-               break;
-       default:
-               break;
-       }
-}
-
-/*
- * GPIO control functions for the Recon3D integrated.
- */
-
-enum r3di_gpio_bit {
-       /* Bit 1 - Switch between front/rear mic. 0 = rear, 1 = front */
-       R3DI_MIC_SELECT_BIT = 1,
-       /* Bit 2 - Switch between headphone/line out. 0 = Headphone, 1 = Line */
-       R3DI_OUT_SELECT_BIT = 2,
-       /*
-        * I dunno what this actually does, but it stays on until the dsp
-        * is downloaded.
-        */
-       R3DI_GPIO_DSP_DOWNLOADING = 3,
-       /*
-        * Same as above, no clue what it does, but it comes on after the dsp
-        * is downloaded.
-        */
-       R3DI_GPIO_DSP_DOWNLOADED = 4
-};
-
-enum r3di_mic_select {
-       /* Set GPIO bit 1 to 0 for rear mic */
-       R3DI_REAR_MIC = 0,
-       /* Set GPIO bit 1 to 1 for front microphone*/
-       R3DI_FRONT_MIC = 1
-};
-
-enum r3di_out_select {
-       /* Set GPIO bit 2 to 0 for headphone */
-       R3DI_HEADPHONE_OUT = 0,
-       /* Set GPIO bit 2 to 1 for speaker */
-       R3DI_LINE_OUT = 1
-};
-enum r3di_dsp_status {
-       /* Set GPIO bit 3 to 1 until DSP is downloaded */
-       R3DI_DSP_DOWNLOADING = 0,
-       /* Set GPIO bit 4 to 1 once DSP is downloaded */
-       R3DI_DSP_DOWNLOADED = 1
-};
-
-
-static void r3di_gpio_mic_set(struct hda_codec *codec,
-               enum r3di_mic_select cur_mic)
-{
-       unsigned int cur_gpio;
-
-       /* Get the current GPIO Data setup */
-       cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0);
-
-       switch (cur_mic) {
-       case R3DI_REAR_MIC:
-               cur_gpio &= ~(1 << R3DI_MIC_SELECT_BIT);
-               break;
-       case R3DI_FRONT_MIC:
-               cur_gpio |= (1 << R3DI_MIC_SELECT_BIT);
-               break;
-       }
-       snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_GPIO_DATA, cur_gpio);
-}
-
-static void r3di_gpio_dsp_status_set(struct hda_codec *codec,
-               enum r3di_dsp_status dsp_status)
-{
-       unsigned int cur_gpio;
-
-       /* Get the current GPIO Data setup */
-       cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0);
-
-       switch (dsp_status) {
-       case R3DI_DSP_DOWNLOADING:
-               cur_gpio |= (1 << R3DI_GPIO_DSP_DOWNLOADING);
-               snd_hda_codec_write(codec, codec->core.afg, 0,
-                               AC_VERB_SET_GPIO_DATA, cur_gpio);
-               break;
-       case R3DI_DSP_DOWNLOADED:
-               /* Set DOWNLOADING bit to 0. */
-               cur_gpio &= ~(1 << R3DI_GPIO_DSP_DOWNLOADING);
-
-               snd_hda_codec_write(codec, codec->core.afg, 0,
-                               AC_VERB_SET_GPIO_DATA, cur_gpio);
-
-               cur_gpio |= (1 << R3DI_GPIO_DSP_DOWNLOADED);
-               break;
-       }
-
-       snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_GPIO_DATA, cur_gpio);
-}
-
-/*
- * PCM callbacks
- */
-static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       unsigned int stream_tag,
-                       unsigned int format,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format);
-
-       return 0;
-}
-
-static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       if (spec->dsp_state == DSP_DOWNLOADING)
-               return 0;
-
-       /*If Playback effects are on, allow stream some time to flush
-        *effects tail*/
-       if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
-               msleep(50);
-
-       snd_hda_codec_cleanup_stream(codec, spec->dacs[0]);
-
-       return 0;
-}
-
-static unsigned int ca0132_playback_pcm_delay(struct hda_pcm_stream *info,
-                       struct hda_codec *codec,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int latency = DSP_PLAYBACK_INIT_LATENCY;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return 0;
-
-       /* Add latency if playback enhancement and either effect is enabled. */
-       if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) {
-               if ((spec->effects_switch[SURROUND - EFFECT_START_NID]) ||
-                   (spec->effects_switch[DIALOG_PLUS - EFFECT_START_NID]))
-                       latency += DSP_PLAY_ENHANCEMENT_LATENCY;
-       }
-
-       /* Applying Speaker EQ adds latency as well. */
-       if (spec->cur_out_type == SPEAKER_OUT)
-               latency += DSP_SPEAKER_OUT_LATENCY;
-
-       return (latency * runtime->rate) / 1000;
-}
-
-/*
- * Digital out
- */
-static int ca0132_dig_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int ca0132_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       unsigned int stream_tag,
-                       unsigned int format,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
-                                            stream_tag, format, substream);
-}
-
-static int ca0132_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout);
-}
-
-static int ca0132_dig_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                        struct hda_codec *codec,
-                                        struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-/*
- * Analog capture
- */
-static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                       struct hda_codec *codec,
-                                       unsigned int stream_tag,
-                                       unsigned int format,
-                                       struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_setup_stream(codec, hinfo->nid,
-                                  stream_tag, 0, format);
-
-       return 0;
-}
-
-static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                       struct hda_codec *codec,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       if (spec->dsp_state == DSP_DOWNLOADING)
-               return 0;
-
-       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
-       return 0;
-}
-
-static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info,
-                       struct hda_codec *codec,
-                       struct snd_pcm_substream *substream)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int latency = DSP_CAPTURE_INIT_LATENCY;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return 0;
-
-       if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID])
-               latency += DSP_CRYSTAL_VOICE_LATENCY;
-
-       return (latency * runtime->rate) / 1000;
-}
-
-/*
- * Controls stuffs.
- */
-
-/*
- * Mixer controls helpers.
- */
-#define CA0132_CODEC_VOL_MONO(xname, nid, channel, dir) \
-       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-         .name = xname, \
-         .subdevice = HDA_SUBDEV_AMP_FLAG, \
-         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
-                       SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
-                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
-         .info = ca0132_volume_info, \
-         .get = ca0132_volume_get, \
-         .put = ca0132_volume_put, \
-         .tlv = { .c = ca0132_volume_tlv }, \
-         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
-
-/*
- * Creates a mixer control that uses defaults of HDA_CODEC_VOL except for the
- * volume put, which is used for setting the DSP volume. This was done because
- * the ca0132 functions were taking too much time and causing lag.
- */
-#define CA0132_ALT_CODEC_VOL_MONO(xname, nid, channel, dir) \
-       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-         .name = xname, \
-         .subdevice = HDA_SUBDEV_AMP_FLAG, \
-         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
-                       SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
-                       SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \
-         .info = snd_hda_mixer_amp_volume_info, \
-         .get = snd_hda_mixer_amp_volume_get, \
-         .put = ca0132_alt_volume_put, \
-         .tlv = { .c = snd_hda_mixer_amp_tlv }, \
-         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
-
-#define CA0132_CODEC_MUTE_MONO(xname, nid, channel, dir) \
-       { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-         .name = xname, \
-         .subdevice = HDA_SUBDEV_AMP_FLAG, \
-         .info = snd_hda_mixer_amp_switch_info, \
-         .get = ca0132_switch_get, \
-         .put = ca0132_switch_put, \
-         .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
-
-/* stereo */
-#define CA0132_CODEC_VOL(xname, nid, dir) \
-       CA0132_CODEC_VOL_MONO(xname, nid, 3, dir)
-#define CA0132_ALT_CODEC_VOL(xname, nid, dir) \
-       CA0132_ALT_CODEC_VOL_MONO(xname, nid, 3, dir)
-#define CA0132_CODEC_MUTE(xname, nid, dir) \
-       CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir)
-
-/* lookup tables */
-/*
- * Lookup table with decibel values for the DSP. When volume is changed in
- * Windows, the DSP is also sent the dB value in floating point. In Windows,
- * these values have decimal points, probably because the Windows driver
- * actually uses floating point. We can't here, so I made a lookup table of
- * values -90 to 9. -90 is the lowest decibel value for both the ADC's and the
- * DAC's, and 9 is the maximum.
- */
-static const unsigned int float_vol_db_lookup[] = {
-0xC2B40000, 0xC2B20000, 0xC2B00000, 0xC2AE0000, 0xC2AC0000, 0xC2AA0000,
-0xC2A80000, 0xC2A60000, 0xC2A40000, 0xC2A20000, 0xC2A00000, 0xC29E0000,
-0xC29C0000, 0xC29A0000, 0xC2980000, 0xC2960000, 0xC2940000, 0xC2920000,
-0xC2900000, 0xC28E0000, 0xC28C0000, 0xC28A0000, 0xC2880000, 0xC2860000,
-0xC2840000, 0xC2820000, 0xC2800000, 0xC27C0000, 0xC2780000, 0xC2740000,
-0xC2700000, 0xC26C0000, 0xC2680000, 0xC2640000, 0xC2600000, 0xC25C0000,
-0xC2580000, 0xC2540000, 0xC2500000, 0xC24C0000, 0xC2480000, 0xC2440000,
-0xC2400000, 0xC23C0000, 0xC2380000, 0xC2340000, 0xC2300000, 0xC22C0000,
-0xC2280000, 0xC2240000, 0xC2200000, 0xC21C0000, 0xC2180000, 0xC2140000,
-0xC2100000, 0xC20C0000, 0xC2080000, 0xC2040000, 0xC2000000, 0xC1F80000,
-0xC1F00000, 0xC1E80000, 0xC1E00000, 0xC1D80000, 0xC1D00000, 0xC1C80000,
-0xC1C00000, 0xC1B80000, 0xC1B00000, 0xC1A80000, 0xC1A00000, 0xC1980000,
-0xC1900000, 0xC1880000, 0xC1800000, 0xC1700000, 0xC1600000, 0xC1500000,
-0xC1400000, 0xC1300000, 0xC1200000, 0xC1100000, 0xC1000000, 0xC0E00000,
-0xC0C00000, 0xC0A00000, 0xC0800000, 0xC0400000, 0xC0000000, 0xBF800000,
-0x00000000, 0x3F800000, 0x40000000, 0x40400000, 0x40800000, 0x40A00000,
-0x40C00000, 0x40E00000, 0x41000000, 0x41100000
-};
-
-/*
- * This table counts from float 0 to 1 in increments of .01, which is
- * useful for a few different sliders.
- */
-static const unsigned int float_zero_to_one_lookup[] = {
-0x00000000, 0x3C23D70A, 0x3CA3D70A, 0x3CF5C28F, 0x3D23D70A, 0x3D4CCCCD,
-0x3D75C28F, 0x3D8F5C29, 0x3DA3D70A, 0x3DB851EC, 0x3DCCCCCD, 0x3DE147AE,
-0x3DF5C28F, 0x3E051EB8, 0x3E0F5C29, 0x3E19999A, 0x3E23D70A, 0x3E2E147B,
-0x3E3851EC, 0x3E428F5C, 0x3E4CCCCD, 0x3E570A3D, 0x3E6147AE, 0x3E6B851F,
-0x3E75C28F, 0x3E800000, 0x3E851EB8, 0x3E8A3D71, 0x3E8F5C29, 0x3E947AE1,
-0x3E99999A, 0x3E9EB852, 0x3EA3D70A, 0x3EA8F5C3, 0x3EAE147B, 0x3EB33333,
-0x3EB851EC, 0x3EBD70A4, 0x3EC28F5C, 0x3EC7AE14, 0x3ECCCCCD, 0x3ED1EB85,
-0x3ED70A3D, 0x3EDC28F6, 0x3EE147AE, 0x3EE66666, 0x3EEB851F, 0x3EF0A3D7,
-0x3EF5C28F, 0x3EFAE148, 0x3F000000, 0x3F028F5C, 0x3F051EB8, 0x3F07AE14,
-0x3F0A3D71, 0x3F0CCCCD, 0x3F0F5C29, 0x3F11EB85, 0x3F147AE1, 0x3F170A3D,
-0x3F19999A, 0x3F1C28F6, 0x3F1EB852, 0x3F2147AE, 0x3F23D70A, 0x3F266666,
-0x3F28F5C3, 0x3F2B851F, 0x3F2E147B, 0x3F30A3D7, 0x3F333333, 0x3F35C28F,
-0x3F3851EC, 0x3F3AE148, 0x3F3D70A4, 0x3F400000, 0x3F428F5C, 0x3F451EB8,
-0x3F47AE14, 0x3F4A3D71, 0x3F4CCCCD, 0x3F4F5C29, 0x3F51EB85, 0x3F547AE1,
-0x3F570A3D, 0x3F59999A, 0x3F5C28F6, 0x3F5EB852, 0x3F6147AE, 0x3F63D70A,
-0x3F666666, 0x3F68F5C3, 0x3F6B851F, 0x3F6E147B, 0x3F70A3D7, 0x3F733333,
-0x3F75C28F, 0x3F7851EC, 0x3F7AE148, 0x3F7D70A4, 0x3F800000
-};
-
-/*
- * This table counts from float 10 to 1000, which is the range of the x-bass
- * crossover slider in Windows.
- */
-static const unsigned int float_xbass_xover_lookup[] = {
-0x41200000, 0x41A00000, 0x41F00000, 0x42200000, 0x42480000, 0x42700000,
-0x428C0000, 0x42A00000, 0x42B40000, 0x42C80000, 0x42DC0000, 0x42F00000,
-0x43020000, 0x430C0000, 0x43160000, 0x43200000, 0x432A0000, 0x43340000,
-0x433E0000, 0x43480000, 0x43520000, 0x435C0000, 0x43660000, 0x43700000,
-0x437A0000, 0x43820000, 0x43870000, 0x438C0000, 0x43910000, 0x43960000,
-0x439B0000, 0x43A00000, 0x43A50000, 0x43AA0000, 0x43AF0000, 0x43B40000,
-0x43B90000, 0x43BE0000, 0x43C30000, 0x43C80000, 0x43CD0000, 0x43D20000,
-0x43D70000, 0x43DC0000, 0x43E10000, 0x43E60000, 0x43EB0000, 0x43F00000,
-0x43F50000, 0x43FA0000, 0x43FF0000, 0x44020000, 0x44048000, 0x44070000,
-0x44098000, 0x440C0000, 0x440E8000, 0x44110000, 0x44138000, 0x44160000,
-0x44188000, 0x441B0000, 0x441D8000, 0x44200000, 0x44228000, 0x44250000,
-0x44278000, 0x442A0000, 0x442C8000, 0x442F0000, 0x44318000, 0x44340000,
-0x44368000, 0x44390000, 0x443B8000, 0x443E0000, 0x44408000, 0x44430000,
-0x44458000, 0x44480000, 0x444A8000, 0x444D0000, 0x444F8000, 0x44520000,
-0x44548000, 0x44570000, 0x44598000, 0x445C0000, 0x445E8000, 0x44610000,
-0x44638000, 0x44660000, 0x44688000, 0x446B0000, 0x446D8000, 0x44700000,
-0x44728000, 0x44750000, 0x44778000, 0x447A0000
-};
-
-/* The following are for tuning of products */
-#ifdef ENABLE_TUNING_CONTROLS
-
-static const unsigned int voice_focus_vals_lookup[] = {
-0x41A00000, 0x41A80000, 0x41B00000, 0x41B80000, 0x41C00000, 0x41C80000,
-0x41D00000, 0x41D80000, 0x41E00000, 0x41E80000, 0x41F00000, 0x41F80000,
-0x42000000, 0x42040000, 0x42080000, 0x420C0000, 0x42100000, 0x42140000,
-0x42180000, 0x421C0000, 0x42200000, 0x42240000, 0x42280000, 0x422C0000,
-0x42300000, 0x42340000, 0x42380000, 0x423C0000, 0x42400000, 0x42440000,
-0x42480000, 0x424C0000, 0x42500000, 0x42540000, 0x42580000, 0x425C0000,
-0x42600000, 0x42640000, 0x42680000, 0x426C0000, 0x42700000, 0x42740000,
-0x42780000, 0x427C0000, 0x42800000, 0x42820000, 0x42840000, 0x42860000,
-0x42880000, 0x428A0000, 0x428C0000, 0x428E0000, 0x42900000, 0x42920000,
-0x42940000, 0x42960000, 0x42980000, 0x429A0000, 0x429C0000, 0x429E0000,
-0x42A00000, 0x42A20000, 0x42A40000, 0x42A60000, 0x42A80000, 0x42AA0000,
-0x42AC0000, 0x42AE0000, 0x42B00000, 0x42B20000, 0x42B40000, 0x42B60000,
-0x42B80000, 0x42BA0000, 0x42BC0000, 0x42BE0000, 0x42C00000, 0x42C20000,
-0x42C40000, 0x42C60000, 0x42C80000, 0x42CA0000, 0x42CC0000, 0x42CE0000,
-0x42D00000, 0x42D20000, 0x42D40000, 0x42D60000, 0x42D80000, 0x42DA0000,
-0x42DC0000, 0x42DE0000, 0x42E00000, 0x42E20000, 0x42E40000, 0x42E60000,
-0x42E80000, 0x42EA0000, 0x42EC0000, 0x42EE0000, 0x42F00000, 0x42F20000,
-0x42F40000, 0x42F60000, 0x42F80000, 0x42FA0000, 0x42FC0000, 0x42FE0000,
-0x43000000, 0x43010000, 0x43020000, 0x43030000, 0x43040000, 0x43050000,
-0x43060000, 0x43070000, 0x43080000, 0x43090000, 0x430A0000, 0x430B0000,
-0x430C0000, 0x430D0000, 0x430E0000, 0x430F0000, 0x43100000, 0x43110000,
-0x43120000, 0x43130000, 0x43140000, 0x43150000, 0x43160000, 0x43170000,
-0x43180000, 0x43190000, 0x431A0000, 0x431B0000, 0x431C0000, 0x431D0000,
-0x431E0000, 0x431F0000, 0x43200000, 0x43210000, 0x43220000, 0x43230000,
-0x43240000, 0x43250000, 0x43260000, 0x43270000, 0x43280000, 0x43290000,
-0x432A0000, 0x432B0000, 0x432C0000, 0x432D0000, 0x432E0000, 0x432F0000,
-0x43300000, 0x43310000, 0x43320000, 0x43330000, 0x43340000
-};
-
-static const unsigned int mic_svm_vals_lookup[] = {
-0x00000000, 0x3C23D70A, 0x3CA3D70A, 0x3CF5C28F, 0x3D23D70A, 0x3D4CCCCD,
-0x3D75C28F, 0x3D8F5C29, 0x3DA3D70A, 0x3DB851EC, 0x3DCCCCCD, 0x3DE147AE,
-0x3DF5C28F, 0x3E051EB8, 0x3E0F5C29, 0x3E19999A, 0x3E23D70A, 0x3E2E147B,
-0x3E3851EC, 0x3E428F5C, 0x3E4CCCCD, 0x3E570A3D, 0x3E6147AE, 0x3E6B851F,
-0x3E75C28F, 0x3E800000, 0x3E851EB8, 0x3E8A3D71, 0x3E8F5C29, 0x3E947AE1,
-0x3E99999A, 0x3E9EB852, 0x3EA3D70A, 0x3EA8F5C3, 0x3EAE147B, 0x3EB33333,
-0x3EB851EC, 0x3EBD70A4, 0x3EC28F5C, 0x3EC7AE14, 0x3ECCCCCD, 0x3ED1EB85,
-0x3ED70A3D, 0x3EDC28F6, 0x3EE147AE, 0x3EE66666, 0x3EEB851F, 0x3EF0A3D7,
-0x3EF5C28F, 0x3EFAE148, 0x3F000000, 0x3F028F5C, 0x3F051EB8, 0x3F07AE14,
-0x3F0A3D71, 0x3F0CCCCD, 0x3F0F5C29, 0x3F11EB85, 0x3F147AE1, 0x3F170A3D,
-0x3F19999A, 0x3F1C28F6, 0x3F1EB852, 0x3F2147AE, 0x3F23D70A, 0x3F266666,
-0x3F28F5C3, 0x3F2B851F, 0x3F2E147B, 0x3F30A3D7, 0x3F333333, 0x3F35C28F,
-0x3F3851EC, 0x3F3AE148, 0x3F3D70A4, 0x3F400000, 0x3F428F5C, 0x3F451EB8,
-0x3F47AE14, 0x3F4A3D71, 0x3F4CCCCD, 0x3F4F5C29, 0x3F51EB85, 0x3F547AE1,
-0x3F570A3D, 0x3F59999A, 0x3F5C28F6, 0x3F5EB852, 0x3F6147AE, 0x3F63D70A,
-0x3F666666, 0x3F68F5C3, 0x3F6B851F, 0x3F6E147B, 0x3F70A3D7, 0x3F733333,
-0x3F75C28F, 0x3F7851EC, 0x3F7AE148, 0x3F7D70A4, 0x3F800000
-};
-
-static const unsigned int equalizer_vals_lookup[] = {
-0xC1C00000, 0xC1B80000, 0xC1B00000, 0xC1A80000, 0xC1A00000, 0xC1980000,
-0xC1900000, 0xC1880000, 0xC1800000, 0xC1700000, 0xC1600000, 0xC1500000,
-0xC1400000, 0xC1300000, 0xC1200000, 0xC1100000, 0xC1000000, 0xC0E00000,
-0xC0C00000, 0xC0A00000, 0xC0800000, 0xC0400000, 0xC0000000, 0xBF800000,
-0x00000000, 0x3F800000, 0x40000000, 0x40400000, 0x40800000, 0x40A00000,
-0x40C00000, 0x40E00000, 0x41000000, 0x41100000, 0x41200000, 0x41300000,
-0x41400000, 0x41500000, 0x41600000, 0x41700000, 0x41800000, 0x41880000,
-0x41900000, 0x41980000, 0x41A00000, 0x41A80000, 0x41B00000, 0x41B80000,
-0x41C00000
-};
-
-static int tuning_ctl_set(struct hda_codec *codec, hda_nid_t nid,
-                         const unsigned int *lookup, int idx)
-{
-       int i = 0;
-
-       for (i = 0; i < TUNING_CTLS_COUNT; i++)
-               if (nid == ca0132_tuning_ctls[i].nid)
-                       goto found;
-
-       return -EINVAL;
-found:
-       snd_hda_power_up(codec);
-       dspio_set_param(codec, ca0132_tuning_ctls[i].mid, 0x20,
-                       ca0132_tuning_ctls[i].req,
-                       &(lookup[idx]), sizeof(unsigned int));
-       snd_hda_power_down(codec);
-
-       return 1;
-}
-
-static int tuning_ctl_get(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int idx = nid - TUNING_CTL_START_NID;
-
-       *valp = spec->cur_ctl_vals[idx];
-       return 0;
-}
-
-static int voice_focus_ctl_info(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_info *uinfo)
-{
-       int chs = get_amp_channels(kcontrol);
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = chs == 3 ? 2 : 1;
-       uinfo->value.integer.min = 20;
-       uinfo->value.integer.max = 180;
-       uinfo->value.integer.step = 1;
-
-       return 0;
-}
-
-static int voice_focus_ctl_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int idx;
-
-       idx = nid - TUNING_CTL_START_NID;
-       /* any change? */
-       if (spec->cur_ctl_vals[idx] == *valp)
-               return 0;
-
-       spec->cur_ctl_vals[idx] = *valp;
-
-       idx = *valp - 20;
-       tuning_ctl_set(codec, nid, voice_focus_vals_lookup, idx);
-
-       return 1;
-}
-
-static int mic_svm_ctl_info(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_info *uinfo)
-{
-       int chs = get_amp_channels(kcontrol);
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = chs == 3 ? 2 : 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 100;
-       uinfo->value.integer.step = 1;
-
-       return 0;
-}
-
-static int mic_svm_ctl_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int idx;
-
-       idx = nid - TUNING_CTL_START_NID;
-       /* any change? */
-       if (spec->cur_ctl_vals[idx] == *valp)
-               return 0;
-
-       spec->cur_ctl_vals[idx] = *valp;
-
-       idx = *valp;
-       tuning_ctl_set(codec, nid, mic_svm_vals_lookup, idx);
-
-       return 0;
-}
-
-static int equalizer_ctl_info(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_info *uinfo)
-{
-       int chs = get_amp_channels(kcontrol);
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = chs == 3 ? 2 : 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 48;
-       uinfo->value.integer.step = 1;
-
-       return 0;
-}
-
-static int equalizer_ctl_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int idx;
-
-       idx = nid - TUNING_CTL_START_NID;
-       /* any change? */
-       if (spec->cur_ctl_vals[idx] == *valp)
-               return 0;
-
-       spec->cur_ctl_vals[idx] = *valp;
-
-       idx = *valp;
-       tuning_ctl_set(codec, nid, equalizer_vals_lookup, idx);
-
-       return 1;
-}
-
-static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(voice_focus_db_scale, 2000, 100, 0);
-static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(eq_db_scale, -2400, 100, 0);
-
-static int add_tuning_control(struct hda_codec *codec,
-                               hda_nid_t pnid, hda_nid_t nid,
-                               const char *name, int dir)
-{
-       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       int type = dir ? HDA_INPUT : HDA_OUTPUT;
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
-
-       knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                       SNDRV_CTL_ELEM_ACCESS_TLV_READ;
-       knew.tlv.c = NULL;
-       knew.tlv.p = NULL;
-       switch (pnid) {
-       case VOICE_FOCUS:
-               knew.info = voice_focus_ctl_info;
-               knew.get = tuning_ctl_get;
-               knew.put = voice_focus_ctl_put;
-               knew.tlv.p = voice_focus_db_scale;
-               break;
-       case MIC_SVM:
-               knew.info = mic_svm_ctl_info;
-               knew.get = tuning_ctl_get;
-               knew.put = mic_svm_ctl_put;
-               break;
-       case EQUALIZER:
-               knew.info = equalizer_ctl_info;
-               knew.get = tuning_ctl_get;
-               knew.put = equalizer_ctl_put;
-               knew.tlv.p = eq_db_scale;
-               break;
-       default:
-               return 0;
-       }
-       knew.private_value =
-               HDA_COMPOSE_AMP_VAL(nid, 1, 0, type);
-       snprintf(namestr, sizeof(namestr), "%s %s Volume", name, dirstr[dir]);
-       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
-}
-
-static int add_tuning_ctls(struct hda_codec *codec)
-{
-       int i;
-       int err;
-
-       for (i = 0; i < TUNING_CTLS_COUNT; i++) {
-               err = add_tuning_control(codec,
-                                       ca0132_tuning_ctls[i].parent_nid,
-                                       ca0132_tuning_ctls[i].nid,
-                                       ca0132_tuning_ctls[i].name,
-                                       ca0132_tuning_ctls[i].direct);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static void ca0132_init_tuning_defaults(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int i;
-
-       /* Wedge Angle defaults to 30.  10 below is 30 - 20.  20 is min. */
-       spec->cur_ctl_vals[WEDGE_ANGLE - TUNING_CTL_START_NID] = 10;
-       /* SVM level defaults to 0.74. */
-       spec->cur_ctl_vals[SVM_LEVEL - TUNING_CTL_START_NID] = 74;
-
-       /* EQ defaults to 0dB. */
-       for (i = 2; i < TUNING_CTLS_COUNT; i++)
-               spec->cur_ctl_vals[i] = 24;
-}
-#endif /*ENABLE_TUNING_CONTROLS*/
-
-/*
- * Select the active output.
- * If autodetect is enabled, output will be selected based on jack detection.
- * If jack inserted, headphone will be selected, else built-in speakers
- * If autodetect is disabled, output will be selected based on selection.
- */
-static int ca0132_select_out(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int pin_ctl;
-       int jack_present;
-       int auto_jack;
-       unsigned int tmp;
-       int err;
-
-       codec_dbg(codec, "ca0132_select_out\n");
-
-       snd_hda_power_up_pm(codec);
-
-       auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
-
-       if (auto_jack)
-               jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_hp);
-       else
-               jack_present =
-                       spec->vnode_lswitch[VNID_HP_SEL - VNODE_START_NID];
-
-       if (jack_present)
-               spec->cur_out_type = HEADPHONE_OUT;
-       else
-               spec->cur_out_type = SPEAKER_OUT;
-
-       if (spec->cur_out_type == SPEAKER_OUT) {
-               codec_dbg(codec, "ca0132_select_out speaker\n");
-               /*speaker out config*/
-               tmp = FLOAT_ONE;
-               err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
-               if (err < 0)
-                       goto exit;
-               /*enable speaker EQ*/
-               tmp = FLOAT_ONE;
-               err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp);
-               if (err < 0)
-                       goto exit;
-
-               /* Setup EAPD */
-               snd_hda_codec_write(codec, spec->out_pins[1], 0,
-                                   VENDOR_CHIPIO_EAPD_SEL_SET, 0x02);
-               snd_hda_codec_write(codec, spec->out_pins[0], 0,
-                                   AC_VERB_SET_EAPD_BTLENABLE, 0x00);
-               snd_hda_codec_write(codec, spec->out_pins[0], 0,
-                                   VENDOR_CHIPIO_EAPD_SEL_SET, 0x00);
-               snd_hda_codec_write(codec, spec->out_pins[0], 0,
-                                   AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-
-               /* disable headphone node */
-               pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
-                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               snd_hda_set_pin_ctl(codec, spec->out_pins[1],
-                                   pin_ctl & ~PIN_HP);
-               /* enable speaker node */
-               pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
-                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               snd_hda_set_pin_ctl(codec, spec->out_pins[0],
-                                   pin_ctl | PIN_OUT);
-       } else {
-               codec_dbg(codec, "ca0132_select_out hp\n");
-               /*headphone out config*/
-               tmp = FLOAT_ZERO;
-               err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
-               if (err < 0)
-                       goto exit;
-               /*disable speaker EQ*/
-               tmp = FLOAT_ZERO;
-               err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp);
-               if (err < 0)
-                       goto exit;
-
-               /* Setup EAPD */
-               snd_hda_codec_write(codec, spec->out_pins[0], 0,
-                                   VENDOR_CHIPIO_EAPD_SEL_SET, 0x00);
-               snd_hda_codec_write(codec, spec->out_pins[0], 0,
-                                   AC_VERB_SET_EAPD_BTLENABLE, 0x00);
-               snd_hda_codec_write(codec, spec->out_pins[1], 0,
-                                   VENDOR_CHIPIO_EAPD_SEL_SET, 0x02);
-               snd_hda_codec_write(codec, spec->out_pins[0], 0,
-                                   AC_VERB_SET_EAPD_BTLENABLE, 0x02);
-
-               /* disable speaker*/
-               pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0,
-                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               snd_hda_set_pin_ctl(codec, spec->out_pins[0],
-                                   pin_ctl & ~PIN_HP);
-               /* enable headphone*/
-               pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0,
-                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               snd_hda_set_pin_ctl(codec, spec->out_pins[1],
-                                   pin_ctl | PIN_HP);
-       }
-
-exit:
-       snd_hda_power_down_pm(codec);
-
-       return err < 0 ? err : 0;
-}
-
-static int ae5_headphone_gain_set(struct hda_codec *codec, long val);
-static int zxr_headphone_gain_set(struct hda_codec *codec, long val);
-static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val);
-
-static void ae5_mmio_select_out(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       const struct ae_ca0113_output_set *out_cmds;
-       unsigned int i;
-
-       if (ca0132_quirk(spec) == QUIRK_AE5)
-               out_cmds = &ae5_ca0113_output_presets;
-       else
-               out_cmds = &ae7_ca0113_output_presets;
-
-       for (i = 0; i < AE_CA0113_OUT_SET_COMMANDS; i++)
-               ca0113_mmio_command_set(codec, out_cmds->group[i],
-                               out_cmds->target[i],
-                               out_cmds->vals[spec->cur_out_type][i]);
-}
-
-static int ca0132_alt_set_full_range_speaker(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int quirk = ca0132_quirk(spec);
-       unsigned int tmp;
-       int err;
-
-       /* 2.0/4.0 setup has no LFE channel, so setting full-range does nothing. */
-       if (spec->channel_cfg_val == SPEAKER_CHANNELS_4_0
-                       || spec->channel_cfg_val == SPEAKER_CHANNELS_2_0)
-               return 0;
-
-       /* Set front L/R full range. Zero for full-range, one for redirection. */
-       tmp = spec->speaker_range_val[0] ? FLOAT_ZERO : FLOAT_ONE;
-       err = dspio_set_uint_param(codec, 0x96,
-                       SPEAKER_FULL_RANGE_FRONT_L_R, tmp);
-       if (err < 0)
-               return err;
-
-       /* When setting full-range rear, both rear and center/lfe are set. */
-       tmp = spec->speaker_range_val[1] ? FLOAT_ZERO : FLOAT_ONE;
-       err = dspio_set_uint_param(codec, 0x96,
-                       SPEAKER_FULL_RANGE_CENTER_LFE, tmp);
-       if (err < 0)
-               return err;
-
-       err = dspio_set_uint_param(codec, 0x96,
-                       SPEAKER_FULL_RANGE_REAR_L_R, tmp);
-       if (err < 0)
-               return err;
-
-       /*
-        * Only the AE series cards set this value when setting full-range,
-        * and it's always 1.0f.
-        */
-       if (quirk == QUIRK_AE5 || quirk == QUIRK_AE7) {
-               err = dspio_set_uint_param(codec, 0x96,
-                               SPEAKER_FULL_RANGE_SURROUND_L_R, FLOAT_ONE);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int ca0132_alt_surround_set_bass_redirection(struct hda_codec *codec,
-               bool val)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-       int err;
-
-       if (val && spec->channel_cfg_val != SPEAKER_CHANNELS_4_0 &&
-                       spec->channel_cfg_val != SPEAKER_CHANNELS_2_0)
-               tmp = FLOAT_ONE;
-       else
-               tmp = FLOAT_ZERO;
-
-       err = dspio_set_uint_param(codec, 0x96, SPEAKER_BASS_REDIRECT, tmp);
-       if (err < 0)
-               return err;
-
-       /* If it is enabled, make sure to set the crossover frequency. */
-       if (tmp) {
-               tmp = float_xbass_xover_lookup[spec->xbass_xover_freq];
-               err = dspio_set_uint_param(codec, 0x96,
-                               SPEAKER_BASS_REDIRECT_XOVER_FREQ, tmp);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-/*
- * These are the commands needed to setup output on each of the different card
- * types.
- */
-static void ca0132_alt_select_out_get_quirk_data(struct hda_codec *codec,
-               const struct ca0132_alt_out_set_quirk_data **quirk_data)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int quirk = ca0132_quirk(spec);
-       unsigned int i;
-
-       *quirk_data = NULL;
-       for (i = 0; i < ARRAY_SIZE(quirk_out_set_data); i++) {
-               if (quirk_out_set_data[i].quirk_id == quirk) {
-                       *quirk_data = &quirk_out_set_data[i];
-                       return;
-               }
-       }
-}
-
-static int ca0132_alt_select_out_quirk_set(struct hda_codec *codec)
-{
-       const struct ca0132_alt_out_set_quirk_data *quirk_data;
-       const struct ca0132_alt_out_set_info *out_info;
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int i, gpio_data;
-       int err;
-
-       ca0132_alt_select_out_get_quirk_data(codec, &quirk_data);
-       if (!quirk_data)
-               return 0;
-
-       out_info = &quirk_data->out_set_info[spec->cur_out_type];
-       if (quirk_data->is_ae_series)
-               ae5_mmio_select_out(codec);
-
-       if (out_info->has_hda_gpio) {
-               gpio_data = snd_hda_codec_read(codec, codec->core.afg, 0,
-                               AC_VERB_GET_GPIO_DATA, 0);
-
-               if (out_info->hda_gpio_set)
-                       gpio_data |= (1 << out_info->hda_gpio_pin);
-               else
-                       gpio_data &= ~(1 << out_info->hda_gpio_pin);
-
-               snd_hda_codec_write(codec, codec->core.afg, 0,
-                                   AC_VERB_SET_GPIO_DATA, gpio_data);
-       }
-
-       if (out_info->mmio_gpio_count) {
-               for (i = 0; i < out_info->mmio_gpio_count; i++) {
-                       ca0113_mmio_gpio_set(codec, out_info->mmio_gpio_pin[i],
-                                       out_info->mmio_gpio_set[i]);
-               }
-       }
-
-       if (out_info->scp_cmds_count) {
-               for (i = 0; i < out_info->scp_cmds_count; i++) {
-                       err = dspio_set_uint_param(codec,
-                                       out_info->scp_cmd_mid[i],
-                                       out_info->scp_cmd_req[i],
-                                       out_info->scp_cmd_val[i]);
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       chipio_set_control_param(codec, 0x0d, out_info->dac2port);
-
-       if (out_info->has_chipio_write) {
-               chipio_write(codec, out_info->chipio_write_addr,
-                               out_info->chipio_write_data);
-       }
-
-       if (quirk_data->has_headphone_gain) {
-               if (spec->cur_out_type != HEADPHONE_OUT) {
-                       if (quirk_data->is_ae_series)
-                               ae5_headphone_gain_set(codec, 2);
-                       else
-                               zxr_headphone_gain_set(codec, 0);
-               } else {
-                       if (quirk_data->is_ae_series)
-                               ae5_headphone_gain_set(codec,
-                                               spec->ae5_headphone_gain_val);
-                       else
-                               zxr_headphone_gain_set(codec,
-                                               spec->zxr_gain_set);
-               }
-       }
-
-       return 0;
-}
-
-static void ca0132_set_out_node_pincfg(struct hda_codec *codec, hda_nid_t nid,
-               bool out_enable, bool hp_enable)
-{
-       unsigned int pin_ctl;
-
-       pin_ctl = snd_hda_codec_read(codec, nid, 0,
-                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-
-       pin_ctl = hp_enable ? pin_ctl | PIN_HP_AMP : pin_ctl & ~PIN_HP_AMP;
-       pin_ctl = out_enable ? pin_ctl | PIN_OUT : pin_ctl & ~PIN_OUT;
-       snd_hda_set_pin_ctl(codec, nid, pin_ctl);
-}
-
-/*
- * This function behaves similarly to the ca0132_select_out funciton above,
- * except with a few differences. It adds the ability to select the current
- * output with an enumerated control "output source" if the auto detect
- * mute switch is set to off. If the auto detect mute switch is enabled, it
- * will detect either headphone or lineout(SPEAKER_OUT) from jack detection.
- * It also adds the ability to auto-detect the front headphone port.
- */
-static int ca0132_alt_select_out(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp, outfx_set;
-       int jack_present;
-       int auto_jack;
-       int err;
-       /* Default Headphone is rear headphone */
-       hda_nid_t headphone_nid = spec->out_pins[1];
-
-       codec_dbg(codec, "%s\n", __func__);
-
-       snd_hda_power_up_pm(codec);
-
-       auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
-
-       /*
-        * If headphone rear or front is plugged in, set to headphone.
-        * If neither is plugged in, set to rear line out. Only if
-        * hp/speaker auto detect is enabled.
-        */
-       if (auto_jack) {
-               jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_hp) ||
-                          snd_hda_jack_detect(codec, spec->unsol_tag_front_hp);
-
-               if (jack_present)
-                       spec->cur_out_type = HEADPHONE_OUT;
-               else
-                       spec->cur_out_type = SPEAKER_OUT;
-       } else
-               spec->cur_out_type = spec->out_enum_val;
-
-       outfx_set = spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID];
-
-       /* Begin DSP output switch, mute DSP volume. */
-       err = dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_MUTE, FLOAT_ONE);
-       if (err < 0)
-               goto exit;
-
-       if (ca0132_alt_select_out_quirk_set(codec) < 0)
-               goto exit;
-
-       switch (spec->cur_out_type) {
-       case SPEAKER_OUT:
-               codec_dbg(codec, "%s speaker\n", __func__);
-
-               /* Enable EAPD */
-               snd_hda_codec_write(codec, spec->out_pins[0], 0,
-                       AC_VERB_SET_EAPD_BTLENABLE, 0x01);
-
-               /* Disable headphone node. */
-               ca0132_set_out_node_pincfg(codec, spec->out_pins[1], 0, 0);
-               /* Set front L-R to output. */
-               ca0132_set_out_node_pincfg(codec, spec->out_pins[0], 1, 0);
-               /* Set Center/LFE to output. */
-               ca0132_set_out_node_pincfg(codec, spec->out_pins[2], 1, 0);
-               /* Set rear surround to output. */
-               ca0132_set_out_node_pincfg(codec, spec->out_pins[3], 1, 0);
-
-               /*
-                * Without PlayEnhancement being enabled, if we've got a 2.0
-                * setup, set it to floating point eight to disable any DSP
-                * processing effects.
-                */
-               if (!outfx_set && spec->channel_cfg_val == SPEAKER_CHANNELS_2_0)
-                       tmp = FLOAT_EIGHT;
-               else
-                       tmp = speaker_channel_cfgs[spec->channel_cfg_val].val;
-
-               err = dspio_set_uint_param(codec, 0x80, 0x04, tmp);
-               if (err < 0)
-                       goto exit;
-
-               break;
-       case HEADPHONE_OUT:
-               codec_dbg(codec, "%s hp\n", __func__);
-               snd_hda_codec_write(codec, spec->out_pins[0], 0,
-                       AC_VERB_SET_EAPD_BTLENABLE, 0x00);
-
-               /* Disable all speaker nodes. */
-               ca0132_set_out_node_pincfg(codec, spec->out_pins[0], 0, 0);
-               ca0132_set_out_node_pincfg(codec, spec->out_pins[2], 0, 0);
-               ca0132_set_out_node_pincfg(codec, spec->out_pins[3], 0, 0);
-
-               /* enable headphone, either front or rear */
-               if (snd_hda_jack_detect(codec, spec->unsol_tag_front_hp))
-                       headphone_nid = spec->out_pins[2];
-               else if (snd_hda_jack_detect(codec, spec->unsol_tag_hp))
-                       headphone_nid = spec->out_pins[1];
-
-               ca0132_set_out_node_pincfg(codec, headphone_nid, 1, 1);
-
-               if (outfx_set)
-                       err = dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE);
-               else
-                       err = dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ZERO);
-
-               if (err < 0)
-                       goto exit;
-               break;
-       }
-       /*
-        * If output effects are enabled, set the X-Bass effect value again to
-        * make sure that it's properly enabled/disabled for speaker
-        * configurations with an LFE channel.
-        */
-       if (outfx_set)
-               ca0132_effects_set(codec, X_BASS,
-                       spec->effects_switch[X_BASS - EFFECT_START_NID]);
-
-       /* Set speaker EQ bypass attenuation to 0. */
-       err = dspio_set_uint_param(codec, 0x8f, 0x01, FLOAT_ZERO);
-       if (err < 0)
-               goto exit;
-
-       /*
-        * Although unused on all cards but the AE series, this is always set
-        * to zero when setting the output.
-        */
-       err = dspio_set_uint_param(codec, 0x96,
-                       SPEAKER_TUNING_USE_SPEAKER_EQ, FLOAT_ZERO);
-       if (err < 0)
-               goto exit;
-
-       if (spec->cur_out_type == SPEAKER_OUT)
-               err = ca0132_alt_surround_set_bass_redirection(codec,
-                               spec->bass_redirection_val);
-       else
-               err = ca0132_alt_surround_set_bass_redirection(codec, 0);
-
-       /* Unmute DSP now that we're done with output selection. */
-       err = dspio_set_uint_param(codec, 0x96,
-                       SPEAKER_TUNING_MUTE, FLOAT_ZERO);
-       if (err < 0)
-               goto exit;
-
-       if (spec->cur_out_type == SPEAKER_OUT) {
-               err = ca0132_alt_set_full_range_speaker(codec);
-               if (err < 0)
-                       goto exit;
-       }
-
-exit:
-       snd_hda_power_down_pm(codec);
-
-       return err < 0 ? err : 0;
-}
-
-static void ca0132_unsol_hp_delayed(struct work_struct *work)
-{
-       struct ca0132_spec *spec = container_of(
-               to_delayed_work(work), struct ca0132_spec, unsol_hp_work);
-       struct hda_jack_tbl *jack;
-
-       if (ca0132_use_alt_functions(spec))
-               ca0132_alt_select_out(spec->codec);
-       else
-               ca0132_select_out(spec->codec);
-
-       jack = snd_hda_jack_tbl_get(spec->codec, spec->unsol_tag_hp);
-       if (jack) {
-               jack->block_report = 0;
-               snd_hda_jack_report_sync(spec->codec);
-       }
-}
-
-static void ca0132_set_dmic(struct hda_codec *codec, int enable);
-static int ca0132_mic_boost_set(struct hda_codec *codec, long val);
-static void resume_mic1(struct hda_codec *codec, unsigned int oldval);
-static int stop_mic1(struct hda_codec *codec);
-static int ca0132_cvoice_switch_set(struct hda_codec *codec);
-static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val);
-
-/*
- * Select the active VIP source
- */
-static int ca0132_set_vipsource(struct hda_codec *codec, int val)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return 0;
-
-       /* if CrystalVoice if off, vipsource should be 0 */
-       if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ||
-           (val == 0)) {
-               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (spec->cur_mic_type == DIGITAL_MIC)
-                       tmp = FLOAT_TWO;
-               else
-                       tmp = FLOAT_ONE;
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-               tmp = FLOAT_ZERO;
-               dspio_set_uint_param(codec, 0x80, 0x05, tmp);
-       } else {
-               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000);
-               if (spec->cur_mic_type == DIGITAL_MIC)
-                       tmp = FLOAT_TWO;
-               else
-                       tmp = FLOAT_ONE;
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-               tmp = FLOAT_ONE;
-               dspio_set_uint_param(codec, 0x80, 0x05, tmp);
-               msleep(20);
-               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, val);
-       }
-
-       return 1;
-}
-
-static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return 0;
-
-       codec_dbg(codec, "%s\n", __func__);
-
-       chipio_set_stream_control(codec, 0x03, 0);
-       chipio_set_stream_control(codec, 0x04, 0);
-
-       /* if CrystalVoice is off, vipsource should be 0 */
-       if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ||
-           (val == 0) || spec->in_enum_val == REAR_LINE_IN) {
-               codec_dbg(codec, "%s: off.", __func__);
-               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0);
-
-               tmp = FLOAT_ZERO;
-               dspio_set_uint_param(codec, 0x80, 0x05, tmp);
-
-               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (ca0132_quirk(spec) == QUIRK_R3DI)
-                       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-
-
-               if (spec->in_enum_val == REAR_LINE_IN)
-                       tmp = FLOAT_ZERO;
-               else {
-                       if (ca0132_quirk(spec) == QUIRK_SBZ)
-                               tmp = FLOAT_THREE;
-                       else
-                               tmp = FLOAT_ONE;
-               }
-
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-       } else {
-               codec_dbg(codec, "%s: on.", __func__);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000);
-               if (ca0132_quirk(spec) == QUIRK_R3DI)
-                       chipio_set_conn_rate(codec, 0x0F, SR_16_000);
-
-               if (spec->effects_switch[VOICE_FOCUS - EFFECT_START_NID])
-                       tmp = FLOAT_TWO;
-               else
-                       tmp = FLOAT_ONE;
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-               tmp = FLOAT_ONE;
-               dspio_set_uint_param(codec, 0x80, 0x05, tmp);
-
-               msleep(20);
-               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, val);
-       }
-
-       chipio_set_stream_control(codec, 0x03, 1);
-       chipio_set_stream_control(codec, 0x04, 1);
-
-       return 1;
-}
-
-/*
- * Select the active microphone.
- * If autodetect is enabled, mic will be selected based on jack detection.
- * If jack inserted, ext.mic will be selected, else built-in mic
- * If autodetect is disabled, mic will be selected based on selection.
- */
-static int ca0132_select_mic(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int jack_present;
-       int auto_jack;
-
-       codec_dbg(codec, "ca0132_select_mic\n");
-
-       snd_hda_power_up_pm(codec);
-
-       auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID];
-
-       if (auto_jack)
-               jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_amic1);
-       else
-               jack_present =
-                       spec->vnode_lswitch[VNID_AMIC1_SEL - VNODE_START_NID];
-
-       if (jack_present)
-               spec->cur_mic_type = LINE_MIC_IN;
-       else
-               spec->cur_mic_type = DIGITAL_MIC;
-
-       if (spec->cur_mic_type == DIGITAL_MIC) {
-               /* enable digital Mic */
-               chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_32_000);
-               ca0132_set_dmic(codec, 1);
-               ca0132_mic_boost_set(codec, 0);
-               /* set voice focus */
-               ca0132_effects_set(codec, VOICE_FOCUS,
-                                  spec->effects_switch
-                                  [VOICE_FOCUS - EFFECT_START_NID]);
-       } else {
-               /* disable digital Mic */
-               chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_96_000);
-               ca0132_set_dmic(codec, 0);
-               ca0132_mic_boost_set(codec, spec->cur_mic_boost);
-               /* disable voice focus */
-               ca0132_effects_set(codec, VOICE_FOCUS, 0);
-       }
-
-       snd_hda_power_down_pm(codec);
-
-       return 0;
-}
-
-/*
- * Select the active input.
- * Mic detection isn't used, because it's kind of pointless on the SBZ.
- * The front mic has no jack-detection, so the only way to switch to it
- * is to do it manually in alsamixer.
- */
-static int ca0132_alt_select_in(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-
-       codec_dbg(codec, "%s\n", __func__);
-
-       snd_hda_power_up_pm(codec);
-
-       chipio_set_stream_control(codec, 0x03, 0);
-       chipio_set_stream_control(codec, 0x04, 0);
-
-       spec->cur_mic_type = spec->in_enum_val;
-
-       switch (spec->cur_mic_type) {
-       case REAR_MIC:
-               switch (ca0132_quirk(spec)) {
-               case QUIRK_SBZ:
-               case QUIRK_R3D:
-                       ca0113_mmio_gpio_set(codec, 0, false);
-                       tmp = FLOAT_THREE;
-                       break;
-               case QUIRK_ZXR:
-                       tmp = FLOAT_THREE;
-                       break;
-               case QUIRK_R3DI:
-                       r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
-                       tmp = FLOAT_ONE;
-                       break;
-               case QUIRK_AE5:
-                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
-                       tmp = FLOAT_THREE;
-                       break;
-               case QUIRK_AE7:
-                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
-                       tmp = FLOAT_THREE;
-                       chipio_set_conn_rate(codec, MEM_CONNID_MICIN2,
-                                       SR_96_000);
-                       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2,
-                                       SR_96_000);
-                       dspio_set_uint_param(codec, 0x80, 0x01, FLOAT_ZERO);
-                       break;
-               default:
-                       tmp = FLOAT_ONE;
-                       break;
-               }
-
-               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (ca0132_quirk(spec) == QUIRK_R3DI)
-                       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-               chipio_set_stream_control(codec, 0x03, 1);
-               chipio_set_stream_control(codec, 0x04, 1);
-               switch (ca0132_quirk(spec)) {
-               case QUIRK_SBZ:
-                       chipio_write(codec, 0x18B098, 0x0000000C);
-                       chipio_write(codec, 0x18B09C, 0x0000000C);
-                       break;
-               case QUIRK_ZXR:
-                       chipio_write(codec, 0x18B098, 0x0000000C);
-                       chipio_write(codec, 0x18B09C, 0x000000CC);
-                       break;
-               case QUIRK_AE5:
-                       chipio_write(codec, 0x18B098, 0x0000000C);
-                       chipio_write(codec, 0x18B09C, 0x0000004C);
-                       break;
-               default:
-                       break;
-               }
-               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
-               break;
-       case REAR_LINE_IN:
-               ca0132_mic_boost_set(codec, 0);
-               switch (ca0132_quirk(spec)) {
-               case QUIRK_SBZ:
-               case QUIRK_R3D:
-                       ca0113_mmio_gpio_set(codec, 0, false);
-                       break;
-               case QUIRK_R3DI:
-                       r3di_gpio_mic_set(codec, R3DI_REAR_MIC);
-                       break;
-               case QUIRK_AE5:
-                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
-                       break;
-               case QUIRK_AE7:
-                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x3f);
-                       chipio_set_conn_rate(codec, MEM_CONNID_MICIN2,
-                                       SR_96_000);
-                       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2,
-                                       SR_96_000);
-                       dspio_set_uint_param(codec, 0x80, 0x01, FLOAT_ZERO);
-                       break;
-               default:
-                       break;
-               }
-
-               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (ca0132_quirk(spec) == QUIRK_R3DI)
-                       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-
-               if (ca0132_quirk(spec) == QUIRK_AE7)
-                       tmp = FLOAT_THREE;
-               else
-                       tmp = FLOAT_ZERO;
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-               switch (ca0132_quirk(spec)) {
-               case QUIRK_SBZ:
-               case QUIRK_AE5:
-                       chipio_write(codec, 0x18B098, 0x00000000);
-                       chipio_write(codec, 0x18B09C, 0x00000000);
-                       break;
-               default:
-                       break;
-               }
-               chipio_set_stream_control(codec, 0x03, 1);
-               chipio_set_stream_control(codec, 0x04, 1);
-               break;
-       case FRONT_MIC:
-               switch (ca0132_quirk(spec)) {
-               case QUIRK_SBZ:
-               case QUIRK_R3D:
-                       ca0113_mmio_gpio_set(codec, 0, true);
-                       ca0113_mmio_gpio_set(codec, 5, false);
-                       tmp = FLOAT_THREE;
-                       break;
-               case QUIRK_R3DI:
-                       r3di_gpio_mic_set(codec, R3DI_FRONT_MIC);
-                       tmp = FLOAT_ONE;
-                       break;
-               case QUIRK_AE5:
-                       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x3f);
-                       tmp = FLOAT_THREE;
-                       break;
-               default:
-                       tmp = FLOAT_ONE;
-                       break;
-               }
-
-               chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-               chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-               if (ca0132_quirk(spec) == QUIRK_R3DI)
-                       chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-               chipio_set_stream_control(codec, 0x03, 1);
-               chipio_set_stream_control(codec, 0x04, 1);
-
-               switch (ca0132_quirk(spec)) {
-               case QUIRK_SBZ:
-                       chipio_write(codec, 0x18B098, 0x0000000C);
-                       chipio_write(codec, 0x18B09C, 0x000000CC);
-                       break;
-               case QUIRK_AE5:
-                       chipio_write(codec, 0x18B098, 0x0000000C);
-                       chipio_write(codec, 0x18B09C, 0x0000004C);
-                       break;
-               default:
-                       break;
-               }
-               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
-               break;
-       }
-       ca0132_cvoice_switch_set(codec);
-
-       snd_hda_power_down_pm(codec);
-       return 0;
-}
-
-/*
- * Check if VNODE settings take effect immediately.
- */
-static bool ca0132_is_vnode_effective(struct hda_codec *codec,
-                                    hda_nid_t vnid,
-                                    hda_nid_t *shared_nid)
-{
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       switch (vnid) {
-       case VNID_SPK:
-               nid = spec->shared_out_nid;
-               break;
-       case VNID_MIC:
-               nid = spec->shared_mic_nid;
-               break;
-       default:
-               return false;
-       }
-
-       if (shared_nid)
-               *shared_nid = nid;
-
-       return true;
-}
-
-/*
-* The following functions are control change helpers.
-* They return 0 if no changed.  Return 1 if changed.
-*/
-static int ca0132_voicefx_set(struct hda_codec *codec, int enable)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-
-       /* based on CrystalVoice state to enable VoiceFX. */
-       if (enable) {
-               tmp = spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ?
-                       FLOAT_ONE : FLOAT_ZERO;
-       } else {
-               tmp = FLOAT_ZERO;
-       }
-
-       dspio_set_uint_param(codec, ca0132_voicefx.mid,
-                            ca0132_voicefx.reqs[0], tmp);
-
-       return 1;
-}
-
-/*
- * Set the effects parameters
- */
-static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int on, tmp, channel_cfg;
-       int num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
-       int err = 0;
-       int idx = nid - EFFECT_START_NID;
-
-       if ((idx < 0) || (idx >= num_fx))
-               return 0; /* no changed */
-
-       /* for out effect, qualify with PE */
-       if ((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) {
-               /* if PE if off, turn off out effects. */
-               if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID])
-                       val = 0;
-               if (spec->cur_out_type == SPEAKER_OUT && nid == X_BASS) {
-                       channel_cfg = spec->channel_cfg_val;
-                       if (channel_cfg != SPEAKER_CHANNELS_2_0 &&
-                                       channel_cfg != SPEAKER_CHANNELS_4_0)
-                               val = 0;
-               }
-       }
-
-       /* for in effect, qualify with CrystalVoice */
-       if ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID)) {
-               /* if CrystalVoice if off, turn off in effects. */
-               if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID])
-                       val = 0;
-
-               /* Voice Focus applies to 2-ch Mic, Digital Mic */
-               if ((nid == VOICE_FOCUS) && (spec->cur_mic_type != DIGITAL_MIC))
-                       val = 0;
-
-               /* If Voice Focus on SBZ, set to two channel. */
-               if ((nid == VOICE_FOCUS) && ca0132_use_pci_mmio(spec)
-                               && (spec->cur_mic_type != REAR_LINE_IN)) {
-                       if (spec->effects_switch[CRYSTAL_VOICE -
-                                                EFFECT_START_NID]) {
-
-                               if (spec->effects_switch[VOICE_FOCUS -
-                                                        EFFECT_START_NID]) {
-                                       tmp = FLOAT_TWO;
-                                       val = 1;
-                               } else
-                                       tmp = FLOAT_ONE;
-
-                               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-                       }
-               }
-               /*
-                * For SBZ noise reduction, there's an extra command
-                * to module ID 0x47. No clue why.
-                */
-               if ((nid == NOISE_REDUCTION) && ca0132_use_pci_mmio(spec)
-                               && (spec->cur_mic_type != REAR_LINE_IN)) {
-                       if (spec->effects_switch[CRYSTAL_VOICE -
-                                                EFFECT_START_NID]) {
-                               if (spec->effects_switch[NOISE_REDUCTION -
-                                                        EFFECT_START_NID])
-                                       tmp = FLOAT_ONE;
-                               else
-                                       tmp = FLOAT_ZERO;
-                       } else
-                               tmp = FLOAT_ZERO;
-
-                       dspio_set_uint_param(codec, 0x47, 0x00, tmp);
-               }
-
-               /* If rear line in disable effects. */
-               if (ca0132_use_alt_functions(spec) &&
-                               spec->in_enum_val == REAR_LINE_IN)
-                       val = 0;
-       }
-
-       codec_dbg(codec, "ca0132_effect_set: nid=0x%x, val=%ld\n",
-                   nid, val);
-
-       on = (val == 0) ? FLOAT_ZERO : FLOAT_ONE;
-       err = dspio_set_uint_param(codec, ca0132_effects[idx].mid,
-                                  ca0132_effects[idx].reqs[0], on);
-
-       if (err < 0)
-               return 0; /* no changed */
-
-       return 1;
-}
-
-/*
- * Turn on/off Playback Enhancements
- */
-static int ca0132_pe_switch_set(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid;
-       int i, ret = 0;
-
-       codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n",
-                   spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]);
-
-       if (ca0132_use_alt_functions(spec))
-               ca0132_alt_select_out(codec);
-
-       i = OUT_EFFECT_START_NID - EFFECT_START_NID;
-       nid = OUT_EFFECT_START_NID;
-       /* PE affects all out effects */
-       for (; nid < OUT_EFFECT_END_NID; nid++, i++)
-               ret |= ca0132_effects_set(codec, nid, spec->effects_switch[i]);
-
-       return ret;
-}
-
-/* Check if Mic1 is streaming, if so, stop streaming */
-static int stop_mic1(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int oldval = snd_hda_codec_read(codec, spec->adcs[0], 0,
-                                                AC_VERB_GET_CONV, 0);
-       if (oldval != 0)
-               snd_hda_codec_write(codec, spec->adcs[0], 0,
-                                   AC_VERB_SET_CHANNEL_STREAMID,
-                                   0);
-       return oldval;
-}
-
-/* Resume Mic1 streaming if it was stopped. */
-static void resume_mic1(struct hda_codec *codec, unsigned int oldval)
-{
-       struct ca0132_spec *spec = codec->spec;
-       /* Restore the previous stream and channel */
-       if (oldval != 0)
-               snd_hda_codec_write(codec, spec->adcs[0], 0,
-                                   AC_VERB_SET_CHANNEL_STREAMID,
-                                   oldval);
-}
-
-/*
- * Turn on/off CrystalVoice
- */
-static int ca0132_cvoice_switch_set(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid;
-       int i, ret = 0;
-       unsigned int oldval;
-
-       codec_dbg(codec, "ca0132_cvoice_switch_set: val=%ld\n",
-                   spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]);
-
-       i = IN_EFFECT_START_NID - EFFECT_START_NID;
-       nid = IN_EFFECT_START_NID;
-       /* CrystalVoice affects all in effects */
-       for (; nid < IN_EFFECT_END_NID; nid++, i++)
-               ret |= ca0132_effects_set(codec, nid, spec->effects_switch[i]);
-
-       /* including VoiceFX */
-       ret |= ca0132_voicefx_set(codec, (spec->voicefx_val ? 1 : 0));
-
-       /* set correct vipsource */
-       oldval = stop_mic1(codec);
-       if (ca0132_use_alt_functions(spec))
-               ret |= ca0132_alt_set_vipsource(codec, 1);
-       else
-               ret |= ca0132_set_vipsource(codec, 1);
-       resume_mic1(codec, oldval);
-       return ret;
-}
-
-static int ca0132_mic_boost_set(struct hda_codec *codec, long val)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int ret = 0;
-
-       if (val) /* on */
-               ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
-                                       HDA_INPUT, 0, HDA_AMP_VOLMASK, 3);
-       else /* off */
-               ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
-                                       HDA_INPUT, 0, HDA_AMP_VOLMASK, 0);
-
-       return ret;
-}
-
-static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int ret = 0;
-
-       ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0,
-                               HDA_INPUT, 0, HDA_AMP_VOLMASK, val);
-       return ret;
-}
-
-static int ae5_headphone_gain_set(struct hda_codec *codec, long val)
-{
-       unsigned int i;
-
-       for (i = 0; i < 4; i++)
-               ca0113_mmio_command_set(codec, 0x48, 0x11 + i,
-                               ae5_headphone_gain_presets[val].vals[i]);
-       return 0;
-}
-
-/*
- * gpio pin 1 is a relay that switches on/off, apparently setting the headphone
- * amplifier to handle a 600 ohm load.
- */
-static int zxr_headphone_gain_set(struct hda_codec *codec, long val)
-{
-       ca0113_mmio_gpio_set(codec, 1, val);
-
-       return 0;
-}
-
-static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       hda_nid_t shared_nid = 0;
-       bool effective;
-       int ret = 0;
-       struct ca0132_spec *spec = codec->spec;
-       int auto_jack;
-
-       if (nid == VNID_HP_SEL) {
-               auto_jack =
-                       spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
-               if (!auto_jack) {
-                       if (ca0132_use_alt_functions(spec))
-                               ca0132_alt_select_out(codec);
-                       else
-                               ca0132_select_out(codec);
-               }
-               return 1;
-       }
-
-       if (nid == VNID_AMIC1_SEL) {
-               auto_jack =
-                       spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID];
-               if (!auto_jack)
-                       ca0132_select_mic(codec);
-               return 1;
-       }
-
-       if (nid == VNID_HP_ASEL) {
-               if (ca0132_use_alt_functions(spec))
-                       ca0132_alt_select_out(codec);
-               else
-                       ca0132_select_out(codec);
-               return 1;
-       }
-
-       if (nid == VNID_AMIC1_ASEL) {
-               ca0132_select_mic(codec);
-               return 1;
-       }
-
-       /* if effective conditions, then update hw immediately. */
-       effective = ca0132_is_vnode_effective(codec, nid, &shared_nid);
-       if (effective) {
-               int dir = get_amp_direction(kcontrol);
-               int ch = get_amp_channels(kcontrol);
-               unsigned long pval;
-
-               mutex_lock(&codec->control_mutex);
-               pval = kcontrol->private_value;
-               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch,
-                                                               0, dir);
-               ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-               kcontrol->private_value = pval;
-               mutex_unlock(&codec->control_mutex);
-       }
-
-       return ret;
-}
-/* End of control change helpers. */
-
-static void ca0132_alt_bass_redirection_xover_set(struct hda_codec *codec,
-               long idx)
-{
-       snd_hda_power_up(codec);
-
-       dspio_set_param(codec, 0x96, 0x20, SPEAKER_BASS_REDIRECT_XOVER_FREQ,
-                       &(float_xbass_xover_lookup[idx]), sizeof(unsigned int));
-
-       snd_hda_power_down(codec);
-}
-
-/*
- * Below I've added controls to mess with the effect levels, I've only enabled
- * them on the Sound Blaster Z, but they would probably also work on the
- * Chromebook. I figured they were probably tuned specifically for it, and left
- * out for a reason.
- */
-
-/* Sets DSP effect level from the sliders above the controls */
-
-static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid,
-                         const unsigned int *lookup, int idx)
-{
-       int i = 0;
-       unsigned int y;
-       /*
-        * For X_BASS, req 2 is actually crossover freq instead of
-        * effect level
-        */
-       if (nid == X_BASS)
-               y = 2;
-       else
-               y = 1;
-
-       snd_hda_power_up(codec);
-       if (nid == XBASS_XOVER) {
-               for (i = 0; i < OUT_EFFECTS_COUNT; i++)
-                       if (ca0132_effects[i].nid == X_BASS)
-                               break;
-
-               dspio_set_param(codec, ca0132_effects[i].mid, 0x20,
-                               ca0132_effects[i].reqs[1],
-                               &(lookup[idx - 1]), sizeof(unsigned int));
-       } else {
-               /* Find the actual effect structure */
-               for (i = 0; i < OUT_EFFECTS_COUNT; i++)
-                       if (nid == ca0132_effects[i].nid)
-                               break;
-
-               dspio_set_param(codec, ca0132_effects[i].mid, 0x20,
-                               ca0132_effects[i].reqs[y],
-                               &(lookup[idx]), sizeof(unsigned int));
-       }
-
-       snd_hda_power_down(codec);
-
-       return 0;
-}
-
-static int ca0132_alt_xbass_xover_slider_ctl_get(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       long *valp = ucontrol->value.integer.value;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-
-       if (nid == BASS_REDIRECTION_XOVER)
-               *valp = spec->bass_redirect_xover_freq;
-       else
-               *valp = spec->xbass_xover_freq;
-
-       return 0;
-}
-
-static int ca0132_alt_slider_ctl_get(struct snd_kcontrol *kcontrol,
-                         struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int idx = nid - OUT_EFFECT_START_NID;
-
-       *valp = spec->fx_ctl_val[idx];
-       return 0;
-}
-
-/*
- * The X-bass crossover starts at 10hz, so the min is 1. The
- * frequency is set in multiples of 10.
- */
-static int ca0132_alt_xbass_xover_slider_info(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 1;
-       uinfo->value.integer.max = 100;
-       uinfo->value.integer.step = 1;
-
-       return 0;
-}
-
-static int ca0132_alt_effect_slider_info(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_info *uinfo)
-{
-       int chs = get_amp_channels(kcontrol);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = chs == 3 ? 2 : 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 100;
-       uinfo->value.integer.step = 1;
-
-       return 0;
-}
-
-static int ca0132_alt_xbass_xover_slider_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       long *cur_val;
-       int idx;
-
-       if (nid == BASS_REDIRECTION_XOVER)
-               cur_val = &spec->bass_redirect_xover_freq;
-       else
-               cur_val = &spec->xbass_xover_freq;
-
-       /* any change? */
-       if (*cur_val == *valp)
-               return 0;
-
-       *cur_val = *valp;
-
-       idx = *valp;
-       if (nid == BASS_REDIRECTION_XOVER)
-               ca0132_alt_bass_redirection_xover_set(codec, *cur_val);
-       else
-               ca0132_alt_slider_ctl_set(codec, nid, float_xbass_xover_lookup, idx);
-
-       return 0;
-}
-
-static int ca0132_alt_effect_slider_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int idx;
-
-       idx = nid - EFFECT_START_NID;
-       /* any change? */
-       if (spec->fx_ctl_val[idx] == *valp)
-               return 0;
-
-       spec->fx_ctl_val[idx] = *valp;
-
-       idx = *valp;
-       ca0132_alt_slider_ctl_set(codec, nid, float_zero_to_one_lookup, idx);
-
-       return 0;
-}
-
-
-/*
- * Mic Boost Enum for alternative ca0132 codecs. I didn't like that the original
- * only has off or full 30 dB, and didn't like making a volume slider that has
- * traditional 0-100 in alsamixer that goes in big steps. I like enum better.
- */
-#define MIC_BOOST_NUM_OF_STEPS 4
-#define MIC_BOOST_ENUM_MAX_STRLEN 10
-
-static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       const char *sfx = "dB";
-       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = MIC_BOOST_NUM_OF_STEPS;
-       if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS)
-               uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1;
-       sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx);
-       strcpy(uinfo->value.enumerated.name, namestr);
-       return 0;
-}
-
-static int ca0132_alt_mic_boost_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->mic_boost_enum_val;
-       return 0;
-}
-
-static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = MIC_BOOST_NUM_OF_STEPS;
-
-       if (sel >= items)
-               return 0;
-
-       codec_dbg(codec, "ca0132_alt_mic_boost: boost=%d\n",
-                   sel);
-
-       spec->mic_boost_enum_val = sel;
-
-       if (spec->in_enum_val != REAR_LINE_IN)
-               ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val);
-
-       return 1;
-}
-
-/*
- * Sound BlasterX AE-5 Headphone Gain Controls.
- */
-#define AE5_HEADPHONE_GAIN_MAX 3
-static int ae5_headphone_gain_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       const char *sfx = " Ohms)";
-       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = AE5_HEADPHONE_GAIN_MAX;
-       if (uinfo->value.enumerated.item >= AE5_HEADPHONE_GAIN_MAX)
-               uinfo->value.enumerated.item = AE5_HEADPHONE_GAIN_MAX - 1;
-       sprintf(namestr, "%s %s",
-               ae5_headphone_gain_presets[uinfo->value.enumerated.item].name,
-               sfx);
-       strcpy(uinfo->value.enumerated.name, namestr);
-       return 0;
-}
-
-static int ae5_headphone_gain_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->ae5_headphone_gain_val;
-       return 0;
-}
-
-static int ae5_headphone_gain_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = AE5_HEADPHONE_GAIN_MAX;
-
-       if (sel >= items)
-               return 0;
-
-       codec_dbg(codec, "ae5_headphone_gain: boost=%d\n",
-                   sel);
-
-       spec->ae5_headphone_gain_val = sel;
-
-       if (spec->out_enum_val == HEADPHONE_OUT)
-               ae5_headphone_gain_set(codec, spec->ae5_headphone_gain_val);
-
-       return 1;
-}
-
-/*
- * Sound BlasterX AE-5 sound filter enumerated control.
- */
-#define AE5_SOUND_FILTER_MAX 3
-
-static int ae5_sound_filter_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = AE5_SOUND_FILTER_MAX;
-       if (uinfo->value.enumerated.item >= AE5_SOUND_FILTER_MAX)
-               uinfo->value.enumerated.item = AE5_SOUND_FILTER_MAX - 1;
-       sprintf(namestr, "%s",
-                       ae5_filter_presets[uinfo->value.enumerated.item].name);
-       strcpy(uinfo->value.enumerated.name, namestr);
-       return 0;
-}
-
-static int ae5_sound_filter_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->ae5_filter_val;
-       return 0;
-}
-
-static int ae5_sound_filter_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = AE5_SOUND_FILTER_MAX;
-
-       if (sel >= items)
-               return 0;
-
-       codec_dbg(codec, "ae5_sound_filter: %s\n",
-                       ae5_filter_presets[sel].name);
-
-       spec->ae5_filter_val = sel;
-
-       ca0113_mmio_command_set_type2(codec, 0x48, 0x07,
-                       ae5_filter_presets[sel].val);
-
-       return 1;
-}
-
-/*
- * Input Select Control for alternative ca0132 codecs. This exists because
- * front microphone has no auto-detect, and we need a way to set the rear
- * as line-in
- */
-static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS;
-       if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS)
-               uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1;
-       strcpy(uinfo->value.enumerated.name,
-                       in_src_str[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int ca0132_alt_input_source_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->in_enum_val;
-       return 0;
-}
-
-static int ca0132_alt_input_source_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = IN_SRC_NUM_OF_INPUTS;
-
-       /*
-        * The AE-7 has no front microphone, so limit items to 2: rear mic and
-        * line-in.
-        */
-       if (ca0132_quirk(spec) == QUIRK_AE7)
-               items = 2;
-
-       if (sel >= items)
-               return 0;
-
-       codec_dbg(codec, "ca0132_alt_input_select: sel=%d, preset=%s\n",
-                   sel, in_src_str[sel]);
-
-       spec->in_enum_val = sel;
-
-       ca0132_alt_select_in(codec);
-
-       return 1;
-}
-
-/* Sound Blaster Z Output Select Control */
-static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = NUM_OF_OUTPUTS;
-       if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS)
-               uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1;
-       strcpy(uinfo->value.enumerated.name,
-                       out_type_str[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int ca0132_alt_output_select_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->out_enum_val;
-       return 0;
-}
-
-static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = NUM_OF_OUTPUTS;
-       unsigned int auto_jack;
-
-       if (sel >= items)
-               return 0;
-
-       codec_dbg(codec, "ca0132_alt_output_select: sel=%d, preset=%s\n",
-                   sel, out_type_str[sel]);
-
-       spec->out_enum_val = sel;
-
-       auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID];
-
-       if (!auto_jack)
-               ca0132_alt_select_out(codec);
-
-       return 1;
-}
-
-/* Select surround output type: 2.1, 4.0, 4.1, or 5.1. */
-static int ca0132_alt_speaker_channel_cfg_get_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       unsigned int items = SPEAKER_CHANNEL_CFG_COUNT;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = items;
-       if (uinfo->value.enumerated.item >= items)
-               uinfo->value.enumerated.item = items - 1;
-       strcpy(uinfo->value.enumerated.name,
-                       speaker_channel_cfgs[uinfo->value.enumerated.item].name);
-       return 0;
-}
-
-static int ca0132_alt_speaker_channel_cfg_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->channel_cfg_val;
-       return 0;
-}
-
-static int ca0132_alt_speaker_channel_cfg_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = SPEAKER_CHANNEL_CFG_COUNT;
-
-       if (sel >= items)
-               return 0;
-
-       codec_dbg(codec, "ca0132_alt_speaker_channels: sel=%d, channels=%s\n",
-                   sel, speaker_channel_cfgs[sel].name);
-
-       spec->channel_cfg_val = sel;
-
-       if (spec->out_enum_val == SPEAKER_OUT)
-               ca0132_alt_select_out(codec);
-
-       return 1;
-}
-
-/*
- * Smart Volume output setting control. Three different settings, Normal,
- * which takes the value from the smart volume slider. The two others, loud
- * and night, disregard the slider value and have uneditable values.
- */
-#define NUM_OF_SVM_SETTINGS 3
-static const char *const out_svm_set_enum_str[3] = {"Normal", "Loud", "Night" };
-
-static int ca0132_alt_svm_setting_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = NUM_OF_SVM_SETTINGS;
-       if (uinfo->value.enumerated.item >= NUM_OF_SVM_SETTINGS)
-               uinfo->value.enumerated.item = NUM_OF_SVM_SETTINGS - 1;
-       strcpy(uinfo->value.enumerated.name,
-                       out_svm_set_enum_str[uinfo->value.enumerated.item]);
-       return 0;
-}
-
-static int ca0132_alt_svm_setting_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->smart_volume_setting;
-       return 0;
-}
-
-static int ca0132_alt_svm_setting_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = NUM_OF_SVM_SETTINGS;
-       unsigned int idx = SMART_VOLUME - EFFECT_START_NID;
-       unsigned int tmp;
-
-       if (sel >= items)
-               return 0;
-
-       codec_dbg(codec, "ca0132_alt_svm_setting: sel=%d, preset=%s\n",
-                   sel, out_svm_set_enum_str[sel]);
-
-       spec->smart_volume_setting = sel;
-
-       switch (sel) {
-       case 0:
-               tmp = FLOAT_ZERO;
-               break;
-       case 1:
-               tmp = FLOAT_ONE;
-               break;
-       case 2:
-               tmp = FLOAT_TWO;
-               break;
-       default:
-               tmp = FLOAT_ZERO;
-               break;
-       }
-       /* Req 2 is the Smart Volume Setting req. */
-       dspio_set_uint_param(codec, ca0132_effects[idx].mid,
-                       ca0132_effects[idx].reqs[2], tmp);
-       return 1;
-}
-
-/* Sound Blaster Z EQ preset controls */
-static int ca0132_alt_eq_preset_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       unsigned int items = ARRAY_SIZE(ca0132_alt_eq_presets);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = items;
-       if (uinfo->value.enumerated.item >= items)
-               uinfo->value.enumerated.item = items - 1;
-       strcpy(uinfo->value.enumerated.name,
-               ca0132_alt_eq_presets[uinfo->value.enumerated.item].name);
-       return 0;
-}
-
-static int ca0132_alt_eq_preset_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->eq_preset_val;
-       return 0;
-}
-
-static int ca0132_alt_eq_preset_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int i, err = 0;
-       int sel = ucontrol->value.enumerated.item[0];
-       unsigned int items = ARRAY_SIZE(ca0132_alt_eq_presets);
-
-       if (sel >= items)
-               return 0;
-
-       codec_dbg(codec, "%s: sel=%d, preset=%s\n", __func__, sel,
-                       ca0132_alt_eq_presets[sel].name);
-       /*
-        * Idx 0 is default.
-        * Default needs to qualify with CrystalVoice state.
-        */
-       for (i = 0; i < EQ_PRESET_MAX_PARAM_COUNT; i++) {
-               err = dspio_set_uint_param(codec, ca0132_alt_eq_enum.mid,
-                               ca0132_alt_eq_enum.reqs[i],
-                               ca0132_alt_eq_presets[sel].vals[i]);
-               if (err < 0)
-                       break;
-       }
-
-       if (err >= 0)
-               spec->eq_preset_val = sel;
-
-       return 1;
-}
-
-static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       unsigned int items = ARRAY_SIZE(ca0132_voicefx_presets);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = items;
-       if (uinfo->value.enumerated.item >= items)
-               uinfo->value.enumerated.item = items - 1;
-       strcpy(uinfo->value.enumerated.name,
-              ca0132_voicefx_presets[uinfo->value.enumerated.item].name);
-       return 0;
-}
-
-static int ca0132_voicefx_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->voicefx_val;
-       return 0;
-}
-
-static int ca0132_voicefx_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       int i, err = 0;
-       int sel = ucontrol->value.enumerated.item[0];
-
-       if (sel >= ARRAY_SIZE(ca0132_voicefx_presets))
-               return 0;
-
-       codec_dbg(codec, "ca0132_voicefx_put: sel=%d, preset=%s\n",
-                   sel, ca0132_voicefx_presets[sel].name);
-
-       /*
-        * Idx 0 is default.
-        * Default needs to qualify with CrystalVoice state.
-        */
-       for (i = 0; i < VOICEFX_MAX_PARAM_COUNT; i++) {
-               err = dspio_set_uint_param(codec, ca0132_voicefx.mid,
-                               ca0132_voicefx.reqs[i],
-                               ca0132_voicefx_presets[sel].vals[i]);
-               if (err < 0)
-                       break;
-       }
-
-       if (err >= 0) {
-               spec->voicefx_val = sel;
-               /* enable voice fx */
-               ca0132_voicefx_set(codec, (sel ? 1 : 0));
-       }
-
-       return 1;
-}
-
-static int ca0132_switch_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       int ch = get_amp_channels(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-
-       /* vnode */
-       if ((nid >= VNODE_START_NID) && (nid < VNODE_END_NID)) {
-               if (ch & 1) {
-                       *valp = spec->vnode_lswitch[nid - VNODE_START_NID];
-                       valp++;
-               }
-               if (ch & 2) {
-                       *valp = spec->vnode_rswitch[nid - VNODE_START_NID];
-                       valp++;
-               }
-               return 0;
-       }
-
-       /* effects, include PE and CrystalVoice */
-       if ((nid >= EFFECT_START_NID) && (nid < EFFECT_END_NID)) {
-               *valp = spec->effects_switch[nid - EFFECT_START_NID];
-               return 0;
-       }
-
-       /* mic boost */
-       if (nid == spec->input_pins[0]) {
-               *valp = spec->cur_mic_boost;
-               return 0;
-       }
-
-       if (nid == ZXR_HEADPHONE_GAIN) {
-               *valp = spec->zxr_gain_set;
-               return 0;
-       }
-
-       if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) {
-               *valp = spec->speaker_range_val[nid - SPEAKER_FULL_RANGE_FRONT];
-               return 0;
-       }
-
-       if (nid == BASS_REDIRECTION) {
-               *valp = spec->bass_redirection_val;
-               return 0;
-       }
-
-       return 0;
-}
-
-static int ca0132_switch_put(struct snd_kcontrol *kcontrol,
-                            struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       int ch = get_amp_channels(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       int changed = 1;
-
-       codec_dbg(codec, "ca0132_switch_put: nid=0x%x, val=%ld\n",
-                   nid, *valp);
-
-       snd_hda_power_up(codec);
-       /* vnode */
-       if ((nid >= VNODE_START_NID) && (nid < VNODE_END_NID)) {
-               if (ch & 1) {
-                       spec->vnode_lswitch[nid - VNODE_START_NID] = *valp;
-                       valp++;
-               }
-               if (ch & 2) {
-                       spec->vnode_rswitch[nid - VNODE_START_NID] = *valp;
-                       valp++;
-               }
-               changed = ca0132_vnode_switch_set(kcontrol, ucontrol);
-               goto exit;
-       }
-
-       /* PE */
-       if (nid == PLAY_ENHANCEMENT) {
-               spec->effects_switch[nid - EFFECT_START_NID] = *valp;
-               changed = ca0132_pe_switch_set(codec);
-               goto exit;
-       }
-
-       /* CrystalVoice */
-       if (nid == CRYSTAL_VOICE) {
-               spec->effects_switch[nid - EFFECT_START_NID] = *valp;
-               changed = ca0132_cvoice_switch_set(codec);
-               goto exit;
-       }
-
-       /* out and in effects */
-       if (((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) ||
-           ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID))) {
-               spec->effects_switch[nid - EFFECT_START_NID] = *valp;
-               changed = ca0132_effects_set(codec, nid, *valp);
-               goto exit;
-       }
-
-       /* mic boost */
-       if (nid == spec->input_pins[0]) {
-               spec->cur_mic_boost = *valp;
-               if (ca0132_use_alt_functions(spec)) {
-                       if (spec->in_enum_val != REAR_LINE_IN)
-                               changed = ca0132_mic_boost_set(codec, *valp);
-               } else {
-                       /* Mic boost does not apply to Digital Mic */
-                       if (spec->cur_mic_type != DIGITAL_MIC)
-                               changed = ca0132_mic_boost_set(codec, *valp);
-               }
-
-               goto exit;
-       }
-
-       if (nid == ZXR_HEADPHONE_GAIN) {
-               spec->zxr_gain_set = *valp;
-               if (spec->cur_out_type == HEADPHONE_OUT)
-                       changed = zxr_headphone_gain_set(codec, *valp);
-               else
-                       changed = 0;
-
-               goto exit;
-       }
-
-       if (nid == SPEAKER_FULL_RANGE_FRONT || nid == SPEAKER_FULL_RANGE_REAR) {
-               spec->speaker_range_val[nid - SPEAKER_FULL_RANGE_FRONT] = *valp;
-               if (spec->cur_out_type == SPEAKER_OUT)
-                       ca0132_alt_set_full_range_speaker(codec);
-
-               changed = 0;
-       }
-
-       if (nid == BASS_REDIRECTION) {
-               spec->bass_redirection_val = *valp;
-               if (spec->cur_out_type == SPEAKER_OUT)
-                       ca0132_alt_surround_set_bass_redirection(codec, *valp);
-
-               changed = 0;
-       }
-
-exit:
-       snd_hda_power_down(codec);
-       return changed;
-}
-
-/*
- * Volume related
- */
-/*
- * Sets the internal DSP decibel level to match the DAC for output, and the
- * ADC for input. Currently only the SBZ sets dsp capture volume level, and
- * all alternative codecs set DSP playback volume.
- */
-static void ca0132_alt_dsp_volume_put(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int dsp_dir;
-       unsigned int lookup_val;
-
-       if (nid == VNID_SPK)
-               dsp_dir = DSP_VOL_OUT;
-       else
-               dsp_dir = DSP_VOL_IN;
-
-       lookup_val = spec->vnode_lvol[nid - VNODE_START_NID];
-
-       dspio_set_uint_param(codec,
-               ca0132_alt_vol_ctls[dsp_dir].mid,
-               ca0132_alt_vol_ctls[dsp_dir].reqs[0],
-               float_vol_db_lookup[lookup_val]);
-
-       lookup_val = spec->vnode_rvol[nid - VNODE_START_NID];
-
-       dspio_set_uint_param(codec,
-               ca0132_alt_vol_ctls[dsp_dir].mid,
-               ca0132_alt_vol_ctls[dsp_dir].reqs[1],
-               float_vol_db_lookup[lookup_val]);
-
-       dspio_set_uint_param(codec,
-               ca0132_alt_vol_ctls[dsp_dir].mid,
-               ca0132_alt_vol_ctls[dsp_dir].reqs[2], FLOAT_ZERO);
-}
-
-static int ca0132_volume_info(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       int ch = get_amp_channels(kcontrol);
-       int dir = get_amp_direction(kcontrol);
-       unsigned long pval;
-       int err;
-
-       switch (nid) {
-       case VNID_SPK:
-               /* follow shared_out info */
-               nid = spec->shared_out_nid;
-               mutex_lock(&codec->control_mutex);
-               pval = kcontrol->private_value;
-               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
-               err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
-               kcontrol->private_value = pval;
-               mutex_unlock(&codec->control_mutex);
-               break;
-       case VNID_MIC:
-               /* follow shared_mic info */
-               nid = spec->shared_mic_nid;
-               mutex_lock(&codec->control_mutex);
-               pval = kcontrol->private_value;
-               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
-               err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
-               kcontrol->private_value = pval;
-               mutex_unlock(&codec->control_mutex);
-               break;
-       default:
-               err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo);
-       }
-       return err;
-}
-
-static int ca0132_volume_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       int ch = get_amp_channels(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-
-       /* store the left and right volume */
-       if (ch & 1) {
-               *valp = spec->vnode_lvol[nid - VNODE_START_NID];
-               valp++;
-       }
-       if (ch & 2) {
-               *valp = spec->vnode_rvol[nid - VNODE_START_NID];
-               valp++;
-       }
-       return 0;
-}
-
-static int ca0132_volume_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       int ch = get_amp_channels(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       hda_nid_t shared_nid = 0;
-       bool effective;
-       int changed = 1;
-
-       /* store the left and right volume */
-       if (ch & 1) {
-               spec->vnode_lvol[nid - VNODE_START_NID] = *valp;
-               valp++;
-       }
-       if (ch & 2) {
-               spec->vnode_rvol[nid - VNODE_START_NID] = *valp;
-               valp++;
-       }
-
-       /* if effective conditions, then update hw immediately. */
-       effective = ca0132_is_vnode_effective(codec, nid, &shared_nid);
-       if (effective) {
-               int dir = get_amp_direction(kcontrol);
-               unsigned long pval;
-
-               snd_hda_power_up(codec);
-               mutex_lock(&codec->control_mutex);
-               pval = kcontrol->private_value;
-               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch,
-                                                               0, dir);
-               changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
-               kcontrol->private_value = pval;
-               mutex_unlock(&codec->control_mutex);
-               snd_hda_power_down(codec);
-       }
-
-       return changed;
-}
-
-/*
- * This function is the same as the one above, because using an if statement
- * inside of the above volume control for the DSP volume would cause too much
- * lag. This is a lot more smooth.
- */
-static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       int ch = get_amp_channels(kcontrol);
-       long *valp = ucontrol->value.integer.value;
-       hda_nid_t vnid = 0;
-       int changed;
-
-       switch (nid) {
-       case 0x02:
-               vnid = VNID_SPK;
-               break;
-       case 0x07:
-               vnid = VNID_MIC;
-               break;
-       }
-
-       /* store the left and right volume */
-       if (ch & 1) {
-               spec->vnode_lvol[vnid - VNODE_START_NID] = *valp;
-               valp++;
-       }
-       if (ch & 2) {
-               spec->vnode_rvol[vnid - VNODE_START_NID] = *valp;
-               valp++;
-       }
-
-       snd_hda_power_up(codec);
-       ca0132_alt_dsp_volume_put(codec, vnid);
-       mutex_lock(&codec->control_mutex);
-       changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
-       mutex_unlock(&codec->control_mutex);
-       snd_hda_power_down(codec);
-
-       return changed;
-}
-
-static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag,
-                            unsigned int size, unsigned int __user *tlv)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct ca0132_spec *spec = codec->spec;
-       hda_nid_t nid = get_amp_nid(kcontrol);
-       int ch = get_amp_channels(kcontrol);
-       int dir = get_amp_direction(kcontrol);
-       unsigned long pval;
-       int err;
-
-       switch (nid) {
-       case VNID_SPK:
-               /* follow shared_out tlv */
-               nid = spec->shared_out_nid;
-               mutex_lock(&codec->control_mutex);
-               pval = kcontrol->private_value;
-               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
-               err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
-               kcontrol->private_value = pval;
-               mutex_unlock(&codec->control_mutex);
-               break;
-       case VNID_MIC:
-               /* follow shared_mic tlv */
-               nid = spec->shared_mic_nid;
-               mutex_lock(&codec->control_mutex);
-               pval = kcontrol->private_value;
-               kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir);
-               err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
-               kcontrol->private_value = pval;
-               mutex_unlock(&codec->control_mutex);
-               break;
-       default:
-               err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv);
-       }
-       return err;
-}
-
-/* Add volume slider control for effect level */
-static int ca0132_alt_add_effect_slider(struct hda_codec *codec, hda_nid_t nid,
-                                       const char *pfx, int dir)
-{
-       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       int type = dir ? HDA_INPUT : HDA_OUTPUT;
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type);
-
-       sprintf(namestr, "FX: %s %s Volume", pfx, dirstr[dir]);
-
-       knew.tlv.c = NULL;
-
-       switch (nid) {
-       case XBASS_XOVER:
-               knew.info = ca0132_alt_xbass_xover_slider_info;
-               knew.get = ca0132_alt_xbass_xover_slider_ctl_get;
-               knew.put = ca0132_alt_xbass_xover_slider_put;
-               break;
-       default:
-               knew.info = ca0132_alt_effect_slider_info;
-               knew.get = ca0132_alt_slider_ctl_get;
-               knew.put = ca0132_alt_effect_slider_put;
-               knew.private_value =
-                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, type);
-               break;
-       }
-
-       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Added FX: prefix for the alternative codecs, because otherwise the surround
- * effect would conflict with the Surround sound volume control. Also seems more
- * clear as to what the switches do. Left alone for others.
- */
-static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid,
-                        const char *pfx, int dir)
-{
-       struct ca0132_spec *spec = codec->spec;
-       char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
-       int type = dir ? HDA_INPUT : HDA_OUTPUT;
-       struct snd_kcontrol_new knew =
-               CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type);
-       /* If using alt_controls, add FX: prefix. But, don't add FX:
-        * prefix to OutFX or InFX enable controls.
-        */
-       if (ca0132_use_alt_controls(spec) && (nid <= IN_EFFECT_END_NID))
-               sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]);
-       else
-               sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]);
-
-       return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec));
-}
-
-static int add_voicefx(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO(ca0132_voicefx.name,
-                                   VOICEFX, 1, 0, HDA_INPUT);
-       knew.info = ca0132_voicefx_info;
-       knew.get = ca0132_voicefx_get;
-       knew.put = ca0132_voicefx_put;
-       return snd_hda_ctl_add(codec, VOICEFX, snd_ctl_new1(&knew, codec));
-}
-
-/* Create the EQ Preset control */
-static int add_ca0132_alt_eq_presets(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO(ca0132_alt_eq_enum.name,
-                                   EQ_PRESET_ENUM, 1, 0, HDA_OUTPUT);
-       knew.info = ca0132_alt_eq_preset_info;
-       knew.get = ca0132_alt_eq_preset_get;
-       knew.put = ca0132_alt_eq_preset_put;
-       return snd_hda_ctl_add(codec, EQ_PRESET_ENUM,
-                               snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Add enumerated control for the three different settings of the smart volume
- * output effect. Normal just uses the slider value, and loud and night are
- * their own things that ignore that value.
- */
-static int ca0132_alt_add_svm_enum(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO("FX: Smart Volume Setting",
-                                   SMART_VOLUME_ENUM, 1, 0, HDA_OUTPUT);
-       knew.info = ca0132_alt_svm_setting_info;
-       knew.get = ca0132_alt_svm_setting_get;
-       knew.put = ca0132_alt_svm_setting_put;
-       return snd_hda_ctl_add(codec, SMART_VOLUME_ENUM,
-                               snd_ctl_new1(&knew, codec));
-
-}
-
-/*
- * Create an Output Select enumerated control for codecs with surround
- * out capabilities.
- */
-static int ca0132_alt_add_output_enum(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO("Output Select",
-                                   OUTPUT_SOURCE_ENUM, 1, 0, HDA_OUTPUT);
-       knew.info = ca0132_alt_output_select_get_info;
-       knew.get = ca0132_alt_output_select_get;
-       knew.put = ca0132_alt_output_select_put;
-       return snd_hda_ctl_add(codec, OUTPUT_SOURCE_ENUM,
-                               snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Add a control for selecting channel count on speaker output. Setting this
- * allows the DSP to do bass redirection and channel upmixing on surround
- * configurations.
- */
-static int ca0132_alt_add_speaker_channel_cfg_enum(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO("Surround Channel Config",
-                                   SPEAKER_CHANNEL_CFG_ENUM, 1, 0, HDA_OUTPUT);
-       knew.info = ca0132_alt_speaker_channel_cfg_get_info;
-       knew.get = ca0132_alt_speaker_channel_cfg_get;
-       knew.put = ca0132_alt_speaker_channel_cfg_put;
-       return snd_hda_ctl_add(codec, SPEAKER_CHANNEL_CFG_ENUM,
-                               snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Full range front stereo and rear surround switches. When these are set to
- * full range, the lower frequencies from these channels are no longer
- * redirected to the LFE channel.
- */
-static int ca0132_alt_add_front_full_range_switch(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               CA0132_CODEC_MUTE_MONO("Full-Range Front Speakers",
-                                   SPEAKER_FULL_RANGE_FRONT, 1, HDA_OUTPUT);
-
-       return snd_hda_ctl_add(codec, SPEAKER_FULL_RANGE_FRONT,
-                               snd_ctl_new1(&knew, codec));
-}
-
-static int ca0132_alt_add_rear_full_range_switch(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               CA0132_CODEC_MUTE_MONO("Full-Range Rear Speakers",
-                                   SPEAKER_FULL_RANGE_REAR, 1, HDA_OUTPUT);
-
-       return snd_hda_ctl_add(codec, SPEAKER_FULL_RANGE_REAR,
-                               snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Bass redirection redirects audio below the crossover frequency to the LFE
- * channel on speakers that are set as not being full-range. On configurations
- * without an LFE channel, it does nothing. Bass redirection seems to be the
- * replacement for X-Bass on configurations with an LFE channel.
- */
-static int ca0132_alt_add_bass_redirection_crossover(struct hda_codec *codec)
-{
-       const char *namestr = "Bass Redirection Crossover";
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_VOLUME_MONO(namestr, BASS_REDIRECTION_XOVER, 1, 0,
-                               HDA_OUTPUT);
-
-       knew.tlv.c = NULL;
-       knew.info = ca0132_alt_xbass_xover_slider_info;
-       knew.get = ca0132_alt_xbass_xover_slider_ctl_get;
-       knew.put = ca0132_alt_xbass_xover_slider_put;
-
-       return snd_hda_ctl_add(codec, BASS_REDIRECTION_XOVER,
-                       snd_ctl_new1(&knew, codec));
-}
-
-static int ca0132_alt_add_bass_redirection_switch(struct hda_codec *codec)
-{
-       const char *namestr = "Bass Redirection";
-       struct snd_kcontrol_new knew =
-               CA0132_CODEC_MUTE_MONO(namestr, BASS_REDIRECTION, 1,
-                               HDA_OUTPUT);
-
-       return snd_hda_ctl_add(codec, BASS_REDIRECTION,
-                       snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Create an Input Source enumerated control for the alternate ca0132 codecs
- * because the front microphone has no auto-detect, and Line-in has to be set
- * somehow.
- */
-static int ca0132_alt_add_input_enum(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO("Input Source",
-                                   INPUT_SOURCE_ENUM, 1, 0, HDA_INPUT);
-       knew.info = ca0132_alt_input_source_info;
-       knew.get = ca0132_alt_input_source_get;
-       knew.put = ca0132_alt_input_source_put;
-       return snd_hda_ctl_add(codec, INPUT_SOURCE_ENUM,
-                               snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Add mic boost enumerated control. Switches through 0dB to 30dB. This adds
- * more control than the original mic boost, which is either full 30dB or off.
- */
-static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO("Mic Boost Capture Switch",
-                                   MIC_BOOST_ENUM, 1, 0, HDA_INPUT);
-       knew.info = ca0132_alt_mic_boost_info;
-       knew.get = ca0132_alt_mic_boost_get;
-       knew.put = ca0132_alt_mic_boost_put;
-       return snd_hda_ctl_add(codec, MIC_BOOST_ENUM,
-                               snd_ctl_new1(&knew, codec));
-
-}
-
-/*
- * Add headphone gain enumerated control for the AE-5. This switches between
- * three modes, low, medium, and high. When non-headphone outputs are selected,
- * it is automatically set to high. This is the same behavior as Windows.
- */
-static int ae5_add_headphone_gain_enum(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO("AE-5: Headphone Gain",
-                                   AE5_HEADPHONE_GAIN_ENUM, 1, 0, HDA_OUTPUT);
-       knew.info = ae5_headphone_gain_info;
-       knew.get = ae5_headphone_gain_get;
-       knew.put = ae5_headphone_gain_put;
-       return snd_hda_ctl_add(codec, AE5_HEADPHONE_GAIN_ENUM,
-                               snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Add sound filter enumerated control for the AE-5. This adds three different
- * settings: Slow Roll Off, Minimum Phase, and Fast Roll Off. From what I've
- * read into it, it changes the DAC's interpolation filter.
- */
-static int ae5_add_sound_filter_enum(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               HDA_CODEC_MUTE_MONO("AE-5: Sound Filter",
-                                   AE5_SOUND_FILTER_ENUM, 1, 0, HDA_OUTPUT);
-       knew.info = ae5_sound_filter_info;
-       knew.get = ae5_sound_filter_get;
-       knew.put = ae5_sound_filter_put;
-       return snd_hda_ctl_add(codec, AE5_SOUND_FILTER_ENUM,
-                               snd_ctl_new1(&knew, codec));
-}
-
-static int zxr_add_headphone_gain_switch(struct hda_codec *codec)
-{
-       struct snd_kcontrol_new knew =
-               CA0132_CODEC_MUTE_MONO("ZxR: 600 Ohm Gain",
-                                   ZXR_HEADPHONE_GAIN, 1, HDA_OUTPUT);
-
-       return snd_hda_ctl_add(codec, ZXR_HEADPHONE_GAIN,
-                               snd_ctl_new1(&knew, codec));
-}
-
-/*
- * Need to create follower controls for the alternate codecs that have surround
- * capabilities.
- */
-static const char * const ca0132_alt_follower_pfxs[] = {
-       "Front", "Surround", "Center", "LFE", NULL,
-};
-
-/*
- * Also need special channel map, because the default one is incorrect.
- * I think this has to do with the pin for rear surround being 0x11,
- * and the center/lfe being 0x10. Usually the pin order is the opposite.
- */
-static const struct snd_pcm_chmap_elem ca0132_alt_chmaps[] = {
-       { .channels = 2,
-         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
-       { .channels = 4,
-         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
-                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
-       { .channels = 6,
-         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
-                  SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
-                  SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
-       { }
-};
-
-/* Add the correct chmap for streams with 6 channels. */
-static void ca0132_alt_add_chmap_ctls(struct hda_codec *codec)
-{
-       int err = 0;
-       struct hda_pcm *pcm;
-
-       list_for_each_entry(pcm, &codec->pcm_list_head, list) {
-               struct hda_pcm_stream *hinfo =
-                       &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
-               struct snd_pcm_chmap *chmap;
-               const struct snd_pcm_chmap_elem *elem;
-
-               elem = ca0132_alt_chmaps;
-               if (hinfo->channels_max == 6) {
-                       err = snd_pcm_add_chmap_ctls(pcm->pcm,
-                                       SNDRV_PCM_STREAM_PLAYBACK,
-                                       elem, hinfo->channels_max, 0, &chmap);
-                       if (err < 0)
-                               codec_dbg(codec, "snd_pcm_add_chmap_ctls failed!");
-               }
-       }
-}
-
-/*
- * When changing Node IDs for Mixer Controls below, make sure to update
- * Node IDs in ca0132_config() as well.
- */
-static const struct snd_kcontrol_new ca0132_mixer[] = {
-       CA0132_CODEC_VOL("Master Playback Volume", VNID_SPK, HDA_OUTPUT),
-       CA0132_CODEC_MUTE("Master Playback Switch", VNID_SPK, HDA_OUTPUT),
-       CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT),
-       CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
-       HDA_CODEC_VOLUME("Analog-Mic2 Capture Volume", 0x08, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("Analog-Mic2 Capture Switch", 0x08, 0, HDA_INPUT),
-       HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT),
-       CA0132_CODEC_MUTE_MONO("Mic1-Boost (30dB) Capture Switch",
-                              0x12, 1, HDA_INPUT),
-       CA0132_CODEC_MUTE_MONO("HP/Speaker Playback Switch",
-                              VNID_HP_SEL, 1, HDA_OUTPUT),
-       CA0132_CODEC_MUTE_MONO("AMic1/DMic Capture Switch",
-                              VNID_AMIC1_SEL, 1, HDA_INPUT),
-       CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch",
-                              VNID_HP_ASEL, 1, HDA_OUTPUT),
-       CA0132_CODEC_MUTE_MONO("AMic1/DMic Auto Detect Capture Switch",
-                              VNID_AMIC1_ASEL, 1, HDA_INPUT),
-       { } /* end */
-};
-
-/*
- * Desktop specific control mixer. Removes auto-detect for mic, and adds
- * surround controls. Also sets both the Front Playback and Capture Volume
- * controls to alt so they set the DSP's decibel level.
- */
-static const struct snd_kcontrol_new desktop_mixer[] = {
-       CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
-       CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT),
-       CA0132_ALT_CODEC_VOL("Capture Volume", 0x07, HDA_INPUT),
-       CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
-       HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT),
-       CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch",
-                               VNID_HP_ASEL, 1, HDA_OUTPUT),
-       { } /* end */
-};
-
-/*
- * Same as the Sound Blaster Z, except doesn't use the alt volume for capture
- * because it doesn't set decibel levels for the DSP for capture.
- */
-static const struct snd_kcontrol_new r3di_mixer[] = {
-       CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT),
-       CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT),
-       HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT),
-       HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT),
-       CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT),
-       CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT),
-       HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT),
-       HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT),
-       CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch",
-                               VNID_HP_ASEL, 1, HDA_OUTPUT),
-       { } /* end */
-};
-
-static int ca0132_build_controls(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int i, num_fx, num_sliders;
-       int err = 0;
-
-       /* Add Mixer controls */
-       for (i = 0; i < spec->num_mixers; i++) {
-               err = snd_hda_add_new_ctls(codec, spec->mixers[i]);
-               if (err < 0)
-                       return err;
-       }
-       /* Setup vmaster with surround followers for desktop ca0132 devices */
-       if (ca0132_use_alt_functions(spec)) {
-               snd_hda_set_vmaster_tlv(codec, spec->dacs[0], HDA_OUTPUT,
-                                       spec->tlv);
-               snd_hda_add_vmaster(codec, "Master Playback Volume",
-                                       spec->tlv, ca0132_alt_follower_pfxs,
-                                       "Playback Volume", 0);
-               err = __snd_hda_add_vmaster(codec, "Master Playback Switch",
-                                           NULL, ca0132_alt_follower_pfxs,
-                                           "Playback Switch",
-                                           true, 0, &spec->vmaster_mute.sw_kctl);
-               if (err < 0)
-                       return err;
-       }
-
-       /* Add in and out effects controls.
-        * VoiceFX, PE and CrystalVoice are added separately.
-        */
-       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
-       for (i = 0; i < num_fx; i++) {
-               /* Desktop cards break if Echo Cancellation is used. */
-               if (ca0132_use_pci_mmio(spec)) {
-                       if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID +
-                                               OUT_EFFECTS_COUNT))
-                               continue;
-               }
-
-               err = add_fx_switch(codec, ca0132_effects[i].nid,
-                                   ca0132_effects[i].name,
-                                   ca0132_effects[i].direct);
-               if (err < 0)
-                       return err;
-       }
-       /*
-        * If codec has use_alt_controls set to true, add effect level sliders,
-        * EQ presets, and Smart Volume presets. Also, change names to add FX
-        * prefix, and change PlayEnhancement and CrystalVoice to match.
-        */
-       if (ca0132_use_alt_controls(spec)) {
-               err = ca0132_alt_add_svm_enum(codec);
-               if (err < 0)
-                       return err;
-
-               err = add_ca0132_alt_eq_presets(codec);
-               if (err < 0)
-                       return err;
-
-               err = add_fx_switch(codec, PLAY_ENHANCEMENT,
-                                       "Enable OutFX", 0);
-               if (err < 0)
-                       return err;
-
-               err = add_fx_switch(codec, CRYSTAL_VOICE,
-                                       "Enable InFX", 1);
-               if (err < 0)
-                       return err;
-
-               num_sliders = OUT_EFFECTS_COUNT - 1;
-               for (i = 0; i < num_sliders; i++) {
-                       err = ca0132_alt_add_effect_slider(codec,
-                                           ca0132_effects[i].nid,
-                                           ca0132_effects[i].name,
-                                           ca0132_effects[i].direct);
-                       if (err < 0)
-                               return err;
-               }
-
-               err = ca0132_alt_add_effect_slider(codec, XBASS_XOVER,
-                                       "X-Bass Crossover", EFX_DIR_OUT);
-
-               if (err < 0)
-                       return err;
-       } else {
-               err = add_fx_switch(codec, PLAY_ENHANCEMENT,
-                                       "PlayEnhancement", 0);
-               if (err < 0)
-                       return err;
-
-               err = add_fx_switch(codec, CRYSTAL_VOICE,
-                                       "CrystalVoice", 1);
-               if (err < 0)
-                       return err;
-       }
-       err = add_voicefx(codec);
-       if (err < 0)
-               return err;
-
-       /*
-        * If the codec uses alt_functions, you need the enumerated controls
-        * to select the new outputs and inputs, plus add the new mic boost
-        * setting control.
-        */
-       if (ca0132_use_alt_functions(spec)) {
-               err = ca0132_alt_add_output_enum(codec);
-               if (err < 0)
-                       return err;
-               err = ca0132_alt_add_speaker_channel_cfg_enum(codec);
-               if (err < 0)
-                       return err;
-               err = ca0132_alt_add_front_full_range_switch(codec);
-               if (err < 0)
-                       return err;
-               err = ca0132_alt_add_rear_full_range_switch(codec);
-               if (err < 0)
-                       return err;
-               err = ca0132_alt_add_bass_redirection_crossover(codec);
-               if (err < 0)
-                       return err;
-               err = ca0132_alt_add_bass_redirection_switch(codec);
-               if (err < 0)
-                       return err;
-               err = ca0132_alt_add_mic_boost_enum(codec);
-               if (err < 0)
-                       return err;
-               /*
-                * ZxR only has microphone input, there is no front panel
-                * header on the card, and aux-in is handled by the DBPro board.
-                */
-               if (ca0132_quirk(spec) != QUIRK_ZXR) {
-                       err = ca0132_alt_add_input_enum(codec);
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_AE5:
-       case QUIRK_AE7:
-               err = ae5_add_headphone_gain_enum(codec);
-               if (err < 0)
-                       return err;
-               err = ae5_add_sound_filter_enum(codec);
-               if (err < 0)
-                       return err;
-               break;
-       case QUIRK_ZXR:
-               err = zxr_add_headphone_gain_switch(codec);
-               if (err < 0)
-                       return err;
-               break;
-       default:
-               break;
-       }
-
-#ifdef ENABLE_TUNING_CONTROLS
-       add_tuning_ctls(codec);
-#endif
-
-       err = snd_hda_jack_add_kctls(codec, &spec->autocfg);
-       if (err < 0)
-               return err;
-
-       if (spec->dig_out) {
-               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
-                                                   spec->dig_out);
-               if (err < 0)
-                       return err;
-               err = snd_hda_create_spdif_share_sw(codec, &spec->multiout);
-               if (err < 0)
-                       return err;
-               /* spec->multiout.share_spdif = 1; */
-       }
-
-       if (spec->dig_in) {
-               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
-               if (err < 0)
-                       return err;
-       }
-
-       if (ca0132_use_alt_functions(spec))
-               ca0132_alt_add_chmap_ctls(codec);
-
-       return 0;
-}
-
-static int dbpro_build_controls(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int err = 0;
-
-       if (spec->dig_out) {
-               err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out,
-                               spec->dig_out);
-               if (err < 0)
-                       return err;
-       }
-
-       if (spec->dig_in) {
-               err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-/*
- * PCM
- */
-static const struct hda_pcm_stream ca0132_pcm_analog_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 6,
-       .ops = {
-               .prepare = ca0132_playback_pcm_prepare,
-               .cleanup = ca0132_playback_pcm_cleanup,
-               .get_delay = ca0132_playback_pcm_delay,
-       },
-};
-
-static const struct hda_pcm_stream ca0132_pcm_analog_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .ops = {
-               .prepare = ca0132_capture_pcm_prepare,
-               .cleanup = ca0132_capture_pcm_cleanup,
-               .get_delay = ca0132_capture_pcm_delay,
-       },
-};
-
-static const struct hda_pcm_stream ca0132_pcm_digital_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .ops = {
-               .open = ca0132_dig_playback_pcm_open,
-               .close = ca0132_dig_playback_pcm_close,
-               .prepare = ca0132_dig_playback_pcm_prepare,
-               .cleanup = ca0132_dig_playback_pcm_cleanup
-       },
-};
-
-static const struct hda_pcm_stream ca0132_pcm_digital_capture = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-};
-
-static int ca0132_build_pcms(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       struct hda_pcm *info;
-
-       info = snd_hda_codec_pcm_new(codec, "CA0132 Analog");
-       if (!info)
-               return -ENOMEM;
-       if (ca0132_use_alt_functions(spec)) {
-               info->own_chmap = true;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap
-                       = ca0132_alt_chmaps;
-       }
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0];
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max =
-               spec->multiout.max_channels;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
-
-       /* With the DSP enabled, desktops don't use this ADC. */
-       if (!ca0132_use_alt_functions(spec)) {
-               info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2");
-               if (!info)
-                       return -ENOMEM;
-               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-                       ca0132_pcm_analog_capture;
-               info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
-               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1];
-       }
-
-       info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear");
-       if (!info)
-               return -ENOMEM;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2];
-
-       if (!spec->dig_out && !spec->dig_in)
-               return 0;
-
-       info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
-       if (!info)
-               return -ENOMEM;
-       info->pcm_type = HDA_PCM_TYPE_SPDIF;
-       if (spec->dig_out) {
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-                       ca0132_pcm_digital_playback;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
-       }
-       if (spec->dig_in) {
-               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-                       ca0132_pcm_digital_capture;
-               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
-       }
-
-       return 0;
-}
-
-static int dbpro_build_pcms(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       struct hda_pcm *info;
-
-       info = snd_hda_codec_pcm_new(codec, "CA0132 Alt Analog");
-       if (!info)
-               return -ENOMEM;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0];
-
-
-       if (!spec->dig_out && !spec->dig_in)
-               return 0;
-
-       info = snd_hda_codec_pcm_new(codec, "CA0132 Digital");
-       if (!info)
-               return -ENOMEM;
-       info->pcm_type = HDA_PCM_TYPE_SPDIF;
-       if (spec->dig_out) {
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK] =
-                       ca0132_pcm_digital_playback;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out;
-       }
-       if (spec->dig_in) {
-               info->stream[SNDRV_PCM_STREAM_CAPTURE] =
-                       ca0132_pcm_digital_capture;
-               info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in;
-       }
-
-       return 0;
-}
-
-static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac)
-{
-       if (pin) {
-               snd_hda_set_pin_ctl(codec, pin, PIN_HP);
-               if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
-                       snd_hda_codec_write(codec, pin, 0,
-                                           AC_VERB_SET_AMP_GAIN_MUTE,
-                                           AMP_OUT_UNMUTE);
-       }
-       if (dac && (get_wcaps(codec, dac) & AC_WCAP_OUT_AMP))
-               snd_hda_codec_write(codec, dac, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO);
-}
-
-static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc)
-{
-       if (pin) {
-               snd_hda_set_pin_ctl(codec, pin, PIN_VREF80);
-               if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP)
-                       snd_hda_codec_write(codec, pin, 0,
-                                           AC_VERB_SET_AMP_GAIN_MUTE,
-                                           AMP_IN_UNMUTE(0));
-       }
-       if (adc && (get_wcaps(codec, adc) & AC_WCAP_IN_AMP)) {
-               snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_IN_UNMUTE(0));
-
-               /* init to 0 dB and unmute. */
-               snd_hda_codec_amp_stereo(codec, adc, HDA_INPUT, 0,
-                                        HDA_AMP_VOLMASK, 0x5a);
-               snd_hda_codec_amp_stereo(codec, adc, HDA_INPUT, 0,
-                                        HDA_AMP_MUTE, 0);
-       }
-}
-
-static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir)
-{
-       unsigned int caps;
-
-       caps = snd_hda_param_read(codec, nid, dir == HDA_OUTPUT ?
-                                 AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP);
-       snd_hda_override_amp_caps(codec, nid, dir, caps);
-}
-
-/*
- * Switch between Digital built-in mic and analog mic.
- */
-static void ca0132_set_dmic(struct hda_codec *codec, int enable)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-       u8 val;
-       unsigned int oldval;
-
-       codec_dbg(codec, "ca0132_set_dmic: enable=%d\n", enable);
-
-       oldval = stop_mic1(codec);
-       ca0132_set_vipsource(codec, 0);
-       if (enable) {
-               /* set DMic input as 2-ch */
-               tmp = FLOAT_TWO;
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-               val = spec->dmic_ctl;
-               val |= 0x80;
-               snd_hda_codec_write(codec, spec->input_pins[0], 0,
-                                   VENDOR_CHIPIO_DMIC_CTL_SET, val);
-
-               if (!(spec->dmic_ctl & 0x20))
-                       chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 1);
-       } else {
-               /* set AMic input as mono */
-               tmp = FLOAT_ONE;
-               dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-               val = spec->dmic_ctl;
-               /* clear bit7 and bit5 to disable dmic */
-               val &= 0x5f;
-               snd_hda_codec_write(codec, spec->input_pins[0], 0,
-                                   VENDOR_CHIPIO_DMIC_CTL_SET, val);
-
-               if (!(spec->dmic_ctl & 0x20))
-                       chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 0);
-       }
-       ca0132_set_vipsource(codec, 1);
-       resume_mic1(codec, oldval);
-}
-
-/*
- * Initialization for Digital Mic.
- */
-static void ca0132_init_dmic(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       u8 val;
-
-       /* Setup Digital Mic here, but don't enable.
-        * Enable based on jack detect.
-        */
-
-       /* MCLK uses MPIO1, set to enable.
-        * Bit 2-0: MPIO select
-        * Bit   3: set to disable
-        * Bit 7-4: reserved
-        */
-       val = 0x01;
-       snd_hda_codec_write(codec, spec->input_pins[0], 0,
-                           VENDOR_CHIPIO_DMIC_MCLK_SET, val);
-
-       /* Data1 uses MPIO3. Data2 not use
-        * Bit 2-0: Data1 MPIO select
-        * Bit   3: set disable Data1
-        * Bit 6-4: Data2 MPIO select
-        * Bit   7: set disable Data2
-        */
-       val = 0x83;
-       snd_hda_codec_write(codec, spec->input_pins[0], 0,
-                           VENDOR_CHIPIO_DMIC_PIN_SET, val);
-
-       /* Use Ch-0 and Ch-1. Rate is 48K, mode 1. Disable DMic first.
-        * Bit 3-0: Channel mask
-        * Bit   4: set for 48KHz, clear for 32KHz
-        * Bit   5: mode
-        * Bit   6: set to select Data2, clear for Data1
-        * Bit   7: set to enable DMic, clear for AMic
-        */
-       if (ca0132_quirk(spec) == QUIRK_ALIENWARE_M17XR4)
-               val = 0x33;
-       else
-               val = 0x23;
-       /* keep a copy of dmic ctl val for enable/disable dmic purpuse */
-       spec->dmic_ctl = val;
-       snd_hda_codec_write(codec, spec->input_pins[0], 0,
-                           VENDOR_CHIPIO_DMIC_CTL_SET, val);
-}
-
-/*
- * Initialization for Analog Mic 2
- */
-static void ca0132_init_analog_mic2(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       chipio_8051_write_exram_no_mutex(codec, 0x1920, 0x00);
-       chipio_8051_write_exram_no_mutex(codec, 0x192d, 0x00);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-static void ca0132_refresh_widget_caps(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int i;
-
-       codec_dbg(codec, "ca0132_refresh_widget_caps.\n");
-       snd_hda_codec_update_widgets(codec);
-
-       for (i = 0; i < spec->multiout.num_dacs; i++)
-               refresh_amp_caps(codec, spec->dacs[i], HDA_OUTPUT);
-
-       for (i = 0; i < spec->num_outputs; i++)
-               refresh_amp_caps(codec, spec->out_pins[i], HDA_OUTPUT);
-
-       for (i = 0; i < spec->num_inputs; i++) {
-               refresh_amp_caps(codec, spec->adcs[i], HDA_INPUT);
-               refresh_amp_caps(codec, spec->input_pins[i], HDA_INPUT);
-       }
-}
-
-
-/* If there is an active channel for some reason, find it and free it. */
-static void ca0132_alt_free_active_dma_channels(struct hda_codec *codec)
-{
-       unsigned int i, tmp;
-       int status;
-
-       /* Read active DSPDMAC channel register. */
-       status = chipio_read(codec, DSPDMAC_CHNLSTART_MODULE_OFFSET, &tmp);
-       if (status >= 0) {
-               /* AND against 0xfff to get the active channel bits. */
-               tmp = tmp & 0xfff;
-
-               /* If there are no active channels, nothing to free. */
-               if (!tmp)
-                       return;
-       } else {
-               codec_dbg(codec, "%s: Failed to read active DSP DMA channel register.\n",
-                               __func__);
-               return;
-       }
-
-       /*
-        * Check each DSP DMA channel for activity, and if the channel is
-        * active, free it.
-        */
-       for (i = 0; i < DSPDMAC_DMA_CFG_CHANNEL_COUNT; i++) {
-               if (dsp_is_dma_active(codec, i)) {
-                       status = dspio_free_dma_chan(codec, i);
-                       if (status < 0)
-                               codec_dbg(codec, "%s: Failed to free active DSP DMA channel %d.\n",
-                                               __func__, i);
-               }
-       }
-}
-
-/*
- * In the case of CT_EXTENSIONS_ENABLE being set to 1, and the DSP being in
- * use, audio is no longer routed directly to the DAC/ADC from the HDA stream.
- * Instead, audio is now routed through the DSP's DMA controllers, which
- * the DSP is tasked with setting up itself. Through debugging, it seems the
- * cause of most of the no-audio on startup issues were due to improperly
- * configured DSP DMA channels.
- *
- * Normally, the DSP configures these the first time an HDA audio stream is
- * started post DSP firmware download. That is why creating a 'dummy' stream
- * worked in fixing the audio in some cases. This works most of the time, but
- * sometimes if a stream is started/stopped before the DSP can setup the DMA
- * configuration registers, it ends up in a broken state. Issues can also
- * arise if streams are started in an unusual order, i.e the audio output dma
- * channel being sandwiched between the mic1 and mic2 dma channels.
- *
- * The solution to this is to make sure that the DSP has no DMA channels
- * in use post DSP firmware download, and then to manually start each default
- * DSP stream that uses the DMA channels. These are 0x0c, the audio output
- * stream, 0x03, analog mic 1, and 0x04, analog mic 2.
- */
-static void ca0132_alt_start_dsp_audio_streams(struct hda_codec *codec)
-{
-       static const unsigned int dsp_dma_stream_ids[] = { 0x0c, 0x03, 0x04 };
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int i, tmp;
-
-       /*
-        * Check if any of the default streams are active, and if they are,
-        * stop them.
-        */
-       mutex_lock(&spec->chipio_mutex);
-
-       for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
-               chipio_get_stream_control(codec, dsp_dma_stream_ids[i], &tmp);
-
-               if (tmp) {
-                       chipio_set_stream_control(codec,
-                                       dsp_dma_stream_ids[i], 0);
-               }
-       }
-
-       mutex_unlock(&spec->chipio_mutex);
-
-       /*
-        * If all DSP streams are inactive, there should be no active DSP DMA
-        * channels. Check and make sure this is the case, and if it isn't,
-        * free any active channels.
-        */
-       ca0132_alt_free_active_dma_channels(codec);
-
-       mutex_lock(&spec->chipio_mutex);
-
-       /* Make sure stream 0x0c is six channels. */
-       chipio_set_stream_channels(codec, 0x0c, 6);
-
-       for (i = 0; i < ARRAY_SIZE(dsp_dma_stream_ids); i++) {
-               chipio_set_stream_control(codec,
-                               dsp_dma_stream_ids[i], 1);
-
-               /* Give the DSP some time to setup the DMA channel. */
-               msleep(75);
-       }
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-/*
- * The region of ChipIO memory from 0x190000-0x1903fc is a sort of 'audio
- * router', where each entry represents a 48khz audio channel, with a format
- * of an 8-bit destination, an 8-bit source, and an unknown 2-bit number
- * value. The 2-bit number value is seemingly 0 if inactive, 1 if active,
- * and 3 if it's using Sample Rate Converter ports.
- * An example is:
- * 0x0001f8c0
- * In this case, f8 is the destination, and c0 is the source. The number value
- * is 1.
- * This region of memory is normally managed internally by the 8051, where
- * the region of exram memory from 0x1477-0x1575 has each byte represent an
- * entry within the 0x190000 range, and when a range of entries is in use, the
- * ending value is overwritten with 0xff.
- * 0x1578 in exram is a table of 0x25 entries, corresponding to the ChipIO
- * streamID's, where each entry is a starting 0x190000 port offset.
- * 0x159d in exram is the same as 0x1578, except it contains the ending port
- * offset for the corresponding streamID.
- *
- * On certain cards, such as the SBZ/ZxR/AE7, these are originally setup by
- * the 8051, then manually overwritten to remap the ports to work with the
- * new DACs.
- *
- * Currently known portID's:
- * 0x00-0x1f: HDA audio stream input/output ports.
- * 0x80-0xbf: Sample rate converter input/outputs. Only valid ports seem to
- *            have the lower-nibble set to 0x1, 0x2, and 0x9.
- * 0xc0-0xdf: DSP DMA input/output ports. Dynamically assigned.
- * 0xe0-0xff: DAC/ADC audio input/output ports.
- *
- * Currently known streamID's:
- * 0x03: Mic1 ADC to DSP.
- * 0x04: Mic2 ADC to DSP.
- * 0x05: HDA node 0x02 audio stream to DSP.
- * 0x0f: DSP Mic exit to HDA node 0x07.
- * 0x0c: DSP processed audio to DACs.
- * 0x14: DAC0, front L/R.
- *
- * It is possible to route the HDA audio streams directly to the DAC and
- * bypass the DSP entirely, with the only downside being that since the DSP
- * does volume control, the only volume control you'll get is through PCM on
- * the PC side, in the same way volume is handled for optical out. This may be
- * useful for debugging.
- */
-static void chipio_remap_stream(struct hda_codec *codec,
-               const struct chipio_stream_remap_data *remap_data)
-{
-       unsigned int i, stream_offset;
-
-       /* Get the starting port for the stream to be remapped. */
-       chipio_8051_read_exram(codec, 0x1578 + remap_data->stream_id,
-                       &stream_offset);
-
-       /*
-        * Check if the stream's port value is 0xff, because the 8051 may not
-        * have gotten around to setting up the stream yet. Wait until it's
-        * setup to remap it's ports.
-        */
-       if (stream_offset == 0xff) {
-               for (i = 0; i < 5; i++) {
-                       msleep(25);
-
-                       chipio_8051_read_exram(codec, 0x1578 + remap_data->stream_id,
-                                       &stream_offset);
-
-                       if (stream_offset != 0xff)
-                               break;
-               }
-       }
-
-       if (stream_offset == 0xff) {
-               codec_info(codec, "%s: Stream 0x%02x ports aren't allocated, remap failed!\n",
-                               __func__, remap_data->stream_id);
-               return;
-       }
-
-       /* Offset isn't in bytes, its in 32-bit words, so multiply it by 4. */
-       stream_offset *= 0x04;
-       stream_offset += 0x190000;
-
-       for (i = 0; i < remap_data->count; i++) {
-               chipio_write_no_mutex(codec,
-                               stream_offset + remap_data->offset[i],
-                               remap_data->value[i]);
-       }
-
-       /* Update stream map configuration. */
-       chipio_write_no_mutex(codec, 0x19042c, 0x00000001);
-}
-
-/*
- * Default speaker tuning values setup for alternative codecs.
- */
-static const unsigned int sbz_default_delay_values[] = {
-       /* Non-zero values are floating point 0.000198. */
-       0x394f9e38, 0x394f9e38, 0x00000000, 0x00000000, 0x00000000, 0x00000000
-};
-
-static const unsigned int zxr_default_delay_values[] = {
-       /* Non-zero values are floating point 0.000220. */
-       0x00000000, 0x00000000, 0x3966afcd, 0x3966afcd, 0x3966afcd, 0x3966afcd
-};
-
-static const unsigned int ae5_default_delay_values[] = {
-       /* Non-zero values are floating point 0.000100. */
-       0x00000000, 0x00000000, 0x38d1b717, 0x38d1b717, 0x38d1b717, 0x38d1b717
-};
-
-/*
- * If we never change these, probably only need them on initialization.
- */
-static void ca0132_alt_init_speaker_tuning(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int i, tmp, start_req, end_req;
-       const unsigned int *values;
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-               values = sbz_default_delay_values;
-               break;
-       case QUIRK_ZXR:
-               values = zxr_default_delay_values;
-               break;
-       case QUIRK_AE5:
-       case QUIRK_AE7:
-               values = ae5_default_delay_values;
-               break;
-       default:
-               values = sbz_default_delay_values;
-               break;
-       }
-
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x96, SPEAKER_TUNING_ENABLE_CENTER_EQ, tmp);
-
-       start_req = SPEAKER_TUNING_FRONT_LEFT_VOL_LEVEL;
-       end_req = SPEAKER_TUNING_REAR_RIGHT_VOL_LEVEL;
-       for (i = start_req; i < end_req + 1; i++)
-               dspio_set_uint_param(codec, 0x96, i, tmp);
-
-       start_req = SPEAKER_TUNING_FRONT_LEFT_INVERT;
-       end_req = SPEAKER_TUNING_REAR_RIGHT_INVERT;
-       for (i = start_req; i < end_req + 1; i++)
-               dspio_set_uint_param(codec, 0x96, i, tmp);
-
-
-       for (i = 0; i < 6; i++)
-               dspio_set_uint_param(codec, 0x96,
-                               SPEAKER_TUNING_FRONT_LEFT_DELAY + i, values[i]);
-}
-
-/*
- * Initialize mic for non-chromebook ca0132 implementations.
- */
-static void ca0132_alt_init_analog_mics(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-
-       /* Mic 1 Setup */
-       chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-       if (ca0132_quirk(spec) == QUIRK_R3DI) {
-               chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-               tmp = FLOAT_ONE;
-       } else
-               tmp = FLOAT_THREE;
-       dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-       /* Mic 2 setup (not present on desktop cards) */
-       chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000);
-       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000);
-       if (ca0132_quirk(spec) == QUIRK_R3DI)
-               chipio_set_conn_rate(codec, 0x0F, SR_96_000);
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x80, 0x01, tmp);
-}
-
-/*
- * Sets the source of stream 0x14 to connpointID 0x48, and the destination
- * connpointID to 0x91. If this isn't done, the destination is 0x71, and
- * you get no sound. I'm guessing this has to do with the Sound Blaster Z
- * having an updated DAC, which changes the destination to that DAC.
- */
-static void sbz_connect_streams(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       codec_dbg(codec, "Connect Streams entered, mutex locked and loaded.\n");
-
-       /* This value is 0x43 for 96khz, and 0x83 for 192khz. */
-       chipio_write_no_mutex(codec, 0x18a020, 0x00000043);
-
-       /* Setup stream 0x14 with it's source and destination points */
-       chipio_set_stream_source_dest(codec, 0x14, 0x48, 0x91);
-       chipio_set_conn_rate_no_mutex(codec, 0x48, SR_96_000);
-       chipio_set_conn_rate_no_mutex(codec, 0x91, SR_96_000);
-       chipio_set_stream_channels(codec, 0x14, 2);
-       chipio_set_stream_control(codec, 0x14, 1);
-
-       codec_dbg(codec, "Connect Streams exited, mutex released.\n");
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-/*
- * Write data through ChipIO to setup proper stream destinations.
- * Not sure how it exactly works, but it seems to direct data
- * to different destinations. Example is f8 to c0, e0 to c0.
- * All I know is, if you don't set these, you get no sound.
- */
-static void sbz_chipio_startup_data(struct hda_codec *codec)
-{
-       const struct chipio_stream_remap_data *dsp_out_remap_data;
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-       codec_dbg(codec, "Startup Data entered, mutex locked and loaded.\n");
-
-       /* Remap DAC0's output ports. */
-       chipio_remap_stream(codec, &stream_remap_data[0]);
-
-       /* Remap DSP audio output stream ports. */
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-               dsp_out_remap_data = &stream_remap_data[1];
-               break;
-
-       case QUIRK_ZXR:
-               dsp_out_remap_data = &stream_remap_data[2];
-               break;
-
-       default:
-               dsp_out_remap_data = NULL;
-               break;
-       }
-
-       if (dsp_out_remap_data)
-               chipio_remap_stream(codec, dsp_out_remap_data);
-
-       codec_dbg(codec, "Startup Data exited, mutex released.\n");
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-static void ca0132_alt_dsp_initial_mic_setup(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-
-       chipio_set_stream_control(codec, 0x03, 0);
-       chipio_set_stream_control(codec, 0x04, 0);
-
-       chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-
-       tmp = FLOAT_THREE;
-       dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-
-       chipio_set_stream_control(codec, 0x03, 1);
-       chipio_set_stream_control(codec, 0x04, 1);
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-               chipio_write(codec, 0x18b098, 0x0000000c);
-               chipio_write(codec, 0x18b09C, 0x0000000c);
-               break;
-       case QUIRK_AE5:
-               chipio_write(codec, 0x18b098, 0x0000000c);
-               chipio_write(codec, 0x18b09c, 0x0000004c);
-               break;
-       default:
-               break;
-       }
-}
-
-static void ae5_post_dsp_register_set(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       chipio_8051_write_direct(codec, 0x93, 0x10);
-       chipio_8051_write_pll_pmu(codec, 0x44, 0xc2);
-
-       writeb(0xff, spec->mem_base + 0x304);
-       writeb(0xff, spec->mem_base + 0x304);
-       writeb(0xff, spec->mem_base + 0x304);
-       writeb(0xff, spec->mem_base + 0x304);
-       writeb(0x00, spec->mem_base + 0x100);
-       writeb(0xff, spec->mem_base + 0x304);
-       writeb(0x00, spec->mem_base + 0x100);
-       writeb(0xff, spec->mem_base + 0x304);
-       writeb(0x00, spec->mem_base + 0x100);
-       writeb(0xff, spec->mem_base + 0x304);
-       writeb(0x00, spec->mem_base + 0x100);
-       writeb(0xff, spec->mem_base + 0x304);
-
-       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x3f);
-       ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
-       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
-}
-
-static void ae5_post_dsp_param_setup(struct hda_codec *codec)
-{
-       /*
-        * Param3 in the 8051's memory is represented by the ascii string 'mch'
-        * which seems to be 'multichannel'. This is also mentioned in the
-        * AE-5's registry values in Windows.
-        */
-       chipio_set_control_param(codec, 3, 0);
-       /*
-        * I believe ASI is 'audio serial interface' and that it's used to
-        * change colors on the external LED strip connected to the AE-5.
-        */
-       chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1);
-
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83);
-       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
-
-       chipio_8051_write_exram(codec, 0xfa92, 0x22);
-}
-
-static void ae5_post_dsp_pll_setup(struct hda_codec *codec)
-{
-       chipio_8051_write_pll_pmu(codec, 0x41, 0xc8);
-       chipio_8051_write_pll_pmu(codec, 0x45, 0xcc);
-       chipio_8051_write_pll_pmu(codec, 0x40, 0xcb);
-       chipio_8051_write_pll_pmu(codec, 0x43, 0xc7);
-       chipio_8051_write_pll_pmu(codec, 0x51, 0x8d);
-}
-
-static void ae5_post_dsp_stream_setup(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
-
-       chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000);
-
-       chipio_set_stream_source_dest(codec, 0x5, 0x43, 0x0);
-
-       chipio_set_stream_source_dest(codec, 0x18, 0x9, 0xd0);
-       chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
-       chipio_set_stream_channels(codec, 0x18, 6);
-       chipio_set_stream_control(codec, 0x18, 1);
-
-       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4);
-
-       chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7);
-
-       ca0113_mmio_command_set(codec, 0x48, 0x01, 0x80);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-static void ae5_post_dsp_startup_data(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       chipio_write_no_mutex(codec, 0x189000, 0x0001f101);
-       chipio_write_no_mutex(codec, 0x189004, 0x0001f101);
-       chipio_write_no_mutex(codec, 0x189024, 0x00014004);
-       chipio_write_no_mutex(codec, 0x189028, 0x0002000f);
-
-       ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
-       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
-       ca0113_mmio_command_set(codec, 0x48, 0x0b, 0x12);
-       ca0113_mmio_command_set(codec, 0x48, 0x04, 0x00);
-       ca0113_mmio_command_set(codec, 0x48, 0x06, 0x48);
-       ca0113_mmio_command_set(codec, 0x48, 0x0a, 0x05);
-       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
-       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
-       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
-       ca0113_mmio_gpio_set(codec, 0, true);
-       ca0113_mmio_gpio_set(codec, 1, true);
-       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x80);
-
-       chipio_write_no_mutex(codec, 0x18b03c, 0x00000012);
-
-       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
-       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-static void ae7_post_dsp_setup_ports(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       /* Seems to share the same port remapping as the SBZ. */
-       chipio_remap_stream(codec, &stream_remap_data[1]);
-
-       ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
-       ca0113_mmio_command_set(codec, 0x48, 0x0d, 0x40);
-       ca0113_mmio_command_set(codec, 0x48, 0x17, 0x00);
-       ca0113_mmio_command_set(codec, 0x48, 0x19, 0x00);
-       ca0113_mmio_command_set(codec, 0x48, 0x11, 0xff);
-       ca0113_mmio_command_set(codec, 0x48, 0x12, 0xff);
-       ca0113_mmio_command_set(codec, 0x48, 0x13, 0xff);
-       ca0113_mmio_command_set(codec, 0x48, 0x14, 0x7f);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-static void ae7_post_dsp_asi_stream_setup(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x81);
-       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
-
-       chipio_set_conn_rate_no_mutex(codec, 0x70, SR_96_000);
-
-       chipio_set_stream_source_dest(codec, 0x05, 0x43, 0x00);
-       chipio_set_stream_source_dest(codec, 0x18, 0x09, 0xd0);
-
-       chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
-       chipio_set_stream_channels(codec, 0x18, 6);
-       chipio_set_stream_control(codec, 0x18, 1);
-
-       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 4);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-static void ae7_post_dsp_pll_setup(struct hda_codec *codec)
-{
-       static const unsigned int addr[] = {
-               0x41, 0x45, 0x40, 0x43, 0x51
-       };
-       static const unsigned int data[] = {
-               0xc8, 0xcc, 0xcb, 0xc7, 0x8d
-       };
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(addr); i++)
-               chipio_8051_write_pll_pmu_no_mutex(codec, addr[i], data[i]);
-}
-
-static void ae7_post_dsp_asi_setup_ports(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       static const unsigned int target[] = {
-               0x0b, 0x04, 0x06, 0x0a, 0x0c, 0x11, 0x12, 0x13, 0x14
-       };
-       static const unsigned int data[] = {
-               0x12, 0x00, 0x48, 0x05, 0x5f, 0xff, 0xff, 0xff, 0x7f
-       };
-       unsigned int i;
-
-       mutex_lock(&spec->chipio_mutex);
-
-       chipio_8051_write_pll_pmu_no_mutex(codec, 0x43, 0xc7);
-
-       chipio_write_no_mutex(codec, 0x189000, 0x0001f101);
-       chipio_write_no_mutex(codec, 0x189004, 0x0001f101);
-       chipio_write_no_mutex(codec, 0x189024, 0x00014004);
-       chipio_write_no_mutex(codec, 0x189028, 0x0002000f);
-
-       ae7_post_dsp_pll_setup(codec);
-       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
-
-       for (i = 0; i < ARRAY_SIZE(target); i++)
-               ca0113_mmio_command_set(codec, 0x48, target[i], data[i]);
-
-       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
-       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
-       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
-
-       chipio_set_stream_source_dest(codec, 0x21, 0x64, 0x56);
-       chipio_set_stream_channels(codec, 0x21, 2);
-       chipio_set_conn_rate_no_mutex(codec, 0x56, SR_8_000);
-
-       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_NODE_ID, 0x09);
-       /*
-        * In the 8051's memory, this param is referred to as 'n2sid', which I
-        * believe is 'node to streamID'. It seems to be a way to assign a
-        * stream to a given HDA node.
-        */
-       chipio_set_control_param_no_mutex(codec, 0x20, 0x21);
-
-       chipio_write_no_mutex(codec, 0x18b038, 0x00000088);
-
-       /*
-        * Now, at this point on Windows, an actual stream is setup and
-        * seemingly sends data to the HDA node 0x09, which is the digital
-        * audio input node. This is left out here, because obviously I don't
-        * know what data is being sent. Interestingly, the AE-5 seems to go
-        * through the motions of getting here and never actually takes this
-        * step, but the AE-7 does.
-        */
-
-       ca0113_mmio_gpio_set(codec, 0, 1);
-       ca0113_mmio_gpio_set(codec, 1, 1);
-
-       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
-       chipio_write_no_mutex(codec, 0x18b03c, 0x00000000);
-       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x00);
-       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x00);
-
-       chipio_set_stream_source_dest(codec, 0x05, 0x43, 0x00);
-       chipio_set_stream_source_dest(codec, 0x18, 0x09, 0xd0);
-
-       chipio_set_conn_rate_no_mutex(codec, 0xd0, SR_96_000);
-       chipio_set_stream_channels(codec, 0x18, 6);
-
-       /*
-        * Runs again, this has been repeated a few times, but I'm just
-        * following what the Windows driver does.
-        */
-       ae7_post_dsp_pll_setup(codec);
-       chipio_set_control_param_no_mutex(codec, CONTROL_PARAM_ASI, 7);
-
-       mutex_unlock(&spec->chipio_mutex);
-}
-
-/*
- * The Windows driver has commands that seem to setup ASI, which I believe to
- * be some sort of audio serial interface. My current speculation is that it's
- * related to communicating with the new DAC.
- */
-static void ae7_post_dsp_asi_setup(struct hda_codec *codec)
-{
-       chipio_8051_write_direct(codec, 0x93, 0x10);
-
-       chipio_8051_write_pll_pmu(codec, 0x44, 0xc2);
-
-       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
-       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
-
-       chipio_set_control_param(codec, 3, 3);
-       chipio_set_control_flag(codec, CONTROL_FLAG_ASI_96KHZ, 1);
-
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x724, 0x83);
-       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
-       snd_hda_codec_write(codec, 0x17, 0, 0x794, 0x00);
-
-       chipio_8051_write_exram(codec, 0xfa92, 0x22);
-
-       ae7_post_dsp_pll_setup(codec);
-       ae7_post_dsp_asi_stream_setup(codec);
-
-       chipio_8051_write_pll_pmu(codec, 0x43, 0xc7);
-
-       ae7_post_dsp_asi_setup_ports(codec);
-}
-
-/*
- * Setup default parameters for DSP
- */
-static void ca0132_setup_defaults(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-       int num_fx;
-       int idx, i;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return;
-
-       /* out, in effects + voicefx */
-       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
-       for (idx = 0; idx < num_fx; idx++) {
-               for (i = 0; i <= ca0132_effects[idx].params; i++) {
-                       dspio_set_uint_param(codec, ca0132_effects[idx].mid,
-                                            ca0132_effects[idx].reqs[i],
-                                            ca0132_effects[idx].def_vals[i]);
-               }
-       }
-
-       /*remove DSP headroom*/
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
-
-       /*set speaker EQ bypass attenuation*/
-       dspio_set_uint_param(codec, 0x8f, 0x01, tmp);
-
-       /* set AMic1 and AMic2 as mono mic */
-       tmp = FLOAT_ONE;
-       dspio_set_uint_param(codec, 0x80, 0x00, tmp);
-       dspio_set_uint_param(codec, 0x80, 0x01, tmp);
-
-       /* set AMic1 as CrystalVoice input */
-       tmp = FLOAT_ONE;
-       dspio_set_uint_param(codec, 0x80, 0x05, tmp);
-
-       /* set WUH source */
-       tmp = FLOAT_TWO;
-       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
-}
-
-/*
- * Setup default parameters for Recon3D/Recon3Di DSP.
- */
-
-static void r3d_setup_defaults(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-       int num_fx;
-       int idx, i;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return;
-
-       ca0132_alt_init_analog_mics(codec);
-       ca0132_alt_start_dsp_audio_streams(codec);
-
-       /*remove DSP headroom*/
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
-
-       /* set WUH source */
-       tmp = FLOAT_TWO;
-       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
-       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
-
-       /* Set speaker source? */
-       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
-
-       if (ca0132_quirk(spec) == QUIRK_R3DI)
-               r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED);
-
-       /* Disable mute on Center/LFE. */
-       if (ca0132_quirk(spec) == QUIRK_R3D) {
-               ca0113_mmio_gpio_set(codec, 2, false);
-               ca0113_mmio_gpio_set(codec, 4, true);
-       }
-
-       /* Setup effect defaults */
-       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
-       for (idx = 0; idx < num_fx; idx++) {
-               for (i = 0; i <= ca0132_effects[idx].params; i++) {
-                       dspio_set_uint_param(codec,
-                                       ca0132_effects[idx].mid,
-                                       ca0132_effects[idx].reqs[i],
-                                       ca0132_effects[idx].def_vals[i]);
-               }
-       }
-}
-
-/*
- * Setup default parameters for the Sound Blaster Z DSP. A lot more going on
- * than the Chromebook setup.
- */
-static void sbz_setup_defaults(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-       int num_fx;
-       int idx, i;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return;
-
-       ca0132_alt_init_analog_mics(codec);
-       ca0132_alt_start_dsp_audio_streams(codec);
-       sbz_connect_streams(codec);
-       sbz_chipio_startup_data(codec);
-
-       /*
-        * Sets internal input loopback to off, used to have a switch to
-        * enable input loopback, but turned out to be way too buggy.
-        */
-       tmp = FLOAT_ONE;
-       dspio_set_uint_param(codec, 0x37, 0x08, tmp);
-       dspio_set_uint_param(codec, 0x37, 0x10, tmp);
-
-       /*remove DSP headroom*/
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
-
-       /* set WUH source */
-       tmp = FLOAT_TWO;
-       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
-       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
-
-       /* Set speaker source? */
-       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
-
-       ca0132_alt_dsp_initial_mic_setup(codec);
-
-       /* out, in effects + voicefx */
-       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
-       for (idx = 0; idx < num_fx; idx++) {
-               for (i = 0; i <= ca0132_effects[idx].params; i++) {
-                       dspio_set_uint_param(codec,
-                                       ca0132_effects[idx].mid,
-                                       ca0132_effects[idx].reqs[i],
-                                       ca0132_effects[idx].def_vals[i]);
-               }
-       }
-
-       ca0132_alt_init_speaker_tuning(codec);
-}
-
-/*
- * Setup default parameters for the Sound BlasterX AE-5 DSP.
- */
-static void ae5_setup_defaults(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-       int num_fx;
-       int idx, i;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return;
-
-       ca0132_alt_init_analog_mics(codec);
-       ca0132_alt_start_dsp_audio_streams(codec);
-
-       /* New, unknown SCP req's */
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x96, 0x29, tmp);
-       dspio_set_uint_param(codec, 0x96, 0x2a, tmp);
-       dspio_set_uint_param(codec, 0x80, 0x0d, tmp);
-       dspio_set_uint_param(codec, 0x80, 0x0e, tmp);
-
-       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
-       ca0113_mmio_gpio_set(codec, 0, false);
-       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
-
-       /* Internal loopback off */
-       tmp = FLOAT_ONE;
-       dspio_set_uint_param(codec, 0x37, 0x08, tmp);
-       dspio_set_uint_param(codec, 0x37, 0x10, tmp);
-
-       /*remove DSP headroom*/
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
-
-       /* set WUH source */
-       tmp = FLOAT_TWO;
-       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
-       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
-
-       /* Set speaker source? */
-       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
-
-       ca0132_alt_dsp_initial_mic_setup(codec);
-       ae5_post_dsp_register_set(codec);
-       ae5_post_dsp_param_setup(codec);
-       ae5_post_dsp_pll_setup(codec);
-       ae5_post_dsp_stream_setup(codec);
-       ae5_post_dsp_startup_data(codec);
-
-       /* out, in effects + voicefx */
-       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
-       for (idx = 0; idx < num_fx; idx++) {
-               for (i = 0; i <= ca0132_effects[idx].params; i++) {
-                       dspio_set_uint_param(codec,
-                                       ca0132_effects[idx].mid,
-                                       ca0132_effects[idx].reqs[i],
-                                       ca0132_effects[idx].def_vals[i]);
-               }
-       }
-
-       ca0132_alt_init_speaker_tuning(codec);
-}
-
-/*
- * Setup default parameters for the Sound Blaster AE-7 DSP.
- */
-static void ae7_setup_defaults(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp;
-       int num_fx;
-       int idx, i;
-
-       if (spec->dsp_state != DSP_DOWNLOADED)
-               return;
-
-       ca0132_alt_init_analog_mics(codec);
-       ca0132_alt_start_dsp_audio_streams(codec);
-       ae7_post_dsp_setup_ports(codec);
-
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x96,
-                       SPEAKER_TUNING_FRONT_LEFT_INVERT, tmp);
-       dspio_set_uint_param(codec, 0x96,
-                       SPEAKER_TUNING_FRONT_RIGHT_INVERT, tmp);
-
-       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
-
-       /* New, unknown SCP req's */
-       dspio_set_uint_param(codec, 0x80, 0x0d, tmp);
-       dspio_set_uint_param(codec, 0x80, 0x0e, tmp);
-
-       ca0113_mmio_gpio_set(codec, 0, false);
-
-       /* Internal loopback off */
-       tmp = FLOAT_ONE;
-       dspio_set_uint_param(codec, 0x37, 0x08, tmp);
-       dspio_set_uint_param(codec, 0x37, 0x10, tmp);
-
-       /*remove DSP headroom*/
-       tmp = FLOAT_ZERO;
-       dspio_set_uint_param(codec, 0x96, 0x3C, tmp);
-
-       /* set WUH source */
-       tmp = FLOAT_TWO;
-       dspio_set_uint_param(codec, 0x31, 0x00, tmp);
-       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
-
-       /* Set speaker source? */
-       dspio_set_uint_param(codec, 0x32, 0x00, tmp);
-       ca0113_mmio_command_set(codec, 0x30, 0x28, 0x00);
-
-       /*
-        * This is the second time we've called this, but this is seemingly
-        * what Windows does.
-        */
-       ca0132_alt_init_analog_mics(codec);
-
-       ae7_post_dsp_asi_setup(codec);
-
-       /*
-        * Not sure why, but these are both set to 1. They're only set to 0
-        * upon shutdown.
-        */
-       ca0113_mmio_gpio_set(codec, 0, true);
-       ca0113_mmio_gpio_set(codec, 1, true);
-
-       /* Volume control related. */
-       ca0113_mmio_command_set(codec, 0x48, 0x0f, 0x04);
-       ca0113_mmio_command_set(codec, 0x48, 0x10, 0x04);
-       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x80);
-
-       /* out, in effects + voicefx */
-       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1;
-       for (idx = 0; idx < num_fx; idx++) {
-               for (i = 0; i <= ca0132_effects[idx].params; i++) {
-                       dspio_set_uint_param(codec,
-                                       ca0132_effects[idx].mid,
-                                       ca0132_effects[idx].reqs[i],
-                                       ca0132_effects[idx].def_vals[i]);
-               }
-       }
-
-       ca0132_alt_init_speaker_tuning(codec);
-}
-
-/*
- * Initialization of flags in chip
- */
-static void ca0132_init_flags(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       if (ca0132_use_alt_functions(spec)) {
-               chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, 1);
-               chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, 1);
-               chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, 1);
-               chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_96KHZ, 1);
-               chipio_set_control_flag(codec, CONTROL_FLAG_SRC_RATE_96KHZ, 1);
-               chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0);
-               chipio_set_control_flag(codec, CONTROL_FLAG_SPDIF2OUT, 0);
-               chipio_set_control_flag(codec,
-                               CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0);
-               chipio_set_control_flag(codec,
-                               CONTROL_FLAG_PORT_A_10KOHM_LOAD, 1);
-       } else {
-               chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0);
-               chipio_set_control_flag(codec,
-                               CONTROL_FLAG_PORT_A_COMMON_MODE, 0);
-               chipio_set_control_flag(codec,
-                               CONTROL_FLAG_PORT_D_COMMON_MODE, 0);
-               chipio_set_control_flag(codec,
-                               CONTROL_FLAG_PORT_A_10KOHM_LOAD, 0);
-               chipio_set_control_flag(codec,
-                               CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0);
-               chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_HIGH_PASS, 1);
-       }
-}
-
-/*
- * Initialization of parameters in chip
- */
-static void ca0132_init_params(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       if (ca0132_use_alt_functions(spec)) {
-               chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
-               chipio_set_conn_rate(codec, 0x0B, SR_48_000);
-               chipio_set_control_param(codec, CONTROL_PARAM_SPDIF1_SOURCE, 0);
-               chipio_set_control_param(codec, 0, 0);
-               chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0);
-       }
-
-       chipio_set_control_param(codec, CONTROL_PARAM_PORTA_160OHM_GAIN, 6);
-       chipio_set_control_param(codec, CONTROL_PARAM_PORTD_160OHM_GAIN, 6);
-}
-
-static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k)
-{
-       chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, is96k);
-       chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, is96k);
-       chipio_set_control_flag(codec, CONTROL_FLAG_SRC_RATE_96KHZ, is96k);
-       chipio_set_control_flag(codec, CONTROL_FLAG_SRC_CLOCK_196MHZ, is96k);
-       chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, is96k);
-       chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_96KHZ, is96k);
-
-       chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000);
-       chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000);
-       chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000);
-}
-
-static bool ca0132_download_dsp_images(struct hda_codec *codec)
-{
-       bool dsp_loaded = false;
-       struct ca0132_spec *spec = codec->spec;
-       const struct dsp_image_seg *dsp_os_image;
-       const struct firmware *fw_entry = NULL;
-       /*
-        * Alternate firmwares for different variants. The Recon3Di apparently
-        * can use the default firmware, but I'll leave the option in case
-        * it needs it again.
-        */
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-       case QUIRK_R3D:
-       case QUIRK_AE5:
-               if (request_firmware(&fw_entry, DESKTOP_EFX_FILE,
-                                       codec->card->dev) != 0)
-                       codec_dbg(codec, "Desktop firmware not found.");
-               else
-                       codec_dbg(codec, "Desktop firmware selected.");
-               break;
-       case QUIRK_R3DI:
-               if (request_firmware(&fw_entry, R3DI_EFX_FILE,
-                                       codec->card->dev) != 0)
-                       codec_dbg(codec, "Recon3Di alt firmware not detected.");
-               else
-                       codec_dbg(codec, "Recon3Di firmware selected.");
-               break;
-       default:
-               break;
-       }
-       /*
-        * Use default ctefx.bin if no alt firmware is detected, or if none
-        * exists for your particular codec.
-        */
-       if (!fw_entry) {
-               codec_dbg(codec, "Default firmware selected.");
-               if (request_firmware(&fw_entry, EFX_FILE,
-                                       codec->card->dev) != 0)
-                       return false;
-       }
-
-       dsp_os_image = (struct dsp_image_seg *)(fw_entry->data);
-       if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) {
-               codec_err(codec, "ca0132 DSP load image failed\n");
-               goto exit_download;
-       }
-
-       dsp_loaded = dspload_wait_loaded(codec);
-
-exit_download:
-       release_firmware(fw_entry);
-
-       return dsp_loaded;
-}
-
-static void ca0132_download_dsp(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-#ifndef CONFIG_SND_HDA_CODEC_CA0132_DSP
-       return; /* NOP */
-#endif
-
-       if (spec->dsp_state == DSP_DOWNLOAD_FAILED)
-               return; /* don't retry failures */
-
-       chipio_enable_clocks(codec);
-       if (spec->dsp_state != DSP_DOWNLOADED) {
-               spec->dsp_state = DSP_DOWNLOADING;
-
-               if (!ca0132_download_dsp_images(codec))
-                       spec->dsp_state = DSP_DOWNLOAD_FAILED;
-               else
-                       spec->dsp_state = DSP_DOWNLOADED;
-       }
-
-       /* For codecs using alt functions, this is already done earlier */
-       if (spec->dsp_state == DSP_DOWNLOADED && !ca0132_use_alt_functions(spec))
-               ca0132_set_dsp_msr(codec, true);
-}
-
-static void ca0132_process_dsp_response(struct hda_codec *codec,
-                                       struct hda_jack_callback *callback)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       codec_dbg(codec, "ca0132_process_dsp_response\n");
-       snd_hda_power_up_pm(codec);
-       if (spec->wait_scp) {
-               if (dspio_get_response_data(codec) >= 0)
-                       spec->wait_scp = 0;
-       }
-
-       dspio_clear_response_queue(codec);
-       snd_hda_power_down_pm(codec);
-}
-
-static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
-{
-       struct ca0132_spec *spec = codec->spec;
-       struct hda_jack_tbl *tbl;
-
-       /* Delay enabling the HP amp, to let the mic-detection
-        * state machine run.
-        */
-       tbl = snd_hda_jack_tbl_get(codec, cb->nid);
-       if (tbl)
-               tbl->block_report = 1;
-       schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(500));
-}
-
-static void amic_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       if (ca0132_use_alt_functions(spec))
-               ca0132_alt_select_in(codec);
-       else
-               ca0132_select_mic(codec);
-}
-
-static void ca0132_setup_unsol(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_hp, hp_callback);
-       snd_hda_jack_detect_enable_callback(codec, spec->unsol_tag_amic1,
-                                           amic_callback);
-       snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP,
-                                           ca0132_process_dsp_response);
-       /* Front headphone jack detection */
-       if (ca0132_use_alt_functions(spec))
-               snd_hda_jack_detect_enable_callback(codec,
-                       spec->unsol_tag_front_hp, hp_callback);
-}
-
-/*
- * Verbs tables.
- */
-
-/* Sends before DSP download. */
-static const struct hda_verb ca0132_base_init_verbs[] = {
-       /*enable ct extension*/
-       {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x1},
-       {}
-};
-
-/* Send at exit. */
-static const struct hda_verb ca0132_base_exit_verbs[] = {
-       /*set afg to D3*/
-       {0x01, AC_VERB_SET_POWER_STATE, 0x03},
-       /*disable ct extension*/
-       {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0},
-       {}
-};
-
-/* Other verbs tables. Sends after DSP download. */
-
-static const struct hda_verb ca0132_init_verbs0[] = {
-       /* chip init verbs */
-       {0x15, 0x70D, 0xF0},
-       {0x15, 0x70E, 0xFE},
-       {0x15, 0x707, 0x75},
-       {0x15, 0x707, 0xD3},
-       {0x15, 0x707, 0x09},
-       {0x15, 0x707, 0x53},
-       {0x15, 0x707, 0xD4},
-       {0x15, 0x707, 0xEF},
-       {0x15, 0x707, 0x75},
-       {0x15, 0x707, 0xD3},
-       {0x15, 0x707, 0x09},
-       {0x15, 0x707, 0x02},
-       {0x15, 0x707, 0x37},
-       {0x15, 0x707, 0x78},
-       {0x15, 0x53C, 0xCE},
-       {0x15, 0x575, 0xC9},
-       {0x15, 0x53D, 0xCE},
-       {0x15, 0x5B7, 0xC9},
-       {0x15, 0x70D, 0xE8},
-       {0x15, 0x70E, 0xFE},
-       {0x15, 0x707, 0x02},
-       {0x15, 0x707, 0x68},
-       {0x15, 0x707, 0x62},
-       {0x15, 0x53A, 0xCE},
-       {0x15, 0x546, 0xC9},
-       {0x15, 0x53B, 0xCE},
-       {0x15, 0x5E8, 0xC9},
-       {}
-};
-
-/* Extra init verbs for desktop cards. */
-static const struct hda_verb ca0132_init_verbs1[] = {
-       {0x15, 0x70D, 0x20},
-       {0x15, 0x70E, 0x19},
-       {0x15, 0x707, 0x00},
-       {0x15, 0x539, 0xCE},
-       {0x15, 0x546, 0xC9},
-       {0x15, 0x70D, 0xB7},
-       {0x15, 0x70E, 0x09},
-       {0x15, 0x707, 0x10},
-       {0x15, 0x70D, 0xAF},
-       {0x15, 0x70E, 0x09},
-       {0x15, 0x707, 0x01},
-       {0x15, 0x707, 0x05},
-       {0x15, 0x70D, 0x73},
-       {0x15, 0x70E, 0x09},
-       {0x15, 0x707, 0x14},
-       {0x15, 0x6FF, 0xC4},
-       {}
-};
-
-static void ca0132_init_chip(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       int num_fx;
-       int i;
-       unsigned int on;
-
-       mutex_init(&spec->chipio_mutex);
-
-       /*
-        * The Windows driver always does this upon startup, which seems to
-        * clear out any previous configuration. This should help issues where
-        * a boot into Windows prior to a boot into Linux breaks things. Also,
-        * Windows always sends the reset twice.
-        */
-       if (ca0132_use_alt_functions(spec)) {
-               chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0);
-               chipio_write_no_mutex(codec, 0x18b0a4, 0x000000c2);
-
-               snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_CODEC_RESET, 0);
-               snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_CODEC_RESET, 0);
-       }
-
-       spec->cur_out_type = SPEAKER_OUT;
-       if (!ca0132_use_alt_functions(spec))
-               spec->cur_mic_type = DIGITAL_MIC;
-       else
-               spec->cur_mic_type = REAR_MIC;
-
-       spec->cur_mic_boost = 0;
-
-       for (i = 0; i < VNODES_COUNT; i++) {
-               spec->vnode_lvol[i] = 0x5a;
-               spec->vnode_rvol[i] = 0x5a;
-               spec->vnode_lswitch[i] = 0;
-               spec->vnode_rswitch[i] = 0;
-       }
-
-       /*
-        * Default states for effects are in ca0132_effects[].
-        */
-       num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT;
-       for (i = 0; i < num_fx; i++) {
-               on = (unsigned int)ca0132_effects[i].reqs[0];
-               spec->effects_switch[i] = on ? 1 : 0;
-       }
-       /*
-        * Sets defaults for the effect slider controls, only for alternative
-        * ca0132 codecs. Also sets x-bass crossover frequency to 80hz.
-        */
-       if (ca0132_use_alt_controls(spec)) {
-               /* Set speakers to default to full range. */
-               spec->speaker_range_val[0] = 1;
-               spec->speaker_range_val[1] = 1;
-
-               spec->xbass_xover_freq = 8;
-               for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++)
-                       spec->fx_ctl_val[i] = effect_slider_defaults[i];
-
-               spec->bass_redirect_xover_freq = 8;
-       }
-
-       spec->voicefx_val = 0;
-       spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1;
-       spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0;
-
-       /*
-        * The ZxR doesn't have a front panel header, and it's line-in is on
-        * the daughter board. So, there is no input enum control, and we need
-        * to make sure that spec->in_enum_val is set properly.
-        */
-       if (ca0132_quirk(spec) == QUIRK_ZXR)
-               spec->in_enum_val = REAR_MIC;
-
-#ifdef ENABLE_TUNING_CONTROLS
-       ca0132_init_tuning_defaults(codec);
-#endif
-}
-
-/*
- * Recon3Di exit specific commands.
- */
-/* prevents popping noise on shutdown */
-static void r3di_gpio_shutdown(struct hda_codec *codec)
-{
-       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0x00);
-}
-
-/*
- * Sound Blaster Z exit specific commands.
- */
-static void sbz_region2_exit(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int i;
-
-       for (i = 0; i < 4; i++)
-               writeb(0x0, spec->mem_base + 0x100);
-       for (i = 0; i < 8; i++)
-               writeb(0xb3, spec->mem_base + 0x304);
-
-       ca0113_mmio_gpio_set(codec, 0, false);
-       ca0113_mmio_gpio_set(codec, 1, false);
-       ca0113_mmio_gpio_set(codec, 4, true);
-       ca0113_mmio_gpio_set(codec, 5, false);
-       ca0113_mmio_gpio_set(codec, 7, false);
-}
-
-static void sbz_set_pin_ctl_default(struct hda_codec *codec)
-{
-       static const hda_nid_t pins[] = {0x0B, 0x0C, 0x0E, 0x12, 0x13};
-       unsigned int i;
-
-       snd_hda_codec_write(codec, 0x11, 0,
-                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
-
-       for (i = 0; i < ARRAY_SIZE(pins); i++)
-               snd_hda_codec_write(codec, pins[i], 0,
-                               AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
-}
-
-static void ca0132_clear_unsolicited(struct hda_codec *codec)
-{
-       static const hda_nid_t pins[] = {0x0B, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13};
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(pins); i++) {
-               snd_hda_codec_write(codec, pins[i], 0,
-                               AC_VERB_SET_UNSOLICITED_ENABLE, 0x00);
-       }
-}
-
-/* On shutdown, sends commands in sets of three */
-static void sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir,
-                                                       int mask, int data)
-{
-       if (dir >= 0)
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_DIRECTION, dir);
-       if (mask >= 0)
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_MASK, mask);
-
-       if (data >= 0)
-               snd_hda_codec_write(codec, 0x01, 0,
-                               AC_VERB_SET_GPIO_DATA, data);
-}
-
-static void zxr_dbpro_power_state_shutdown(struct hda_codec *codec)
-{
-       static const hda_nid_t pins[] = {0x05, 0x0c, 0x09, 0x0e, 0x08, 0x11, 0x01};
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(pins); i++)
-               snd_hda_codec_write(codec, pins[i], 0,
-                               AC_VERB_SET_POWER_STATE, 0x03);
-}
-
-static void sbz_exit_chip(struct hda_codec *codec)
-{
-       chipio_set_stream_control(codec, 0x03, 0);
-       chipio_set_stream_control(codec, 0x04, 0);
-
-       /* Mess with GPIO */
-       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, -1);
-       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x05);
-       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x01);
-
-       chipio_set_stream_control(codec, 0x14, 0);
-       chipio_set_stream_control(codec, 0x0C, 0);
-
-       chipio_set_conn_rate(codec, 0x41, SR_192_000);
-       chipio_set_conn_rate(codec, 0x91, SR_192_000);
-
-       chipio_write(codec, 0x18a020, 0x00000083);
-
-       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x03);
-       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x07);
-       sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x06);
-
-       chipio_set_stream_control(codec, 0x0C, 0);
-
-       chipio_set_control_param(codec, 0x0D, 0x24);
-
-       ca0132_clear_unsolicited(codec);
-       sbz_set_pin_ctl_default(codec);
-
-       snd_hda_codec_write(codec, 0x0B, 0,
-               AC_VERB_SET_EAPD_BTLENABLE, 0x00);
-
-       sbz_region2_exit(codec);
-}
-
-static void r3d_exit_chip(struct hda_codec *codec)
-{
-       ca0132_clear_unsolicited(codec);
-       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
-       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5b);
-}
-
-static void ae5_exit_chip(struct hda_codec *codec)
-{
-       chipio_set_stream_control(codec, 0x03, 0);
-       chipio_set_stream_control(codec, 0x04, 0);
-
-       ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
-       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
-       ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
-       ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
-       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
-       ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x00);
-       ca0113_mmio_gpio_set(codec, 0, false);
-       ca0113_mmio_gpio_set(codec, 1, false);
-
-       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
-       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
-
-       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
-
-       chipio_set_stream_control(codec, 0x18, 0);
-       chipio_set_stream_control(codec, 0x0c, 0);
-
-       snd_hda_codec_write(codec, 0x01, 0, 0x724, 0x83);
-}
-
-static void ae7_exit_chip(struct hda_codec *codec)
-{
-       chipio_set_stream_control(codec, 0x18, 0);
-       chipio_set_stream_source_dest(codec, 0x21, 0xc8, 0xc8);
-       chipio_set_stream_channels(codec, 0x21, 0);
-       chipio_set_control_param(codec, CONTROL_PARAM_NODE_ID, 0x09);
-       chipio_set_control_param(codec, 0x20, 0x01);
-
-       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 0);
-
-       chipio_set_stream_control(codec, 0x18, 0);
-       chipio_set_stream_control(codec, 0x0c, 0);
-
-       ca0113_mmio_command_set(codec, 0x30, 0x2b, 0x00);
-       snd_hda_codec_write(codec, 0x15, 0, 0x724, 0x83);
-       ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
-       ca0113_mmio_command_set(codec, 0x30, 0x30, 0x00);
-       ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x00);
-       ca0113_mmio_gpio_set(codec, 0, false);
-       ca0113_mmio_gpio_set(codec, 1, false);
-       ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
-
-       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
-       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
-}
-
-static void zxr_exit_chip(struct hda_codec *codec)
-{
-       chipio_set_stream_control(codec, 0x03, 0);
-       chipio_set_stream_control(codec, 0x04, 0);
-       chipio_set_stream_control(codec, 0x14, 0);
-       chipio_set_stream_control(codec, 0x0C, 0);
-
-       chipio_set_conn_rate(codec, 0x41, SR_192_000);
-       chipio_set_conn_rate(codec, 0x91, SR_192_000);
-
-       chipio_write(codec, 0x18a020, 0x00000083);
-
-       snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00);
-       snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53);
-
-       ca0132_clear_unsolicited(codec);
-       sbz_set_pin_ctl_default(codec);
-       snd_hda_codec_write(codec, 0x0B, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x00);
-
-       ca0113_mmio_gpio_set(codec, 5, false);
-       ca0113_mmio_gpio_set(codec, 2, false);
-       ca0113_mmio_gpio_set(codec, 3, false);
-       ca0113_mmio_gpio_set(codec, 0, false);
-       ca0113_mmio_gpio_set(codec, 4, true);
-       ca0113_mmio_gpio_set(codec, 0, true);
-       ca0113_mmio_gpio_set(codec, 5, true);
-       ca0113_mmio_gpio_set(codec, 2, false);
-       ca0113_mmio_gpio_set(codec, 3, false);
-}
-
-static void ca0132_exit_chip(struct hda_codec *codec)
-{
-       /* put any chip cleanup stuffs here. */
-
-       if (dspload_is_loaded(codec))
-               dsp_reset(codec);
-}
-
-/*
- * This fixes a problem that was hard to reproduce. Very rarely, I would
- * boot up, and there would be no sound, but the DSP indicated it had loaded
- * properly. I did a few memory dumps to see if anything was different, and
- * there were a few areas of memory uninitialized with a1a2a3a4. This function
- * checks if those areas are uninitialized, and if they are, it'll attempt to
- * reload the card 3 times. Usually it fixes by the second.
- */
-static void sbz_dsp_startup_check(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int dsp_data_check[4];
-       unsigned int cur_address = 0x390;
-       unsigned int i;
-       unsigned int failure = 0;
-       unsigned int reload = 3;
-
-       if (spec->startup_check_entered)
-               return;
-
-       spec->startup_check_entered = true;
-
-       for (i = 0; i < 4; i++) {
-               chipio_read(codec, cur_address, &dsp_data_check[i]);
-               cur_address += 0x4;
-       }
-       for (i = 0; i < 4; i++) {
-               if (dsp_data_check[i] == 0xa1a2a3a4)
-                       failure = 1;
-       }
-
-       codec_dbg(codec, "Startup Check: %d ", failure);
-       if (failure)
-               codec_info(codec, "DSP not initialized properly. Attempting to fix.");
-       /*
-        * While the failure condition is true, and we haven't reached our
-        * three reload limit, continue trying to reload the driver and
-        * fix the issue.
-        */
-       while (failure && (reload != 0)) {
-               codec_info(codec, "Reloading... Tries left: %d", reload);
-               sbz_exit_chip(codec);
-               spec->dsp_state = DSP_DOWNLOAD_INIT;
-               codec->patch_ops.init(codec);
-               failure = 0;
-               for (i = 0; i < 4; i++) {
-                       chipio_read(codec, cur_address, &dsp_data_check[i]);
-                       cur_address += 0x4;
-               }
-               for (i = 0; i < 4; i++) {
-                       if (dsp_data_check[i] == 0xa1a2a3a4)
-                               failure = 1;
-               }
-               reload--;
-       }
-
-       if (!failure && reload < 3)
-               codec_info(codec, "DSP fixed.");
-
-       if (!failure)
-               return;
-
-       codec_info(codec, "DSP failed to initialize properly. Either try a full shutdown or a suspend to clear the internal memory.");
-}
-
-/*
- * This is for the extra volume verbs 0x797 (left) and 0x798 (right). These add
- * extra precision for decibel values. If you had the dB value in floating point
- * you would take the value after the decimal point, multiply by 64, and divide
- * by 2. So for 8.59, it's (59 * 64) / 100. Useful if someone wanted to
- * implement fixed point or floating point dB volumes. For now, I'll set them
- * to 0 just incase a value has lingered from a boot into Windows.
- */
-static void ca0132_alt_vol_setup(struct hda_codec *codec)
-{
-       snd_hda_codec_write(codec, 0x02, 0, 0x797, 0x00);
-       snd_hda_codec_write(codec, 0x02, 0, 0x798, 0x00);
-       snd_hda_codec_write(codec, 0x03, 0, 0x797, 0x00);
-       snd_hda_codec_write(codec, 0x03, 0, 0x798, 0x00);
-       snd_hda_codec_write(codec, 0x04, 0, 0x797, 0x00);
-       snd_hda_codec_write(codec, 0x04, 0, 0x798, 0x00);
-       snd_hda_codec_write(codec, 0x07, 0, 0x797, 0x00);
-       snd_hda_codec_write(codec, 0x07, 0, 0x798, 0x00);
-}
-
-/*
- * Extra commands that don't really fit anywhere else.
- */
-static void sbz_pre_dsp_setup(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       writel(0x00820680, spec->mem_base + 0x01C);
-       writel(0x00820680, spec->mem_base + 0x01C);
-
-       chipio_write(codec, 0x18b0a4, 0x000000c2);
-
-       snd_hda_codec_write(codec, 0x11, 0,
-                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44);
-}
-
-static void r3d_pre_dsp_setup(struct hda_codec *codec)
-{
-       chipio_write(codec, 0x18b0a4, 0x000000c2);
-
-       chipio_8051_write_exram(codec, 0x1c1e, 0x5b);
-
-       snd_hda_codec_write(codec, 0x11, 0,
-                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44);
-}
-
-static void r3di_pre_dsp_setup(struct hda_codec *codec)
-{
-       chipio_write(codec, 0x18b0a4, 0x000000c2);
-
-       chipio_8051_write_exram(codec, 0x1c1e, 0x5b);
-       chipio_8051_write_exram(codec, 0x1920, 0x00);
-       chipio_8051_write_exram(codec, 0x1921, 0x40);
-
-       snd_hda_codec_write(codec, 0x11, 0,
-                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x04);
-}
-
-/*
- * The ZxR seems to use alternative DAC's for the surround channels, which
- * require PLL PMU setup for the clock rate, I'm guessing. Without setting
- * this up, we get no audio out of the surround jacks.
- */
-static void zxr_pre_dsp_setup(struct hda_codec *codec)
-{
-       static const unsigned int addr[] = { 0x43, 0x40, 0x41, 0x42, 0x45 };
-       static const unsigned int data[] = { 0x08, 0x0c, 0x0b, 0x07, 0x0d };
-       unsigned int i;
-
-       chipio_write(codec, 0x189000, 0x0001f100);
-       msleep(50);
-       chipio_write(codec, 0x18900c, 0x0001f100);
-       msleep(50);
-
-       /*
-        * This writes a RET instruction at the entry point of the function at
-        * 0xfa92 in exram. This function seems to have something to do with
-        * ASI. Might be some way to prevent the card from reconfiguring the
-        * ASI stuff itself.
-        */
-       chipio_8051_write_exram(codec, 0xfa92, 0x22);
-
-       chipio_8051_write_pll_pmu(codec, 0x51, 0x98);
-
-       snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x725, 0x82);
-       chipio_set_control_param(codec, CONTROL_PARAM_ASI, 3);
-
-       chipio_write(codec, 0x18902c, 0x00000000);
-       msleep(50);
-       chipio_write(codec, 0x18902c, 0x00000003);
-       msleep(50);
-
-       for (i = 0; i < ARRAY_SIZE(addr); i++)
-               chipio_8051_write_pll_pmu(codec, addr[i], data[i]);
-}
-
-/*
- * These are sent before the DSP is downloaded. Not sure
- * what they do, or if they're necessary. Could possibly
- * be removed. Figure they're better to leave in.
- */
-static const unsigned int ca0113_mmio_init_address_sbz[] = {
-       0x400, 0x408, 0x40c, 0x01c, 0xc0c, 0xc00, 0xc04, 0xc0c, 0xc0c, 0xc0c,
-       0xc0c, 0xc08, 0xc08, 0xc08, 0xc08, 0xc08, 0xc04
-};
-
-static const unsigned int ca0113_mmio_init_data_sbz[] = {
-       0x00000030, 0x00000000, 0x00000003, 0x00000003, 0x00000003,
-       0x00000003, 0x000000c1, 0x000000f1, 0x00000001, 0x000000c7,
-       0x000000c1, 0x00000080
-};
-
-static const unsigned int ca0113_mmio_init_data_zxr[] = {
-       0x00000030, 0x00000000, 0x00000000, 0x00000003, 0x00000003,
-       0x00000003, 0x00000001, 0x000000f1, 0x00000001, 0x000000c7,
-       0x000000c1, 0x00000080
-};
-
-static const unsigned int ca0113_mmio_init_address_ae5[] = {
-       0x400, 0x42c, 0x46c, 0x4ac, 0x4ec, 0x43c, 0x47c, 0x4bc, 0x4fc, 0x408,
-       0x100, 0x410, 0x40c, 0x100, 0x100, 0x830, 0x86c, 0x800, 0x86c, 0x800,
-       0x804, 0x20c, 0x01c, 0xc0c, 0xc00, 0xc04, 0xc0c, 0xc0c, 0xc0c, 0xc0c,
-       0xc08, 0xc08, 0xc08, 0xc08, 0xc08, 0xc04, 0x01c
-};
-
-static const unsigned int ca0113_mmio_init_data_ae5[] = {
-       0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
-       0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001,
-       0x00000600, 0x00000014, 0x00000001, 0x0000060f, 0x0000070f,
-       0x00000aff, 0x00000000, 0x0000006b, 0x00000001, 0x0000006b,
-       0x00000057, 0x00800000, 0x00880680, 0x00000080, 0x00000030,
-       0x00000000, 0x00000000, 0x00000003, 0x00000003, 0x00000003,
-       0x00000001, 0x000000f1, 0x00000001, 0x000000c7, 0x000000c1,
-       0x00000080, 0x00880680
-};
-
-static void ca0132_mmio_init_sbz(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int tmp[2], i, count, cur_addr;
-       const unsigned int *addr, *data;
-
-       addr = ca0113_mmio_init_address_sbz;
-       for (i = 0; i < 3; i++)
-               writel(0x00000000, spec->mem_base + addr[i]);
-
-       cur_addr = i;
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_ZXR:
-               tmp[0] = 0x00880480;
-               tmp[1] = 0x00000080;
-               break;
-       case QUIRK_SBZ:
-               tmp[0] = 0x00820680;
-               tmp[1] = 0x00000083;
-               break;
-       case QUIRK_R3D:
-               tmp[0] = 0x00880680;
-               tmp[1] = 0x00000083;
-               break;
-       default:
-               tmp[0] = 0x00000000;
-               tmp[1] = 0x00000000;
-               break;
-       }
-
-       for (i = 0; i < 2; i++)
-               writel(tmp[i], spec->mem_base + addr[cur_addr + i]);
-
-       cur_addr += i;
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_ZXR:
-               count = ARRAY_SIZE(ca0113_mmio_init_data_zxr);
-               data = ca0113_mmio_init_data_zxr;
-               break;
-       default:
-               count = ARRAY_SIZE(ca0113_mmio_init_data_sbz);
-               data = ca0113_mmio_init_data_sbz;
-               break;
-       }
-
-       for (i = 0; i < count; i++)
-               writel(data[i], spec->mem_base + addr[cur_addr + i]);
-}
-
-static void ca0132_mmio_init_ae5(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       const unsigned int *addr, *data;
-       unsigned int i, count;
-
-       addr = ca0113_mmio_init_address_ae5;
-       data = ca0113_mmio_init_data_ae5;
-       count = ARRAY_SIZE(ca0113_mmio_init_data_ae5);
-
-       if (ca0132_quirk(spec) == QUIRK_AE7) {
-               writel(0x00000680, spec->mem_base + 0x1c);
-               writel(0x00880680, spec->mem_base + 0x1c);
-       }
-
-       for (i = 0; i < count; i++) {
-               /*
-                * AE-7 shares all writes with the AE-5, except that it writes
-                * a different value to 0x20c.
-                */
-               if (i == 21 && ca0132_quirk(spec) == QUIRK_AE7) {
-                       writel(0x00800001, spec->mem_base + addr[i]);
-                       continue;
-               }
-
-               writel(data[i], spec->mem_base + addr[i]);
-       }
-
-       if (ca0132_quirk(spec) == QUIRK_AE5)
-               writel(0x00880680, spec->mem_base + 0x1c);
-}
-
-static void ca0132_mmio_init(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_R3D:
-       case QUIRK_SBZ:
-       case QUIRK_ZXR:
-               ca0132_mmio_init_sbz(codec);
-               break;
-       case QUIRK_AE5:
-               ca0132_mmio_init_ae5(codec);
-               break;
-       default:
-               break;
-       }
-}
-
-static const unsigned int ca0132_ae5_register_set_addresses[] = {
-       0x304, 0x304, 0x304, 0x304, 0x100, 0x304, 0x100, 0x304, 0x100, 0x304,
-       0x100, 0x304, 0x86c, 0x800, 0x86c, 0x800, 0x804
-};
-
-static const unsigned char ca0132_ae5_register_set_data[] = {
-       0x0f, 0x0e, 0x1f, 0x0c, 0x3f, 0x08, 0x7f, 0x00, 0xff, 0x00, 0x6b,
-       0x01, 0x6b, 0x57
-};
-
-/*
- * This function writes to some SFR's, does some region2 writes, and then
- * eventually resets the codec with the 0x7ff verb. Not quite sure why it does
- * what it does.
- */
-static void ae5_register_set(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       unsigned int count = ARRAY_SIZE(ca0132_ae5_register_set_addresses);
-       const unsigned int *addr = ca0132_ae5_register_set_addresses;
-       const unsigned char *data = ca0132_ae5_register_set_data;
-       unsigned int i, cur_addr;
-       unsigned char tmp[3];
-
-       if (ca0132_quirk(spec) == QUIRK_AE7)
-               chipio_8051_write_pll_pmu(codec, 0x41, 0xc8);
-
-       chipio_8051_write_direct(codec, 0x93, 0x10);
-       chipio_8051_write_pll_pmu(codec, 0x44, 0xc2);
-
-       if (ca0132_quirk(spec) == QUIRK_AE7) {
-               tmp[0] = 0x03;
-               tmp[1] = 0x03;
-               tmp[2] = 0x07;
-       } else {
-               tmp[0] = 0x0f;
-               tmp[1] = 0x0f;
-               tmp[2] = 0x0f;
-       }
-
-       for (i = cur_addr = 0; i < 3; i++, cur_addr++)
-               writeb(tmp[i], spec->mem_base + addr[cur_addr]);
-
-       /*
-        * First writes are in single bytes, final are in 4 bytes. So, we use
-        * writeb, then writel.
-        */
-       for (i = 0; cur_addr < 12; i++, cur_addr++)
-               writeb(data[i], spec->mem_base + addr[cur_addr]);
-
-       for (; cur_addr < count; i++, cur_addr++)
-               writel(data[i], spec->mem_base + addr[cur_addr]);
-
-       writel(0x00800001, spec->mem_base + 0x20c);
-
-       if (ca0132_quirk(spec) == QUIRK_AE7) {
-               ca0113_mmio_command_set_type2(codec, 0x48, 0x07, 0x83);
-               ca0113_mmio_command_set(codec, 0x30, 0x2e, 0x3f);
-       } else {
-               ca0113_mmio_command_set(codec, 0x30, 0x2d, 0x3f);
-       }
-
-       chipio_8051_write_direct(codec, 0x90, 0x00);
-       chipio_8051_write_direct(codec, 0x90, 0x10);
-
-       if (ca0132_quirk(spec) == QUIRK_AE5)
-               ca0113_mmio_command_set(codec, 0x48, 0x07, 0x83);
-}
-
-/*
- * Extra init functions for alternative ca0132 codecs. Done
- * here so they don't clutter up the main ca0132_init function
- * anymore than they have to.
- */
-static void ca0132_alt_init(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       ca0132_alt_vol_setup(codec);
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-               codec_dbg(codec, "SBZ alt_init");
-               ca0132_gpio_init(codec);
-               sbz_pre_dsp_setup(codec);
-               snd_hda_sequence_write(codec, spec->chip_init_verbs);
-               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
-               break;
-       case QUIRK_R3DI:
-               codec_dbg(codec, "R3DI alt_init");
-               ca0132_gpio_init(codec);
-               ca0132_gpio_setup(codec);
-               r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADING);
-               r3di_pre_dsp_setup(codec);
-               snd_hda_sequence_write(codec, spec->chip_init_verbs);
-               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x6FF, 0xC4);
-               break;
-       case QUIRK_R3D:
-               r3d_pre_dsp_setup(codec);
-               snd_hda_sequence_write(codec, spec->chip_init_verbs);
-               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
-               break;
-       case QUIRK_AE5:
-               ca0132_gpio_init(codec);
-               chipio_8051_write_pll_pmu(codec, 0x49, 0x88);
-               chipio_write(codec, 0x18b030, 0x00000020);
-               snd_hda_sequence_write(codec, spec->chip_init_verbs);
-               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
-               ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
-               break;
-       case QUIRK_AE7:
-               ca0132_gpio_init(codec);
-               chipio_8051_write_pll_pmu(codec, 0x49, 0x88);
-               snd_hda_sequence_write(codec, spec->chip_init_verbs);
-               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
-               chipio_write(codec, 0x18b008, 0x000000f8);
-               chipio_write(codec, 0x18b008, 0x000000f0);
-               chipio_write(codec, 0x18b030, 0x00000020);
-               ca0113_mmio_command_set(codec, 0x30, 0x32, 0x3f);
-               break;
-       case QUIRK_ZXR:
-               chipio_8051_write_pll_pmu(codec, 0x49, 0x88);
-               snd_hda_sequence_write(codec, spec->chip_init_verbs);
-               snd_hda_sequence_write(codec, spec->desktop_init_verbs);
-               zxr_pre_dsp_setup(codec);
-               break;
-       default:
-               break;
-       }
-}
-
-static int ca0132_init(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       int i;
-       bool dsp_loaded;
-
-       /*
-        * If the DSP is already downloaded, and init has been entered again,
-        * there's only two reasons for it. One, the codec has awaken from a
-        * suspended state, and in that case dspload_is_loaded will return
-        * false, and the init will be ran again. The other reason it gets
-        * re entered is on startup for some reason it triggers a suspend and
-        * resume state. In this case, it will check if the DSP is downloaded,
-        * and not run the init function again. For codecs using alt_functions,
-        * it will check if the DSP is loaded properly.
-        */
-       if (spec->dsp_state == DSP_DOWNLOADED) {
-               dsp_loaded = dspload_is_loaded(codec);
-               if (!dsp_loaded) {
-                       spec->dsp_reload = true;
-                       spec->dsp_state = DSP_DOWNLOAD_INIT;
-               } else {
-                       if (ca0132_quirk(spec) == QUIRK_SBZ)
-                               sbz_dsp_startup_check(codec);
-                       return 0;
-               }
-       }
-
-       if (spec->dsp_state != DSP_DOWNLOAD_FAILED)
-               spec->dsp_state = DSP_DOWNLOAD_INIT;
-       spec->curr_chip_addx = INVALID_CHIP_ADDRESS;
-
-       if (ca0132_use_pci_mmio(spec))
-               ca0132_mmio_init(codec);
-
-       snd_hda_power_up_pm(codec);
-
-       if (ca0132_quirk(spec) == QUIRK_AE5 || ca0132_quirk(spec) == QUIRK_AE7)
-               ae5_register_set(codec);
-
-       ca0132_init_params(codec);
-       ca0132_init_flags(codec);
-
-       snd_hda_sequence_write(codec, spec->base_init_verbs);
-
-       if (ca0132_use_alt_functions(spec))
-               ca0132_alt_init(codec);
-
-       ca0132_download_dsp(codec);
-
-       ca0132_refresh_widget_caps(codec);
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_R3DI:
-       case QUIRK_R3D:
-               r3d_setup_defaults(codec);
-               break;
-       case QUIRK_SBZ:
-       case QUIRK_ZXR:
-               sbz_setup_defaults(codec);
-               break;
-       case QUIRK_AE5:
-               ae5_setup_defaults(codec);
-               break;
-       case QUIRK_AE7:
-               ae7_setup_defaults(codec);
-               break;
-       default:
-               ca0132_setup_defaults(codec);
-               ca0132_init_analog_mic2(codec);
-               ca0132_init_dmic(codec);
-               break;
-       }
-
-       for (i = 0; i < spec->num_outputs; i++)
-               init_output(codec, spec->out_pins[i], spec->dacs[0]);
-
-       init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
-
-       for (i = 0; i < spec->num_inputs; i++)
-               init_input(codec, spec->input_pins[i], spec->adcs[i]);
-
-       init_input(codec, cfg->dig_in_pin, spec->dig_in);
-
-       if (!ca0132_use_alt_functions(spec)) {
-               snd_hda_sequence_write(codec, spec->chip_init_verbs);
-               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_PARAM_EX_ID_SET, 0x0D);
-               snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0,
-                           VENDOR_CHIPIO_PARAM_EX_VALUE_SET, 0x20);
-       }
-
-       if (ca0132_quirk(spec) == QUIRK_SBZ)
-               ca0132_gpio_setup(codec);
-
-       snd_hda_sequence_write(codec, spec->spec_init_verbs);
-       if (ca0132_use_alt_functions(spec)) {
-               ca0132_alt_select_out(codec);
-               ca0132_alt_select_in(codec);
-       } else {
-               ca0132_select_out(codec);
-               ca0132_select_mic(codec);
-       }
-
-       snd_hda_jack_report_sync(codec);
-
-       /*
-        * Re set the PlayEnhancement switch on a resume event, because the
-        * controls will not be reloaded.
-        */
-       if (spec->dsp_reload) {
-               spec->dsp_reload = false;
-               ca0132_pe_switch_set(codec);
-       }
-
-       snd_hda_power_down_pm(codec);
-
-       return 0;
-}
-
-static int dbpro_init(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->autocfg;
-       unsigned int i;
-
-       init_output(codec, cfg->dig_out_pins[0], spec->dig_out);
-       init_input(codec, cfg->dig_in_pin, spec->dig_in);
-
-       for (i = 0; i < spec->num_inputs; i++)
-               init_input(codec, spec->input_pins[i], spec->adcs[i]);
-
-       return 0;
-}
-
-static void ca0132_free(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       cancel_delayed_work_sync(&spec->unsol_hp_work);
-       snd_hda_power_up(codec);
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-               sbz_exit_chip(codec);
-               break;
-       case QUIRK_ZXR:
-               zxr_exit_chip(codec);
-               break;
-       case QUIRK_R3D:
-               r3d_exit_chip(codec);
-               break;
-       case QUIRK_AE5:
-               ae5_exit_chip(codec);
-               break;
-       case QUIRK_AE7:
-               ae7_exit_chip(codec);
-               break;
-       case QUIRK_R3DI:
-               r3di_gpio_shutdown(codec);
-               break;
-       default:
-               break;
-       }
-
-       snd_hda_sequence_write(codec, spec->base_exit_verbs);
-       ca0132_exit_chip(codec);
-
-       snd_hda_power_down(codec);
-#ifdef CONFIG_PCI
-       if (spec->mem_base)
-               pci_iounmap(codec->bus->pci, spec->mem_base);
-#endif
-       kfree(spec->spec_init_verbs);
-       kfree(codec->spec);
-}
-
-static void dbpro_free(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       zxr_dbpro_power_state_shutdown(codec);
-
-       kfree(spec->spec_init_verbs);
-       kfree(codec->spec);
-}
-
-static int ca0132_suspend(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       cancel_delayed_work_sync(&spec->unsol_hp_work);
-       return 0;
-}
-
-static const struct hda_codec_ops ca0132_patch_ops = {
-       .build_controls = ca0132_build_controls,
-       .build_pcms = ca0132_build_pcms,
-       .init = ca0132_init,
-       .free = ca0132_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .suspend = ca0132_suspend,
-};
-
-static const struct hda_codec_ops dbpro_patch_ops = {
-       .build_controls = dbpro_build_controls,
-       .build_pcms = dbpro_build_pcms,
-       .init = dbpro_init,
-       .free = dbpro_free,
-};
-
-static void ca0132_config(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec = codec->spec;
-
-       spec->dacs[0] = 0x2;
-       spec->dacs[1] = 0x3;
-       spec->dacs[2] = 0x4;
-
-       spec->multiout.dac_nids = spec->dacs;
-       spec->multiout.num_dacs = 3;
-
-       if (!ca0132_use_alt_functions(spec))
-               spec->multiout.max_channels = 2;
-       else
-               spec->multiout.max_channels = 6;
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_ALIENWARE:
-               codec_dbg(codec, "%s: QUIRK_ALIENWARE applied.\n", __func__);
-               snd_hda_apply_pincfgs(codec, alienware_pincfgs);
-               break;
-       case QUIRK_SBZ:
-               codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__);
-               snd_hda_apply_pincfgs(codec, sbz_pincfgs);
-               break;
-       case QUIRK_ZXR:
-               codec_dbg(codec, "%s: QUIRK_ZXR applied.\n", __func__);
-               snd_hda_apply_pincfgs(codec, zxr_pincfgs);
-               break;
-       case QUIRK_R3D:
-               codec_dbg(codec, "%s: QUIRK_R3D applied.\n", __func__);
-               snd_hda_apply_pincfgs(codec, r3d_pincfgs);
-               break;
-       case QUIRK_R3DI:
-               codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__);
-               snd_hda_apply_pincfgs(codec, r3di_pincfgs);
-               break;
-       case QUIRK_AE5:
-               codec_dbg(codec, "%s: QUIRK_AE5 applied.\n", __func__);
-               snd_hda_apply_pincfgs(codec, ae5_pincfgs);
-               break;
-       case QUIRK_AE7:
-               codec_dbg(codec, "%s: QUIRK_AE7 applied.\n", __func__);
-               snd_hda_apply_pincfgs(codec, ae7_pincfgs);
-               break;
-       default:
-               break;
-       }
-
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_ALIENWARE:
-               spec->num_outputs = 2;
-               spec->out_pins[0] = 0x0b; /* speaker out */
-               spec->out_pins[1] = 0x0f;
-               spec->shared_out_nid = 0x2;
-               spec->unsol_tag_hp = 0x0f;
-
-               spec->adcs[0] = 0x7; /* digital mic / analog mic1 */
-               spec->adcs[1] = 0x8; /* analog mic2 */
-               spec->adcs[2] = 0xa; /* what u hear */
-
-               spec->num_inputs = 3;
-               spec->input_pins[0] = 0x12;
-               spec->input_pins[1] = 0x11;
-               spec->input_pins[2] = 0x13;
-               spec->shared_mic_nid = 0x7;
-               spec->unsol_tag_amic1 = 0x11;
-               break;
-       case QUIRK_SBZ:
-       case QUIRK_R3D:
-               spec->num_outputs = 2;
-               spec->out_pins[0] = 0x0B; /* Line out */
-               spec->out_pins[1] = 0x0F; /* Rear headphone out */
-               spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
-               spec->out_pins[3] = 0x11; /* Rear surround */
-               spec->shared_out_nid = 0x2;
-               spec->unsol_tag_hp = spec->out_pins[1];
-               spec->unsol_tag_front_hp = spec->out_pins[2];
-
-               spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
-               spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */
-               spec->adcs[2] = 0xa; /* what u hear */
-
-               spec->num_inputs = 2;
-               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
-               spec->input_pins[1] = 0x13; /* What U Hear */
-               spec->shared_mic_nid = 0x7;
-               spec->unsol_tag_amic1 = spec->input_pins[0];
-
-               /* SPDIF I/O */
-               spec->dig_out = 0x05;
-               spec->multiout.dig_out_nid = spec->dig_out;
-               spec->dig_in = 0x09;
-               break;
-       case QUIRK_ZXR:
-               spec->num_outputs = 2;
-               spec->out_pins[0] = 0x0B; /* Line out */
-               spec->out_pins[1] = 0x0F; /* Rear headphone out */
-               spec->out_pins[2] = 0x10; /* Center/LFE */
-               spec->out_pins[3] = 0x11; /* Rear surround */
-               spec->shared_out_nid = 0x2;
-               spec->unsol_tag_hp = spec->out_pins[1];
-               spec->unsol_tag_front_hp = spec->out_pins[2];
-
-               spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
-               spec->adcs[1] = 0x8; /* Not connected, no front mic */
-               spec->adcs[2] = 0xa; /* what u hear */
-
-               spec->num_inputs = 2;
-               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
-               spec->input_pins[1] = 0x13; /* What U Hear */
-               spec->shared_mic_nid = 0x7;
-               spec->unsol_tag_amic1 = spec->input_pins[0];
-               break;
-       case QUIRK_ZXR_DBPRO:
-               spec->adcs[0] = 0x8; /* ZxR DBPro Aux In */
-
-               spec->num_inputs = 1;
-               spec->input_pins[0] = 0x11; /* RCA Line-in */
-
-               spec->dig_out = 0x05;
-               spec->multiout.dig_out_nid = spec->dig_out;
-
-               spec->dig_in = 0x09;
-               break;
-       case QUIRK_AE5:
-       case QUIRK_AE7:
-               spec->num_outputs = 2;
-               spec->out_pins[0] = 0x0B; /* Line out */
-               spec->out_pins[1] = 0x11; /* Rear headphone out */
-               spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
-               spec->out_pins[3] = 0x0F; /* Rear surround */
-               spec->shared_out_nid = 0x2;
-               spec->unsol_tag_hp = spec->out_pins[1];
-               spec->unsol_tag_front_hp = spec->out_pins[2];
-
-               spec->adcs[0] = 0x7; /* Rear Mic / Line-in */
-               spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */
-               spec->adcs[2] = 0xa; /* what u hear */
-
-               spec->num_inputs = 2;
-               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
-               spec->input_pins[1] = 0x13; /* What U Hear */
-               spec->shared_mic_nid = 0x7;
-               spec->unsol_tag_amic1 = spec->input_pins[0];
-
-               /* SPDIF I/O */
-               spec->dig_out = 0x05;
-               spec->multiout.dig_out_nid = spec->dig_out;
-               break;
-       case QUIRK_R3DI:
-               spec->num_outputs = 2;
-               spec->out_pins[0] = 0x0B; /* Line out */
-               spec->out_pins[1] = 0x0F; /* Rear headphone out */
-               spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/
-               spec->out_pins[3] = 0x11; /* Rear surround */
-               spec->shared_out_nid = 0x2;
-               spec->unsol_tag_hp = spec->out_pins[1];
-               spec->unsol_tag_front_hp = spec->out_pins[2];
-
-               spec->adcs[0] = 0x07; /* Rear Mic / Line-in */
-               spec->adcs[1] = 0x08; /* Front Mic, but only if no DSP */
-               spec->adcs[2] = 0x0a; /* what u hear */
-
-               spec->num_inputs = 2;
-               spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */
-               spec->input_pins[1] = 0x13; /* What U Hear */
-               spec->shared_mic_nid = 0x7;
-               spec->unsol_tag_amic1 = spec->input_pins[0];
-
-               /* SPDIF I/O */
-               spec->dig_out = 0x05;
-               spec->multiout.dig_out_nid = spec->dig_out;
-               break;
-       default:
-               spec->num_outputs = 2;
-               spec->out_pins[0] = 0x0b; /* speaker out */
-               spec->out_pins[1] = 0x10; /* headphone out */
-               spec->shared_out_nid = 0x2;
-               spec->unsol_tag_hp = spec->out_pins[1];
-
-               spec->adcs[0] = 0x7; /* digital mic / analog mic1 */
-               spec->adcs[1] = 0x8; /* analog mic2 */
-               spec->adcs[2] = 0xa; /* what u hear */
-
-               spec->num_inputs = 3;
-               spec->input_pins[0] = 0x12;
-               spec->input_pins[1] = 0x11;
-               spec->input_pins[2] = 0x13;
-               spec->shared_mic_nid = 0x7;
-               spec->unsol_tag_amic1 = spec->input_pins[0];
-
-               /* SPDIF I/O */
-               spec->dig_out = 0x05;
-               spec->multiout.dig_out_nid = spec->dig_out;
-               spec->dig_in = 0x09;
-               break;
-       }
-}
-
-static int ca0132_prepare_verbs(struct hda_codec *codec)
-{
-/* Verbs + terminator (an empty element) */
-#define NUM_SPEC_VERBS 2
-       struct ca0132_spec *spec = codec->spec;
-
-       spec->chip_init_verbs = ca0132_init_verbs0;
-       /*
-        * Since desktop cards use pci_mmio, this can be used to determine
-        * whether or not to use these verbs instead of a separate bool.
-        */
-       if (ca0132_use_pci_mmio(spec))
-               spec->desktop_init_verbs = ca0132_init_verbs1;
-       spec->spec_init_verbs = kcalloc(NUM_SPEC_VERBS,
-                                       sizeof(struct hda_verb),
-                                       GFP_KERNEL);
-       if (!spec->spec_init_verbs)
-               return -ENOMEM;
-
-       /* config EAPD */
-       spec->spec_init_verbs[0].nid = 0x0b;
-       spec->spec_init_verbs[0].param = 0x78D;
-       spec->spec_init_verbs[0].verb = 0x00;
-
-       /* Previously commented configuration */
-       /*
-       spec->spec_init_verbs[2].nid = 0x0b;
-       spec->spec_init_verbs[2].param = AC_VERB_SET_EAPD_BTLENABLE;
-       spec->spec_init_verbs[2].verb = 0x02;
-
-       spec->spec_init_verbs[3].nid = 0x10;
-       spec->spec_init_verbs[3].param = 0x78D;
-       spec->spec_init_verbs[3].verb = 0x02;
-
-       spec->spec_init_verbs[4].nid = 0x10;
-       spec->spec_init_verbs[4].param = AC_VERB_SET_EAPD_BTLENABLE;
-       spec->spec_init_verbs[4].verb = 0x02;
-       */
-
-       /* Terminator: spec->spec_init_verbs[NUM_SPEC_VERBS-1] */
-       return 0;
-}
-
-/*
- * The Sound Blaster ZxR shares the same PCI subsystem ID as some regular
- * Sound Blaster Z cards. However, they have different HDA codec subsystem
- * ID's. So, we check for the ZxR's subsystem ID, as well as the DBPro
- * daughter boards ID.
- */
-static void sbz_detect_quirk(struct hda_codec *codec)
-{
-       switch (codec->core.subsystem_id) {
-       case 0x11020033:
-               codec->fixup_id = QUIRK_ZXR;
-               break;
-       case 0x1102003f:
-               codec->fixup_id = QUIRK_ZXR_DBPRO;
-               break;
-       default:
-               codec->fixup_id = QUIRK_SBZ;
-               break;
-       }
-}
-
-static int patch_ca0132(struct hda_codec *codec)
-{
-       struct ca0132_spec *spec;
-       int err;
-
-       codec_dbg(codec, "patch_ca0132\n");
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       codec->spec = spec;
-       spec->codec = codec;
-
-       /* Detect codec quirk */
-       snd_hda_pick_fixup(codec, ca0132_quirk_models, ca0132_quirks, NULL);
-       if (ca0132_quirk(spec) == QUIRK_SBZ)
-               sbz_detect_quirk(codec);
-
-       if (ca0132_quirk(spec) == QUIRK_ZXR_DBPRO)
-               codec->patch_ops = dbpro_patch_ops;
-       else
-               codec->patch_ops = ca0132_patch_ops;
-
-       codec->pcm_format_first = 1;
-       codec->no_sticky_stream = 1;
-
-
-       spec->dsp_state = DSP_DOWNLOAD_INIT;
-       spec->num_mixers = 1;
-
-       /* Set which mixers each quirk uses. */
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-               spec->mixers[0] = desktop_mixer;
-               snd_hda_codec_set_name(codec, "Sound Blaster Z");
-               break;
-       case QUIRK_ZXR:
-               spec->mixers[0] = desktop_mixer;
-               snd_hda_codec_set_name(codec, "Sound Blaster ZxR");
-               break;
-       case QUIRK_ZXR_DBPRO:
-               break;
-       case QUIRK_R3D:
-               spec->mixers[0] = desktop_mixer;
-               snd_hda_codec_set_name(codec, "Recon3D");
-               break;
-       case QUIRK_R3DI:
-               spec->mixers[0] = r3di_mixer;
-               snd_hda_codec_set_name(codec, "Recon3Di");
-               break;
-       case QUIRK_AE5:
-               spec->mixers[0] = desktop_mixer;
-               snd_hda_codec_set_name(codec, "Sound BlasterX AE-5");
-               break;
-       case QUIRK_AE7:
-               spec->mixers[0] = desktop_mixer;
-               snd_hda_codec_set_name(codec, "Sound Blaster AE-7");
-               break;
-       default:
-               spec->mixers[0] = ca0132_mixer;
-               break;
-       }
-
-       /* Setup whether or not to use alt functions/controls/pci_mmio */
-       switch (ca0132_quirk(spec)) {
-       case QUIRK_SBZ:
-       case QUIRK_R3D:
-       case QUIRK_AE5:
-       case QUIRK_AE7:
-       case QUIRK_ZXR:
-               spec->use_alt_controls = true;
-               spec->use_alt_functions = true;
-               spec->use_pci_mmio = true;
-               break;
-       case QUIRK_R3DI:
-               spec->use_alt_controls = true;
-               spec->use_alt_functions = true;
-               spec->use_pci_mmio = false;
-               break;
-       default:
-               spec->use_alt_controls = false;
-               spec->use_alt_functions = false;
-               spec->use_pci_mmio = false;
-               break;
-       }
-
-#ifdef CONFIG_PCI
-       if (spec->use_pci_mmio) {
-               spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20);
-               if (spec->mem_base == NULL) {
-                       codec_warn(codec, "pci_iomap failed! Setting quirk to QUIRK_NONE.");
-                       codec->fixup_id = QUIRK_NONE;
-               }
-       }
-#endif
-
-       spec->base_init_verbs = ca0132_base_init_verbs;
-       spec->base_exit_verbs = ca0132_base_exit_verbs;
-
-       INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed);
-
-       ca0132_init_chip(codec);
-
-       ca0132_config(codec);
-
-       err = ca0132_prepare_verbs(codec);
-       if (err < 0)
-               goto error;
-
-       err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL);
-       if (err < 0)
-               goto error;
-
-       ca0132_setup_unsol(codec);
-
-       return 0;
-
- error:
-       ca0132_free(codec);
-       return err;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_ca0132[] = {
-       HDA_CODEC_ENTRY(0x11020011, "CA0132", patch_ca0132),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_ca0132);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Creative Sound Core3D codec");
-
-static struct hda_codec_driver ca0132_driver = {
-       .id = snd_hda_id_ca0132,
-};
-
-module_hda_codec_driver(ca0132_driver);
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c
deleted file mode 100644 (file)
index 06e0462..0000000
+++ /dev/null
@@ -1,1243 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * HD audio interface patch for Cirrus Logic CS420x chip
- *
- * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <linux/pci.h>
-#include <sound/tlv.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-/*
- */
-
-struct cs_spec {
-       struct hda_gen_spec gen;
-
-       unsigned int gpio_mask;
-       unsigned int gpio_dir;
-       unsigned int gpio_data;
-       unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */
-       unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */
-
-       /* CS421x */
-       unsigned int spdif_detect:1;
-       unsigned int spdif_present:1;
-       unsigned int sense_b:1;
-       hda_nid_t vendor_nid;
-
-       /* for MBP SPDIF control */
-       int (*spdif_sw_put)(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_value *ucontrol);
-};
-
-/* available models with CS420x */
-enum {
-       CS420X_MBP53,
-       CS420X_MBP55,
-       CS420X_IMAC27,
-       CS420X_GPIO_13,
-       CS420X_GPIO_23,
-       CS420X_MBP101,
-       CS420X_MBP81,
-       CS420X_MBA42,
-       CS420X_AUTO,
-       /* aliases */
-       CS420X_IMAC27_122 = CS420X_GPIO_23,
-       CS420X_APPLE = CS420X_GPIO_13,
-};
-
-/* CS421x boards */
-enum {
-       CS421X_CDB4210,
-       CS421X_SENSE_B,
-       CS421X_STUMPY,
-};
-
-/* Vendor-specific processing widget */
-#define CS420X_VENDOR_NID      0x11
-#define CS_DIG_OUT1_PIN_NID    0x10
-#define CS_DIG_OUT2_PIN_NID    0x15
-#define CS_DMIC1_PIN_NID       0x0e
-#define CS_DMIC2_PIN_NID       0x12
-
-/* coef indices */
-#define IDX_SPDIF_STAT         0x0000
-#define IDX_SPDIF_CTL          0x0001
-#define IDX_ADC_CFG            0x0002
-/* SZC bitmask, 4 modes below:
- * 0 = immediate,
- * 1 = digital immediate, analog zero-cross
- * 2 = digtail & analog soft-ramp
- * 3 = digital soft-ramp, analog zero-cross
- */
-#define   CS_COEF_ADC_SZC_MASK         (3 << 0)
-#define   CS_COEF_ADC_MIC_SZC_MODE     (3 << 0) /* SZC setup for mic */
-#define   CS_COEF_ADC_LI_SZC_MODE      (3 << 0) /* SZC setup for line-in */
-/* PGA mode: 0 = differential, 1 = signle-ended */
-#define   CS_COEF_ADC_MIC_PGA_MODE     (1 << 5) /* PGA setup for mic */
-#define   CS_COEF_ADC_LI_PGA_MODE      (1 << 6) /* PGA setup for line-in */
-#define IDX_DAC_CFG            0x0003
-/* SZC bitmask, 4 modes below:
- * 0 = Immediate
- * 1 = zero-cross
- * 2 = soft-ramp
- * 3 = soft-ramp on zero-cross
- */
-#define   CS_COEF_DAC_HP_SZC_MODE      (3 << 0) /* nid 0x02 */
-#define   CS_COEF_DAC_LO_SZC_MODE      (3 << 2) /* nid 0x03 */
-#define   CS_COEF_DAC_SPK_SZC_MODE     (3 << 4) /* nid 0x04 */
-
-#define IDX_BEEP_CFG           0x0004
-/* 0x0008 - test reg key */
-/* 0x0009 - 0x0014 -> 12 test regs */
-/* 0x0015 - visibility reg */
-
-/* Cirrus Logic CS4208 */
-#define CS4208_VENDOR_NID      0x24
-
-/*
- * Cirrus Logic CS4210
- *
- * 1 DAC => HP(sense) / Speakers,
- * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
- * 1 SPDIF OUT => SPDIF Trasmitter(sense)
- */
-#define CS4210_DAC_NID         0x02
-#define CS4210_ADC_NID         0x03
-#define CS4210_VENDOR_NID      0x0B
-#define CS421X_DMIC_PIN_NID    0x09 /* Port E */
-#define CS421X_SPDIF_PIN_NID   0x0A /* Port H */
-
-#define CS421X_IDX_DEV_CFG     0x01
-#define CS421X_IDX_ADC_CFG     0x02
-#define CS421X_IDX_DAC_CFG     0x03
-#define CS421X_IDX_SPK_CTL     0x04
-
-/* Cirrus Logic CS4213 is like CS4210 but does not have SPDIF input/output */
-#define CS4213_VENDOR_NID      0x09
-
-
-static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
-{
-       struct cs_spec *spec = codec->spec;
-
-       snd_hda_codec_write(codec, spec->vendor_nid, 0,
-                           AC_VERB_SET_COEF_INDEX, idx);
-       return snd_hda_codec_read(codec, spec->vendor_nid, 0,
-                                 AC_VERB_GET_PROC_COEF, 0);
-}
-
-static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
-                                     unsigned int coef)
-{
-       struct cs_spec *spec = codec->spec;
-
-       snd_hda_codec_write(codec, spec->vendor_nid, 0,
-                           AC_VERB_SET_COEF_INDEX, idx);
-       snd_hda_codec_write(codec, spec->vendor_nid, 0,
-                           AC_VERB_SET_PROC_COEF, coef);
-}
-
-/*
- * auto-mute and auto-mic switching
- * CS421x auto-output redirecting
- * HP/SPK/SPDIF
- */
-
-static void cs_automute(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-
-       /* mute HPs if spdif jack (SENSE_B) is present */
-       spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b);
-
-       snd_hda_gen_update_outputs(codec);
-
-       if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) {
-               if (spec->gen.automute_speaker)
-                       spec->gpio_data = spec->gen.hp_jack_present ?
-                               spec->gpio_eapd_hp : spec->gpio_eapd_speaker;
-               else
-                       spec->gpio_data =
-                               spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
-               snd_hda_codec_write(codec, 0x01, 0,
-                                   AC_VERB_SET_GPIO_DATA, spec->gpio_data);
-       }
-}
-
-static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int val;
-
-       val = snd_hda_codec_get_pincfg(codec, nid);
-       return (get_defcfg_connect(val) != AC_JACK_PORT_NONE);
-}
-
-static void init_input_coef(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-       unsigned int coef;
-
-       /* CS420x has multiple ADC, CS421x has single ADC */
-       if (spec->vendor_nid == CS420X_VENDOR_NID) {
-               coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG);
-               if (is_active_pin(codec, CS_DMIC2_PIN_NID))
-                       coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */
-               if (is_active_pin(codec, CS_DMIC1_PIN_NID))
-                       coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off
-                                        * No effect if SPDIF_OUT2 is
-                                        * selected in IDX_SPDIF_CTL.
-                                        */
-
-               cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef);
-       }
-}
-
-static const struct hda_verb cs_coef_init_verbs[] = {
-       {0x11, AC_VERB_SET_PROC_STATE, 1},
-       {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG},
-       {0x11, AC_VERB_SET_PROC_COEF,
-        (0x002a /* DAC1/2/3 SZCMode Soft Ramp */
-         | 0x0040 /* Mute DACs on FIFO error */
-         | 0x1000 /* Enable DACs High Pass Filter */
-         | 0x0400 /* Disable Coefficient Auto increment */
-         )},
-       /* ADC1/2 - Digital and Analog Soft Ramp */
-       {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG},
-       {0x11, AC_VERB_SET_PROC_COEF, 0x000a},
-       /* Beep */
-       {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG},
-       {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */
-
-       {} /* terminator */
-};
-
-static const struct hda_verb cs4208_coef_init_verbs[] = {
-       {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
-       {0x24, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
-       {0x24, AC_VERB_SET_COEF_INDEX, 0x0033},
-       {0x24, AC_VERB_SET_PROC_COEF, 0x0001}, /* A1 ICS */
-       {0x24, AC_VERB_SET_COEF_INDEX, 0x0034},
-       {0x24, AC_VERB_SET_PROC_COEF, 0x1C01}, /* A1 Enable, A Thresh = 300mV */
-       {} /* terminator */
-};
-
-/* Errata: CS4207 rev C0/C1/C2 Silicon
- *
- * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf
- *
- * 6. At high temperature (TA > +85°C), the digital supply current (IVD)
- * may be excessive (up to an additional 200 Î¼A), which is most easily
- * observed while the part is being held in reset (RESET# active low).
- *
- * Root Cause: At initial powerup of the device, the logic that drives
- * the clock and write enable to the S/PDIF SRC RAMs is not properly
- * initialized.
- * Certain random patterns will cause a steady leakage current in those
- * RAM cells. The issue will resolve once the SRCs are used (turned on).
- *
- * Workaround: The following verb sequence briefly turns on the S/PDIF SRC
- * blocks, which will alleviate the issue.
- */
-
-static const struct hda_verb cs_errata_init_verbs[] = {
-       {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */
-       {0x11, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
-
-       {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
-       {0x11, AC_VERB_SET_PROC_COEF, 0x9999},
-       {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
-       {0x11, AC_VERB_SET_PROC_COEF, 0xa412},
-       {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
-       {0x11, AC_VERB_SET_PROC_COEF, 0x0009},
-
-       {0x07, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Rx: D0 */
-       {0x08, AC_VERB_SET_POWER_STATE, 0x00}, /* S/PDIF Tx: D0 */
-
-       {0x11, AC_VERB_SET_COEF_INDEX, 0x0017},
-       {0x11, AC_VERB_SET_PROC_COEF, 0x2412},
-       {0x11, AC_VERB_SET_COEF_INDEX, 0x0008},
-       {0x11, AC_VERB_SET_PROC_COEF, 0x0000},
-       {0x11, AC_VERB_SET_COEF_INDEX, 0x0001},
-       {0x11, AC_VERB_SET_PROC_COEF, 0x0008},
-       {0x11, AC_VERB_SET_PROC_STATE, 0x00},
-       {} /* terminator */
-};
-
-/* SPDIF setup */
-static void init_digital_coef(struct hda_codec *codec)
-{
-       unsigned int coef;
-
-       coef = 0x0002; /* SRC_MUTE soft-mute on SPDIF (if no lock) */
-       coef |= 0x0008; /* Replace with mute on error */
-       if (is_active_pin(codec, CS_DIG_OUT2_PIN_NID))
-               coef |= 0x4000; /* RX to TX1 or TX2 Loopthru / SPDIF2
-                                * SPDIF_OUT2 is shared with GPIO1 and
-                                * DMIC_SDA2.
-                                */
-       cs_vendor_coef_set(codec, IDX_SPDIF_CTL, coef);
-}
-
-static int cs_init(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-
-       if (spec->vendor_nid == CS420X_VENDOR_NID) {
-               /* init_verb sequence for C0/C1/C2 errata*/
-               snd_hda_sequence_write(codec, cs_errata_init_verbs);
-               snd_hda_sequence_write(codec, cs_coef_init_verbs);
-       } else if (spec->vendor_nid == CS4208_VENDOR_NID) {
-               snd_hda_sequence_write(codec, cs4208_coef_init_verbs);
-       }
-
-       snd_hda_gen_init(codec);
-
-       if (spec->gpio_mask) {
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
-                                   spec->gpio_mask);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
-                                   spec->gpio_dir);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_data);
-       }
-
-       if (spec->vendor_nid == CS420X_VENDOR_NID) {
-               init_input_coef(codec);
-               init_digital_coef(codec);
-       }
-
-       return 0;
-}
-
-static int cs_build_controls(struct hda_codec *codec)
-{
-       int err;
-
-       err = snd_hda_gen_build_controls(codec);
-       if (err < 0)
-               return err;
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
-       return 0;
-}
-
-#define cs_free                snd_hda_gen_free
-
-static const struct hda_codec_ops cs_patch_ops = {
-       .build_controls = cs_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = cs_init,
-       .free = cs_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-};
-
-static int cs_parse_auto_config(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-       int err;
-       int i;
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
-       if (err < 0)
-               return err;
-
-       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
-       if (err < 0)
-               return err;
-
-       /* keep the ADCs powered up when it's dynamically switchable */
-       if (spec->gen.dyn_adc_switch) {
-               unsigned int done = 0;
-
-               for (i = 0; i < spec->gen.input_mux.num_items; i++) {
-                       int idx = spec->gen.dyn_adc_idx[i];
-
-                       if (done & (1 << idx))
-                               continue;
-                       snd_hda_gen_fix_pin_power(codec,
-                                                 spec->gen.adc_nids[idx]);
-                       done |= 1 << idx;
-               }
-       }
-
-       return 0;
-}
-
-static const struct hda_model_fixup cs420x_models[] = {
-       { .id = CS420X_MBP53, .name = "mbp53" },
-       { .id = CS420X_MBP55, .name = "mbp55" },
-       { .id = CS420X_IMAC27, .name = "imac27" },
-       { .id = CS420X_IMAC27_122, .name = "imac27_122" },
-       { .id = CS420X_APPLE, .name = "apple" },
-       { .id = CS420X_MBP101, .name = "mbp101" },
-       { .id = CS420X_MBP81, .name = "mbp81" },
-       { .id = CS420X_MBA42, .name = "mba42" },
-       {}
-};
-
-static const struct hda_quirk cs420x_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x10de, 0x0ac0, "MacBookPro 5,3", CS420X_MBP53),
-       SND_PCI_QUIRK(0x10de, 0x0d94, "MacBookAir 3,1(2)", CS420X_MBP55),
-       SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55),
-       SND_PCI_QUIRK(0x10de, 0xcb89, "MacBookPro 7,1", CS420X_MBP55),
-       /* this conflicts with too many other models */
-       /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/
-
-       /* codec SSID */
-       SND_PCI_QUIRK(0x106b, 0x0600, "iMac 14,1", CS420X_IMAC27_122),
-       SND_PCI_QUIRK(0x106b, 0x0900, "iMac 12,1", CS420X_IMAC27_122),
-       SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81),
-       SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122),
-       SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101),
-       SND_PCI_QUIRK(0x106b, 0x5600, "MacBookAir 5,2", CS420X_MBP81),
-       SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42),
-       SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE),
-       {} /* terminator */
-};
-
-static const struct hda_pintbl mbp53_pincfgs[] = {
-       { 0x09, 0x012b4050 },
-       { 0x0a, 0x90100141 },
-       { 0x0b, 0x90100140 },
-       { 0x0c, 0x018b3020 },
-       { 0x0d, 0x90a00110 },
-       { 0x0e, 0x400000f0 },
-       { 0x0f, 0x01cbe030 },
-       { 0x10, 0x014be060 },
-       { 0x12, 0x400000f0 },
-       { 0x15, 0x400000f0 },
-       {} /* terminator */
-};
-
-static const struct hda_pintbl mbp55_pincfgs[] = {
-       { 0x09, 0x012b4030 },
-       { 0x0a, 0x90100121 },
-       { 0x0b, 0x90100120 },
-       { 0x0c, 0x400000f0 },
-       { 0x0d, 0x90a00110 },
-       { 0x0e, 0x400000f0 },
-       { 0x0f, 0x400000f0 },
-       { 0x10, 0x014be040 },
-       { 0x12, 0x400000f0 },
-       { 0x15, 0x400000f0 },
-       {} /* terminator */
-};
-
-static const struct hda_pintbl imac27_pincfgs[] = {
-       { 0x09, 0x012b4050 },
-       { 0x0a, 0x90100140 },
-       { 0x0b, 0x90100142 },
-       { 0x0c, 0x018b3020 },
-       { 0x0d, 0x90a00110 },
-       { 0x0e, 0x400000f0 },
-       { 0x0f, 0x01cbe030 },
-       { 0x10, 0x014be060 },
-       { 0x12, 0x01ab9070 },
-       { 0x15, 0x400000f0 },
-       {} /* terminator */
-};
-
-static const struct hda_pintbl mbp101_pincfgs[] = {
-       { 0x0d, 0x40ab90f0 },
-       { 0x0e, 0x90a600f0 },
-       { 0x12, 0x50a600f0 },
-       {} /* terminator */
-};
-
-static const struct hda_pintbl mba42_pincfgs[] = {
-       { 0x09, 0x012b4030 }, /* HP */
-       { 0x0a, 0x400000f0 },
-       { 0x0b, 0x90100120 }, /* speaker */
-       { 0x0c, 0x400000f0 },
-       { 0x0d, 0x90a00110 }, /* mic */
-       { 0x0e, 0x400000f0 },
-       { 0x0f, 0x400000f0 },
-       { 0x10, 0x400000f0 },
-       { 0x12, 0x400000f0 },
-       { 0x15, 0x400000f0 },
-       {} /* terminator */
-};
-
-static const struct hda_pintbl mba6_pincfgs[] = {
-       { 0x10, 0x032120f0 }, /* HP */
-       { 0x11, 0x500000f0 },
-       { 0x12, 0x90100010 }, /* Speaker */
-       { 0x13, 0x500000f0 },
-       { 0x14, 0x500000f0 },
-       { 0x15, 0x770000f0 },
-       { 0x16, 0x770000f0 },
-       { 0x17, 0x430000f0 },
-       { 0x18, 0x43ab9030 }, /* Mic */
-       { 0x19, 0x770000f0 },
-       { 0x1a, 0x770000f0 },
-       { 0x1b, 0x770000f0 },
-       { 0x1c, 0x90a00090 },
-       { 0x1d, 0x500000f0 },
-       { 0x1e, 0x500000f0 },
-       { 0x1f, 0x500000f0 },
-       { 0x20, 0x500000f0 },
-       { 0x21, 0x430000f0 },
-       { 0x22, 0x430000f0 },
-       {} /* terminator */
-};
-
-static void cs420x_fixup_gpio_13(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               struct cs_spec *spec = codec->spec;
-
-               spec->gpio_eapd_hp = 2; /* GPIO1 = headphones */
-               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
-               spec->gpio_mask = spec->gpio_dir =
-                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
-       }
-}
-
-static void cs420x_fixup_gpio_23(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               struct cs_spec *spec = codec->spec;
-
-               spec->gpio_eapd_hp = 4; /* GPIO2 = headphones */
-               spec->gpio_eapd_speaker = 8; /* GPIO3 = speakers */
-               spec->gpio_mask = spec->gpio_dir =
-                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
-       }
-}
-
-static const struct hda_fixup cs420x_fixups[] = {
-       [CS420X_MBP53] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = mbp53_pincfgs,
-               .chained = true,
-               .chain_id = CS420X_APPLE,
-       },
-       [CS420X_MBP55] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = mbp55_pincfgs,
-               .chained = true,
-               .chain_id = CS420X_GPIO_13,
-       },
-       [CS420X_IMAC27] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = imac27_pincfgs,
-               .chained = true,
-               .chain_id = CS420X_GPIO_13,
-       },
-       [CS420X_GPIO_13] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs420x_fixup_gpio_13,
-       },
-       [CS420X_GPIO_23] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs420x_fixup_gpio_23,
-       },
-       [CS420X_MBP101] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = mbp101_pincfgs,
-               .chained = true,
-               .chain_id = CS420X_GPIO_13,
-       },
-       [CS420X_MBP81] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* internal mic ADC2: right only, single ended */
-                       {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG},
-                       {0x11, AC_VERB_SET_PROC_COEF, 0x102a},
-                       {}
-               },
-               .chained = true,
-               .chain_id = CS420X_GPIO_13,
-       },
-       [CS420X_MBA42] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = mba42_pincfgs,
-               .chained = true,
-               .chain_id = CS420X_GPIO_13,
-       },
-};
-
-static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid)
-{
-       struct cs_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return NULL;
-       codec->spec = spec;
-       spec->vendor_nid = vendor_nid;
-       codec->power_save_node = 1;
-       snd_hda_gen_spec_init(&spec->gen);
-
-       return spec;
-}
-
-static int patch_cs420x(struct hda_codec *codec)
-{
-       struct cs_spec *spec;
-       int err;
-
-       spec = cs_alloc_spec(codec, CS420X_VENDOR_NID);
-       if (!spec)
-               return -ENOMEM;
-
-       codec->patch_ops = cs_patch_ops;
-       spec->gen.automute_hook = cs_automute;
-       codec->single_adc_amp = 1;
-
-       snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl,
-                          cs420x_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = cs_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       cs_free(codec);
-       return err;
-}
-
-/*
- * CS4208 support:
- * Its layout is no longer compatible with CS4206/CS4207
- */
-enum {
-       CS4208_MAC_AUTO,
-       CS4208_MBA6,
-       CS4208_MBP11,
-       CS4208_MACMINI,
-       CS4208_GPIO0,
-};
-
-static const struct hda_model_fixup cs4208_models[] = {
-       { .id = CS4208_GPIO0, .name = "gpio0" },
-       { .id = CS4208_MBA6, .name = "mba6" },
-       { .id = CS4208_MBP11, .name = "mbp11" },
-       { .id = CS4208_MACMINI, .name = "macmini" },
-       {}
-};
-
-static const struct hda_quirk cs4208_fixup_tbl[] = {
-       SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO),
-       {} /* terminator */
-};
-
-/* codec SSID matching */
-static const struct hda_quirk cs4208_mac_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
-       SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI),
-       SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
-       SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
-       SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11),
-       {} /* terminator */
-};
-
-static void cs4208_fixup_gpio0(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               struct cs_spec *spec = codec->spec;
-
-               spec->gpio_eapd_hp = 0;
-               spec->gpio_eapd_speaker = 1;
-               spec->gpio_mask = spec->gpio_dir =
-                       spec->gpio_eapd_hp | spec->gpio_eapd_speaker;
-       }
-}
-
-static const struct hda_fixup cs4208_fixups[];
-
-/* remap the fixup from codec SSID and apply it */
-static void cs4208_fixup_mac(struct hda_codec *codec,
-                            const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
-       snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups);
-       if (codec->fixup_id == HDA_FIXUP_ID_NOT_SET)
-               codec->fixup_id = CS4208_GPIO0; /* default fixup */
-       snd_hda_apply_fixup(codec, action);
-}
-
-/* MacMini 7,1 has the inverted jack detection */
-static void cs4208_fixup_macmini(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */
-               { 0x21, 0x004be140 }, /* SPDIF: disable detect */
-               { }
-       };
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               /* HP pin (0x10) has an inverted detection */
-               codec->inv_jack_detect = 1;
-               /* disable the bogus Mic and SPDIF jack detections */
-               snd_hda_apply_pincfgs(codec, pincfgs);
-       }
-}
-
-static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct cs_spec *spec = codec->spec;
-       hda_nid_t pin = spec->gen.autocfg.dig_out_pins[0];
-       int pinctl = ucontrol->value.integer.value[0] ? PIN_OUT : 0;
-
-       snd_hda_set_pin_ctl_cache(codec, pin, pinctl);
-       return spec->spdif_sw_put(kcontrol, ucontrol);
-}
-
-/* hook the SPDIF switch */
-static void cs4208_fixup_spdif_switch(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_BUILD) {
-               struct cs_spec *spec = codec->spec;
-               struct snd_kcontrol *kctl;
-
-               if (!spec->gen.autocfg.dig_out_pins[0])
-                       return;
-               kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch");
-               if (!kctl)
-                       return;
-               spec->spdif_sw_put = kctl->put;
-               kctl->put = cs4208_spdif_sw_put;
-       }
-}
-
-static const struct hda_fixup cs4208_fixups[] = {
-       [CS4208_MBA6] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = mba6_pincfgs,
-               .chained = true,
-               .chain_id = CS4208_GPIO0,
-       },
-       [CS4208_MBP11] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs4208_fixup_spdif_switch,
-               .chained = true,
-               .chain_id = CS4208_GPIO0,
-       },
-       [CS4208_MACMINI] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs4208_fixup_macmini,
-               .chained = true,
-               .chain_id = CS4208_GPIO0,
-       },
-       [CS4208_GPIO0] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs4208_fixup_gpio0,
-       },
-       [CS4208_MAC_AUTO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs4208_fixup_mac,
-       },
-};
-
-/* correct the 0dB offset of input pins */
-static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc)
-{
-       unsigned int caps;
-
-       caps = query_amp_caps(codec, adc, HDA_INPUT);
-       caps &= ~(AC_AMPCAP_OFFSET);
-       caps |= 0x02;
-       snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps);
-}
-
-static int patch_cs4208(struct hda_codec *codec)
-{
-       struct cs_spec *spec;
-       int err;
-
-       spec = cs_alloc_spec(codec, CS4208_VENDOR_NID);
-       if (!spec)
-               return -ENOMEM;
-
-       codec->patch_ops = cs_patch_ops;
-       spec->gen.automute_hook = cs_automute;
-       /* exclude NID 0x10 (HP) from output volumes due to different steps */
-       spec->gen.out_vol_mask = 1ULL << 0x10;
-
-       snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl,
-                          cs4208_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       snd_hda_override_wcaps(codec, 0x18,
-                              get_wcaps(codec, 0x18) | AC_WCAP_STEREO);
-       cs4208_fix_amp_caps(codec, 0x18);
-       cs4208_fix_amp_caps(codec, 0x1b);
-       cs4208_fix_amp_caps(codec, 0x1c);
-
-       err = cs_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       cs_free(codec);
-       return err;
-}
-
-/*
- * Cirrus Logic CS4210
- *
- * 1 DAC => HP(sense) / Speakers,
- * 1 ADC <= LineIn(sense) / MicIn / DMicIn,
- * 1 SPDIF OUT => SPDIF Trasmitter(sense)
- */
-
-/* CS4210 board names */
-static const struct hda_model_fixup cs421x_models[] = {
-       { .id = CS421X_CDB4210, .name = "cdb4210" },
-       { .id = CS421X_STUMPY, .name = "stumpy" },
-       {}
-};
-
-static const struct hda_quirk cs421x_fixup_tbl[] = {
-       /* Test Intel board + CDB2410  */
-       SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210),
-       {} /* terminator */
-};
-
-/* CS4210 board pinconfigs */
-/* Default CS4210 (CDB4210)*/
-static const struct hda_pintbl cdb4210_pincfgs[] = {
-       { 0x05, 0x0321401f },
-       { 0x06, 0x90170010 },
-       { 0x07, 0x03813031 },
-       { 0x08, 0xb7a70037 },
-       { 0x09, 0xb7a6003e },
-       { 0x0a, 0x034510f0 },
-       {} /* terminator */
-};
-
-/* Stumpy ChromeBox */
-static const struct hda_pintbl stumpy_pincfgs[] = {
-       { 0x05, 0x022120f0 },
-       { 0x06, 0x901700f0 },
-       { 0x07, 0x02a120f0 },
-       { 0x08, 0x77a70037 },
-       { 0x09, 0x77a6003e },
-       { 0x0a, 0x434510f0 },
-       {} /* terminator */
-};
-
-/* Setup GPIO/SENSE for each board (if used) */
-static void cs421x_fixup_sense_b(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       struct cs_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->sense_b = 1;
-}
-
-static const struct hda_fixup cs421x_fixups[] = {
-       [CS421X_CDB4210] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cdb4210_pincfgs,
-               .chained = true,
-               .chain_id = CS421X_SENSE_B,
-       },
-       [CS421X_SENSE_B] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs421x_fixup_sense_b,
-       },
-       [CS421X_STUMPY] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stumpy_pincfgs,
-       },
-};
-
-static const struct hda_verb cs421x_coef_init_verbs[] = {
-       {0x0B, AC_VERB_SET_PROC_STATE, 1},
-       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG},
-       /*
-        *  Disable Coefficient Index Auto-Increment(DAI)=1,
-        *  PDREF=0
-        */
-       {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 },
-
-       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG},
-       /* ADC SZCMode = Digital Soft Ramp */
-       {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 },
-
-       {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG},
-       {0x0B, AC_VERB_SET_PROC_COEF,
-        (0x0002 /* DAC SZCMode = Digital Soft Ramp */
-         | 0x0004 /* Mute DAC on FIFO error */
-         | 0x0008 /* Enable DAC High Pass Filter */
-         )},
-       {} /* terminator */
-};
-
-/* Errata: CS4210 rev A1 Silicon
- *
- * http://www.cirrus.com/en/pubs/errata/
- *
- * Description:
- * 1. Performance degredation is present in the ADC.
- * 2. Speaker output is not completely muted upon HP detect.
- * 3. Noise is present when clipping occurs on the amplified
- *    speaker outputs.
- *
- * Workaround:
- * The following verb sequence written to the registers during
- * initialization will correct the issues listed above.
- */
-
-static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = {
-       {0x0B, AC_VERB_SET_PROC_STATE, 0x01},  /* VPW: processing on */
-
-       {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006},
-       {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */
-
-       {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A},
-       {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */
-
-       {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011},
-       {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */
-
-       {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A},
-       {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */
-
-       {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B},
-       {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */
-
-       {} /* terminator */
-};
-
-/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */
-static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0);
-
-static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 3;
-       return 0;
-}
-
-static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] =
-               cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003;
-       return 0;
-}
-
-static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-
-       unsigned int vol = ucontrol->value.integer.value[0];
-       unsigned int coef =
-               cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL);
-       unsigned int original_coef = coef;
-
-       coef &= ~0x0003;
-       coef |= (vol & 0x0003);
-       if (original_coef != coef) {
-               cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef);
-               return 1;
-       }
-
-       return 0;
-}
-
-static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = {
-
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE |
-                       SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-       .name = "Speaker Boost Playback Volume",
-       .info = cs421x_boost_vol_info,
-       .get = cs421x_boost_vol_get,
-       .put = cs421x_boost_vol_put,
-       .tlv = { .p = cs421x_speaker_boost_db_scale },
-};
-
-static void cs4210_pinmux_init(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-       unsigned int def_conf, coef;
-
-       /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */
-       coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
-
-       if (spec->gpio_mask)
-               coef |= 0x0008; /* B1,B2 are GPIOs */
-       else
-               coef &= ~0x0008;
-
-       if (spec->sense_b)
-               coef |= 0x0010; /* B2 is SENSE_B, not inverted  */
-       else
-               coef &= ~0x0010;
-
-       cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
-
-       if ((spec->gpio_mask || spec->sense_b) &&
-           is_active_pin(codec, CS421X_DMIC_PIN_NID)) {
-
-               /*
-                *  GPIO or SENSE_B forced - disconnect the DMIC pin.
-                */
-               def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID);
-               def_conf &= ~AC_DEFCFG_PORT_CONN;
-               def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT);
-               snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf);
-       }
-}
-
-static void cs4210_spdif_automute(struct hda_codec *codec,
-                                 struct hda_jack_callback *tbl)
-{
-       struct cs_spec *spec = codec->spec;
-       bool spdif_present = false;
-       hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0];
-
-       /* detect on spdif is specific to CS4210 */
-       if (!spec->spdif_detect ||
-           spec->vendor_nid != CS4210_VENDOR_NID)
-               return;
-
-       spdif_present = snd_hda_jack_detect(codec, spdif_pin);
-       if (spdif_present == spec->spdif_present)
-               return;
-
-       spec->spdif_present = spdif_present;
-       /* SPDIF TX on/off */
-       snd_hda_set_pin_ctl(codec, spdif_pin, spdif_present ? PIN_OUT : 0);
-
-       cs_automute(codec);
-}
-
-static void parse_cs421x_digital(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-       int i;
-
-       for (i = 0; i < cfg->dig_outs; i++) {
-               hda_nid_t nid = cfg->dig_out_pins[i];
-
-               if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) {
-                       spec->spdif_detect = 1;
-                       snd_hda_jack_detect_enable_callback(codec, nid,
-                                                           cs4210_spdif_automute);
-               }
-       }
-}
-
-static int cs421x_init(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-
-       if (spec->vendor_nid == CS4210_VENDOR_NID) {
-               snd_hda_sequence_write(codec, cs421x_coef_init_verbs);
-               snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes);
-               cs4210_pinmux_init(codec);
-       }
-
-       snd_hda_gen_init(codec);
-
-       if (spec->gpio_mask) {
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
-                                   spec->gpio_mask);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
-                                   spec->gpio_dir);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_data);
-       }
-
-       init_input_coef(codec);
-
-       cs4210_spdif_automute(codec, NULL);
-
-       return 0;
-}
-
-static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac)
-{
-       unsigned int caps;
-
-       /* set the upper-limit for mixer amp to 0dB */
-       caps = query_amp_caps(codec, dac, HDA_OUTPUT);
-       caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT);
-       caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f)
-               << AC_AMPCAP_NUM_STEPS_SHIFT;
-       snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps);
-}
-
-static int cs421x_parse_auto_config(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-       hda_nid_t dac = CS4210_DAC_NID;
-       int err;
-
-       fix_volume_caps(codec, dac);
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
-       if (err < 0)
-               return err;
-
-       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
-       if (err < 0)
-               return err;
-
-       parse_cs421x_digital(codec);
-
-       if (spec->gen.autocfg.speaker_outs &&
-           spec->vendor_nid == CS4210_VENDOR_NID) {
-               if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
-                                         &cs421x_speaker_boost_ctl))
-                       return -ENOMEM;
-       }
-
-       return 0;
-}
-
-/*
- *     Manage PDREF, when transitioning to D3hot
- *     (DAC,ADC) -> D3, PDREF=1, AFG->D3
- */
-static int cs421x_suspend(struct hda_codec *codec)
-{
-       struct cs_spec *spec = codec->spec;
-       unsigned int coef;
-
-       snd_hda_shutup_pins(codec);
-
-       snd_hda_codec_write(codec, CS4210_DAC_NID, 0,
-                           AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
-       snd_hda_codec_write(codec, CS4210_ADC_NID, 0,
-                           AC_VERB_SET_POWER_STATE,  AC_PWRST_D3);
-
-       if (spec->vendor_nid == CS4210_VENDOR_NID) {
-               coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG);
-               coef |= 0x0004; /* PDREF */
-               cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef);
-       }
-
-       return 0;
-}
-
-static const struct hda_codec_ops cs421x_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = cs421x_init,
-       .free = cs_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .suspend = cs421x_suspend,
-};
-
-static int patch_cs4210(struct hda_codec *codec)
-{
-       struct cs_spec *spec;
-       int err;
-
-       spec = cs_alloc_spec(codec, CS4210_VENDOR_NID);
-       if (!spec)
-               return -ENOMEM;
-
-       codec->patch_ops = cs421x_patch_ops;
-       spec->gen.automute_hook = cs_automute;
-
-       snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl,
-                          cs421x_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       /*
-        *  Update the GPIO/DMIC/SENSE_B pinmux before the configuration
-        *   is auto-parsed. If GPIO or SENSE_B is forced, DMIC input
-        *   is disabled.
-        */
-       cs4210_pinmux_init(codec);
-
-       err = cs421x_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       cs_free(codec);
-       return err;
-}
-
-static int patch_cs4213(struct hda_codec *codec)
-{
-       struct cs_spec *spec;
-       int err;
-
-       spec = cs_alloc_spec(codec, CS4213_VENDOR_NID);
-       if (!spec)
-               return -ENOMEM;
-
-       codec->patch_ops = cs421x_patch_ops;
-
-       err = cs421x_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       cs_free(codec);
-       return err;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_cirrus[] = {
-       HDA_CODEC_ENTRY(0x10134206, "CS4206", patch_cs420x),
-       HDA_CODEC_ENTRY(0x10134207, "CS4207", patch_cs420x),
-       HDA_CODEC_ENTRY(0x10134208, "CS4208", patch_cs4208),
-       HDA_CODEC_ENTRY(0x10134210, "CS4210", patch_cs4210),
-       HDA_CODEC_ENTRY(0x10134213, "CS4213", patch_cs4213),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cirrus);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cirrus Logic HD-audio codec");
-
-static struct hda_codec_driver cirrus_driver = {
-       .id = snd_hda_id_cirrus,
-};
-
-module_hda_codec_driver(cirrus_driver);
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c
deleted file mode 100644 (file)
index fe946d4..0000000
+++ /dev/null
@@ -1,396 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for C-Media CMI9880
- *
- * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-/* CM9825 Offset Definitions */
-
-#define CM9825_VERB_SET_HPF_1 0x781
-#define CM9825_VERB_SET_HPF_2 0x785
-#define CM9825_VERB_SET_PLL 0x7a0
-#define CM9825_VERB_SET_NEG 0x7a1
-#define CM9825_VERB_SET_ADCL 0x7a2
-#define CM9825_VERB_SET_DACL 0x7a3
-#define CM9825_VERB_SET_MBIAS 0x7a4
-#define CM9825_VERB_SET_VNEG 0x7a8
-#define CM9825_VERB_SET_D2S 0x7a9
-#define CM9825_VERB_SET_DACTRL 0x7aa
-#define CM9825_VERB_SET_PDNEG 0x7ac
-#define CM9825_VERB_SET_VDO 0x7ad
-#define CM9825_VERB_SET_CDALR 0x7b0
-#define CM9825_VERB_SET_MTCBA 0x7b1
-#define CM9825_VERB_SET_OTP 0x7b2
-#define CM9825_VERB_SET_OCP 0x7b3
-#define CM9825_VERB_SET_GAD 0x7b4
-#define CM9825_VERB_SET_TMOD 0x7b5
-#define CM9825_VERB_SET_SNR 0x7b6
-
-struct cmi_spec {
-       struct hda_gen_spec gen;
-       const struct hda_verb *chip_d0_verbs;
-       const struct hda_verb *chip_d3_verbs;
-       const struct hda_verb *chip_hp_present_verbs;
-       const struct hda_verb *chip_hp_remove_verbs;
-       struct hda_codec *codec;
-       struct delayed_work unsol_hp_work;
-       int quirk;
-};
-
-static const struct hda_verb cm9825_std_d3_verbs[] = {
-       /* chip sleep verbs */
-       {0x43, CM9825_VERB_SET_D2S, 0x62},      /* depop */
-       {0x43, CM9825_VERB_SET_PLL, 0x01},      /* PLL set */
-       {0x43, CM9825_VERB_SET_NEG, 0xc2},      /* NEG set */
-       {0x43, CM9825_VERB_SET_ADCL, 0x00},     /* ADC */
-       {0x43, CM9825_VERB_SET_DACL, 0x02},     /* DACL */
-       {0x43, CM9825_VERB_SET_VNEG, 0x50},     /* VOL NEG */
-       {0x43, CM9825_VERB_SET_MBIAS, 0x00},    /* MBIAS */
-       {0x43, CM9825_VERB_SET_PDNEG, 0x04},    /* SEL OSC */
-       {0x43, CM9825_VERB_SET_CDALR, 0xf6},    /* Class D */
-       {0x43, CM9825_VERB_SET_OTP, 0xcd},      /* OTP set */
-       {}
-};
-
-static const struct hda_verb cm9825_std_d0_verbs[] = {
-       /* chip init verbs */
-       {0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},       /* EAPD set */
-       {0x43, CM9825_VERB_SET_SNR, 0x30},      /* SNR set */
-       {0x43, CM9825_VERB_SET_PLL, 0x00},      /* PLL set */
-       {0x43, CM9825_VERB_SET_ADCL, 0x00},     /* ADC */
-       {0x43, CM9825_VERB_SET_DACL, 0x02},     /* DACL */
-       {0x43, CM9825_VERB_SET_MBIAS, 0x00},    /* MBIAS */
-       {0x43, CM9825_VERB_SET_VNEG, 0x56},     /* VOL NEG */
-       {0x43, CM9825_VERB_SET_D2S, 0x62},      /* depop */
-       {0x43, CM9825_VERB_SET_DACTRL, 0x00},   /* DACTRL set */
-       {0x43, CM9825_VERB_SET_PDNEG, 0x0c},    /* SEL OSC */
-       {0x43, CM9825_VERB_SET_VDO, 0x80},      /* VDO set */
-       {0x43, CM9825_VERB_SET_CDALR, 0xf4},    /* Class D */
-       {0x43, CM9825_VERB_SET_OTP, 0xcd},      /* OTP set */
-       {0x43, CM9825_VERB_SET_MTCBA, 0x61},    /* SR set */
-       {0x43, CM9825_VERB_SET_OCP, 0x33},      /* OTP set */
-       {0x43, CM9825_VERB_SET_GAD, 0x07},      /* ADC -3db */
-       {0x43, CM9825_VERB_SET_TMOD, 0x26},     /* Class D clk */
-       {0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
-               AC_AMP_SET_OUTPUT | AC_AMP_SET_RIGHT, 0x2d},    /* Gain set */
-       {0x3C, AC_VERB_SET_AMP_GAIN_MUTE |
-               AC_AMP_SET_OUTPUT | AC_AMP_SET_LEFT, 0x2d},     /* Gain set */
-       {0x43, CM9825_VERB_SET_HPF_1, 0x40},    /* HPF set */
-       {0x43, CM9825_VERB_SET_HPF_2, 0x40},    /* HPF set */
-       {}
-};
-
-static const struct hda_verb cm9825_hp_present_verbs[] = {
-       {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00},   /* PIN off */
-       {0x43, CM9825_VERB_SET_ADCL, 0x88},     /* ADC */
-       {0x43, CM9825_VERB_SET_DACL, 0xaa},     /* DACL */
-       {0x43, CM9825_VERB_SET_MBIAS, 0x10},    /* MBIAS */
-       {0x43, CM9825_VERB_SET_D2S, 0xf2},      /* depop */
-       {0x43, CM9825_VERB_SET_DACTRL, 0x00},   /* DACTRL set */
-       {0x43, CM9825_VERB_SET_VDO, 0xc4},      /* VDO set */
-       {}
-};
-
-static const struct hda_verb cm9825_hp_remove_verbs[] = {
-       {0x43, CM9825_VERB_SET_ADCL, 0x00},     /* ADC */
-       {0x43, CM9825_VERB_SET_DACL, 0x56},     /* DACL */
-       {0x43, CM9825_VERB_SET_MBIAS, 0x00},    /* MBIAS */
-       {0x43, CM9825_VERB_SET_D2S, 0x62},      /* depop */
-       {0x43, CM9825_VERB_SET_DACTRL, 0xe0},   /* DACTRL set */
-       {0x43, CM9825_VERB_SET_VDO, 0x80},      /* VDO set */
-       {0x42, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40},   /* PIN on */
-       {}
-};
-
-static void cm9825_unsol_hp_delayed(struct work_struct *work)
-{
-       struct cmi_spec *spec =
-           container_of(to_delayed_work(work), struct cmi_spec, unsol_hp_work);
-       struct hda_jack_tbl *jack;
-       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
-       bool hp_jack_plugin = false;
-       int err = 0;
-
-       hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
-
-       codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
-                 (int)hp_jack_plugin, hp_pin);
-
-       if (!hp_jack_plugin) {
-               err =
-                   snd_hda_codec_write(spec->codec, 0x42, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
-               if (err)
-                       codec_dbg(spec->codec, "codec_write err %d\n", err);
-
-               snd_hda_sequence_write(spec->codec, spec->chip_hp_remove_verbs);
-       } else {
-               snd_hda_sequence_write(spec->codec,
-                                      spec->chip_hp_present_verbs);
-       }
-
-       jack = snd_hda_jack_tbl_get(spec->codec, hp_pin);
-       if (jack) {
-               jack->block_report = 0;
-               snd_hda_jack_report_sync(spec->codec);
-       }
-}
-
-static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
-{
-       struct cmi_spec *spec = codec->spec;
-       struct hda_jack_tbl *tbl;
-
-       /* Delay enabling the HP amp, to let the mic-detection
-        * state machine run.
-        */
-
-       codec_dbg(spec->codec, "cb->nid 0x%X\n", cb->nid);
-
-       tbl = snd_hda_jack_tbl_get(codec, cb->nid);
-       if (tbl)
-               tbl->block_report = 1;
-       schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200));
-}
-
-static void cm9825_setup_unsol(struct hda_codec *codec)
-{
-       struct cmi_spec *spec = codec->spec;
-
-       hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0];
-
-       snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
-}
-
-static int cm9825_init(struct hda_codec *codec)
-{
-       snd_hda_gen_init(codec);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
-
-       return 0;
-}
-
-static void cm9825_free(struct hda_codec *codec)
-{
-       struct cmi_spec *spec = codec->spec;
-
-       cancel_delayed_work_sync(&spec->unsol_hp_work);
-       snd_hda_gen_free(codec);
-}
-
-static int cm9825_suspend(struct hda_codec *codec)
-{
-       struct cmi_spec *spec = codec->spec;
-
-       cancel_delayed_work_sync(&spec->unsol_hp_work);
-
-       snd_hda_sequence_write(codec, spec->chip_d3_verbs);
-
-       return 0;
-}
-
-static int cm9825_resume(struct hda_codec *codec)
-{
-       struct cmi_spec *spec = codec->spec;
-       hda_nid_t hp_pin = 0;
-       bool hp_jack_plugin = false;
-       int err;
-
-       err =
-           snd_hda_codec_write(spec->codec, 0x42, 0,
-                               AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
-       if (err)
-               codec_dbg(codec, "codec_write err %d\n", err);
-
-       msleep(150);            /* for depop noise */
-
-       codec->patch_ops.init(codec);
-
-       hp_pin = spec->gen.autocfg.hp_pins[0];
-       hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
-
-       codec_dbg(spec->codec, "hp_jack_plugin %d, hp_pin 0x%X\n",
-                 (int)hp_jack_plugin, hp_pin);
-
-       if (!hp_jack_plugin) {
-               err =
-                   snd_hda_codec_write(spec->codec, 0x42, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40);
-
-               if (err)
-                       codec_dbg(codec, "codec_write err %d\n", err);
-
-               snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
-       }
-
-       snd_hda_regmap_sync(codec);
-       hda_call_check_power_status(codec, 0x01);
-
-       return 0;
-}
-
-/*
- * stuff for auto-parser
- */
-static const struct hda_codec_ops cmi_auto_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = snd_hda_gen_init,
-       .free = snd_hda_gen_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-};
-
-static int patch_cm9825(struct hda_codec *codec)
-{
-       struct cmi_spec *spec;
-       struct auto_pin_cfg *cfg;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       INIT_DELAYED_WORK(&spec->unsol_hp_work, cm9825_unsol_hp_delayed);
-       codec->spec = spec;
-       spec->codec = codec;
-       codec->patch_ops = cmi_auto_patch_ops;
-       codec->patch_ops.init = cm9825_init;
-       codec->patch_ops.suspend = cm9825_suspend;
-       codec->patch_ops.resume = cm9825_resume;
-       codec->patch_ops.free = cm9825_free;
-       codec->patch_ops.check_power_status = snd_hda_gen_check_power_status;
-       cfg = &spec->gen.autocfg;
-       snd_hda_gen_spec_init(&spec->gen);
-       spec->chip_d0_verbs = cm9825_std_d0_verbs;
-       spec->chip_d3_verbs = cm9825_std_d3_verbs;
-       spec->chip_hp_present_verbs = cm9825_hp_present_verbs;
-       spec->chip_hp_remove_verbs = cm9825_hp_remove_verbs;
-
-       snd_hda_sequence_write(codec, spec->chip_d0_verbs);
-
-       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
-       if (err < 0)
-               goto error;
-       err = snd_hda_gen_parse_auto_config(codec, cfg);
-       if (err < 0)
-               goto error;
-
-       cm9825_setup_unsol(codec);
-
-       return 0;
-
- error:
-       cm9825_free(codec);
-
-       codec_info(codec, "Enter err %d\n", err);
-
-       return err;
-}
-
-static int patch_cmi9880(struct hda_codec *codec)
-{
-       struct cmi_spec *spec;
-       struct auto_pin_cfg *cfg;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       codec->spec = spec;
-       codec->patch_ops = cmi_auto_patch_ops;
-       cfg = &spec->gen.autocfg;
-       snd_hda_gen_spec_init(&spec->gen);
-
-       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
-       if (err < 0)
-               goto error;
-       err = snd_hda_gen_parse_auto_config(codec, cfg);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-static int patch_cmi8888(struct hda_codec *codec)
-{
-       struct cmi_spec *spec;
-       struct auto_pin_cfg *cfg;
-       int err;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-
-       codec->spec = spec;
-       codec->patch_ops = cmi_auto_patch_ops;
-       cfg = &spec->gen.autocfg;
-       snd_hda_gen_spec_init(&spec->gen);
-
-       /* mask NID 0x10 from the playback volume selection;
-        * it's a headphone boost volume handled manually below
-        */
-       spec->gen.out_vol_mask = (1ULL << 0x10);
-
-       err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
-       if (err < 0)
-               goto error;
-       err = snd_hda_gen_parse_auto_config(codec, cfg);
-       if (err < 0)
-               goto error;
-
-       if (get_defcfg_device(snd_hda_codec_get_pincfg(codec, 0x10)) ==
-           AC_JACK_HP_OUT) {
-               static const struct snd_kcontrol_new amp_kctl =
-                       HDA_CODEC_VOLUME("Headphone Amp Playback Volume",
-                                        0x10, 0, HDA_OUTPUT);
-               if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &amp_kctl)) {
-                       err = -ENOMEM;
-                       goto error;
-               }
-       }
-
-       return 0;
-
- error:
-       snd_hda_gen_free(codec);
-       return err;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_cmedia[] = {
-       HDA_CODEC_ENTRY(0x13f68888, "CMI8888", patch_cmi8888),
-       HDA_CODEC_ENTRY(0x13f69880, "CMI9880", patch_cmi9880),
-       HDA_CODEC_ENTRY(0x434d4980, "CMI9880", patch_cmi9880),
-       HDA_CODEC_ENTRY(0x13f69825, "CM9825", patch_cm9825),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cmedia);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("C-Media HD-audio codec");
-
-static struct hda_codec_driver cmedia_driver = {
-       .id = snd_hda_id_cmedia,
-};
-
-module_hda_codec_driver(cmedia_driver);
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c
deleted file mode 100644 (file)
index e584a7b..0000000
+++ /dev/null
@@ -1,1331 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * HD audio interface patch for Conexant HDA audio codec
- *
- * Copyright (c) 2006 Pototskiy Akex <alex.pototskiy@gmail.com>
- *                   Takashi Iwai <tiwai@suse.de>
- *                   Tobin Davis  <tdavis@dsl-only.net>
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_beep.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-struct conexant_spec {
-       struct hda_gen_spec gen;
-
-       /* extra EAPD pins */
-       unsigned int num_eapds;
-       hda_nid_t eapds[4];
-       bool dynamic_eapd;
-       hda_nid_t mute_led_eapd;
-
-       unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
-
-       /* OPLC XO specific */
-       bool recording;
-       bool dc_enable;
-       unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */
-       struct nid_path *dc_mode_path;
-
-       int mute_led_polarity;
-       unsigned int gpio_led;
-       unsigned int gpio_mute_led_mask;
-       unsigned int gpio_mic_led_mask;
-       bool is_cx11880_sn6140;
-};
-
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-/* additional beep mixers; private_value will be overwritten */
-static const struct snd_kcontrol_new cxt_beep_mixer[] = {
-       HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
-};
-
-static int set_beep_amp(struct conexant_spec *spec, hda_nid_t nid,
-                       int idx, int dir)
-{
-       struct snd_kcontrol_new *knew;
-       unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
-       int i;
-
-       spec->gen.beep_nid = nid;
-       for (i = 0; i < ARRAY_SIZE(cxt_beep_mixer); i++) {
-               knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
-                                           &cxt_beep_mixer[i]);
-               if (!knew)
-                       return -ENOMEM;
-               knew->private_value = beep_amp;
-       }
-       return 0;
-}
-
-static int cx_auto_parse_beep(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       for_each_hda_codec_node(nid, codec)
-               if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
-                       return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
-       return 0;
-}
-#else
-#define cx_auto_parse_beep(codec)      0
-#endif
-
-/*
- * Automatic parser for CX20641 & co
- */
-
-/* parse EAPDs */
-static void cx_auto_parse_eapd(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       for_each_hda_codec_node(nid, codec) {
-               if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
-                       continue;
-               if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
-                       continue;
-               spec->eapds[spec->num_eapds++] = nid;
-               if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
-                       break;
-       }
-
-       /* NOTE: below is a wild guess; if we have more than two EAPDs,
-        * it's a new chip, where EAPDs are supposed to be associated to
-        * pins, and we can control EAPD per pin.
-        * OTOH, if only one or two EAPDs are found, it's an old chip,
-        * thus it might control over all pins.
-        */
-       if (spec->num_eapds > 2)
-               spec->dynamic_eapd = 1;
-}
-
-static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins,
-                             const hda_nid_t *pins, bool on)
-{
-       int i;
-       for (i = 0; i < num_pins; i++) {
-               if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
-                       snd_hda_codec_write(codec, pins[i], 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE,
-                                           on ? 0x02 : 0);
-       }
-}
-
-/* turn on/off EAPD according to Master switch */
-static void cx_auto_vmaster_hook(void *private_data, int enabled)
-{
-       struct hda_codec *codec = private_data;
-       struct conexant_spec *spec = codec->spec;
-
-       cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
-}
-
-/* turn on/off EAPD according to Master switch (inversely!) for mute LED */
-static int cx_auto_vmaster_mute_led(struct led_classdev *led_cdev,
-                                   enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct conexant_spec *spec = codec->spec;
-
-       snd_hda_codec_write(codec, spec->mute_led_eapd, 0,
-                           AC_VERB_SET_EAPD_BTLENABLE,
-                           brightness ? 0x02 : 0x00);
-       return 0;
-}
-
-static void cxt_init_gpio_led(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
-
-       if (mask) {
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
-                                   mask);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
-                                   mask);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_led);
-       }
-}
-
-static void cx_fixup_headset_recog(struct hda_codec *codec)
-{
-       unsigned int mic_present;
-
-       /* fix some headset type recognize fail issue, such as EDIFIER headset */
-       /* set micbias output current comparator threshold from 66% to 55%. */
-       snd_hda_codec_write(codec, 0x1c, 0, 0x320, 0x010);
-       /* set OFF voltage for DFET from -1.2V to -0.8V, set headset micbias register
-        * value adjustment trim from 2.2K ohms to 2.0K ohms.
-        */
-       snd_hda_codec_write(codec, 0x1c, 0, 0x3b0, 0xe10);
-       /* fix reboot headset type recognize fail issue */
-       mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0);
-       if (mic_present & AC_PINSENSE_PRESENCE)
-               /* enable headset mic VREF */
-               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
-       else
-               /* disable headset mic VREF */
-               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
-}
-
-static int cx_auto_init(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       snd_hda_gen_init(codec);
-       if (!spec->dynamic_eapd)
-               cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true);
-
-       cxt_init_gpio_led(codec);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
-
-       if (spec->is_cx11880_sn6140)
-               cx_fixup_headset_recog(codec);
-
-       return 0;
-}
-
-static void cx_auto_shutdown(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-
-       /* Turn the problematic codec into D3 to avoid spurious noises
-          from the internal speaker during (and after) reboot */
-       cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
-}
-
-static void cx_auto_free(struct hda_codec *codec)
-{
-       cx_auto_shutdown(codec);
-       snd_hda_gen_free(codec);
-}
-
-static void cx_process_headset_plugin(struct hda_codec *codec)
-{
-       unsigned int val;
-       unsigned int count = 0;
-
-       /* Wait headset detect done. */
-       do {
-               val = snd_hda_codec_read(codec, 0x1c, 0, 0xca0, 0x0);
-               if (val & 0x080) {
-                       codec_dbg(codec, "headset type detect done!\n");
-                       break;
-               }
-               msleep(20);
-               count++;
-       } while (count < 3);
-       val = snd_hda_codec_read(codec, 0x1c, 0, 0xcb0, 0x0);
-       if (val & 0x800) {
-               codec_dbg(codec, "headset plugin, type is CTIA\n");
-               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
-       } else if (val & 0x400) {
-               codec_dbg(codec, "headset plugin, type is OMTP\n");
-               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24);
-       } else {
-               codec_dbg(codec, "headphone plugin\n");
-       }
-}
-
-static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_callback *event)
-{
-       unsigned int mic_present;
-
-       /* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled,
-        * the node 19 can only be configured to microphone or disabled.
-        * Check hp&mic tag to process headset plugin & plugout.
-        */
-       mic_present = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0x0);
-       if (!(mic_present & AC_PINSENSE_PRESENCE)) /* mic plugout */
-               snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20);
-       else
-               cx_process_headset_plugin(codec);
-}
-
-static int cx_auto_suspend(struct hda_codec *codec)
-{
-       cx_auto_shutdown(codec);
-       return 0;
-}
-
-static const struct hda_codec_ops cx_auto_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = cx_auto_init,
-       .free = cx_auto_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .suspend = cx_auto_suspend,
-       .check_power_status = snd_hda_gen_check_power_status,
-};
-
-/*
- * pin fix-up
- */
-enum {
-       CXT_PINCFG_LENOVO_X200,
-       CXT_PINCFG_LENOVO_TP410,
-       CXT_PINCFG_LEMOTE_A1004,
-       CXT_PINCFG_LEMOTE_A1205,
-       CXT_PINCFG_COMPAQ_CQ60,
-       CXT_FIXUP_STEREO_DMIC,
-       CXT_PINCFG_LENOVO_NOTEBOOK,
-       CXT_FIXUP_INC_MIC_BOOST,
-       CXT_FIXUP_HEADPHONE_MIC_PIN,
-       CXT_FIXUP_HEADPHONE_MIC,
-       CXT_FIXUP_GPIO1,
-       CXT_FIXUP_ASPIRE_DMIC,
-       CXT_FIXUP_THINKPAD_ACPI,
-       CXT_FIXUP_LENOVO_XPAD_ACPI,
-       CXT_FIXUP_OLPC_XO,
-       CXT_FIXUP_CAP_MIX_AMP,
-       CXT_FIXUP_TOSHIBA_P105,
-       CXT_FIXUP_HP_530,
-       CXT_FIXUP_CAP_MIX_AMP_5047,
-       CXT_FIXUP_MUTE_LED_EAPD,
-       CXT_FIXUP_HP_DOCK,
-       CXT_FIXUP_HP_SPECTRE,
-       CXT_FIXUP_HP_GATE_MIC,
-       CXT_FIXUP_MUTE_LED_GPIO,
-       CXT_FIXUP_HP_ELITEONE_OUT_DIS,
-       CXT_FIXUP_HP_ZBOOK_MUTE_LED,
-       CXT_FIXUP_HEADSET_MIC,
-       CXT_FIXUP_HP_MIC_NO_PRESENCE,
-       CXT_PINCFG_SWS_JS201D,
-       CXT_PINCFG_TOP_SPEAKER,
-       CXT_FIXUP_HP_A_U,
-};
-
-/* for hda_fixup_thinkpad_acpi() */
-#include "thinkpad_helper.c"
-
-/* for hda_fixup_ideapad_acpi() */
-#include "ideapad_hotkey_led_helper.c"
-
-static void cxt_fixup_stereo_dmic(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       struct conexant_spec *spec = codec->spec;
-       spec->gen.inv_dmic_split = 1;
-}
-
-/* fix widget control pin settings */
-static void cxt_fixup_update_pinctl(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               /* Unset OUT_EN for this Node pin, leaving only HP_EN.
-                * This is the value stored in the codec register after
-                * the correct initialization of the previous windows boot.
-                */
-               snd_hda_set_pin_ctl_cache(codec, 0x1d, AC_PINCTL_HP_EN);
-       }
-}
-
-static void cxt5066_increase_mic_boost(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       snd_hda_override_amp_caps(codec, 0x17, HDA_OUTPUT,
-                                 (0x3 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (0x4 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (0 << AC_AMPCAP_MUTE_SHIFT));
-}
-
-static void cxt_update_headset_mode(struct hda_codec *codec)
-{
-       /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */
-       int i;
-       bool mic_mode = false;
-       struct conexant_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-
-       hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
-
-       for (i = 0; i < cfg->num_inputs; i++)
-               if (cfg->inputs[i].pin == mux_pin) {
-                       mic_mode = !!cfg->inputs[i].is_headphone_mic;
-                       break;
-               }
-
-       if (mic_mode) {
-               snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */
-               spec->gen.hp_jack_present = false;
-       } else {
-               snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */
-               spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]);
-       }
-
-       snd_hda_gen_update_outputs(codec);
-}
-
-static void cxt_update_headset_mode_hook(struct hda_codec *codec,
-                                        struct snd_kcontrol *kcontrol,
-                                        struct snd_ctl_elem_value *ucontrol)
-{
-       cxt_update_headset_mode(codec);
-}
-
-static void cxt_fixup_headphone_mic(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct conexant_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC;
-               snd_hdac_regmap_add_vendor_verb(&codec->core, 0x410);
-               break;
-       case HDA_FIXUP_ACT_PROBE:
-               WARN_ON(spec->gen.cap_sync_hook);
-               spec->gen.cap_sync_hook = cxt_update_headset_mode_hook;
-               spec->gen.automute_hook = cxt_update_headset_mode;
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               cxt_update_headset_mode(codec);
-               break;
-       }
-}
-
-static void cxt_fixup_headset_mic(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct conexant_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-               break;
-       }
-}
-
-/* OPLC XO 1.5 fixup */
-
-/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors)
- * through the microphone jack.
- * When the user enables this through a mixer switch, both internal and
- * external microphones are disabled. Gain is fixed at 0dB. In this mode,
- * we also allow the bias to be configured through a separate mixer
- * control. */
-
-#define update_mic_pin(codec, nid, val)                                        \
-       snd_hda_codec_write_cache(codec, nid, 0,                        \
-                                  AC_VERB_SET_PIN_WIDGET_CONTROL, val)
-
-static const struct hda_input_mux olpc_xo_dc_bias = {
-       .num_items = 3,
-       .items = {
-               { "Off", PIN_IN },
-               { "50%", PIN_VREF50 },
-               { "80%", PIN_VREF80 },
-       },
-};
-
-static void olpc_xo_update_mic_boost(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       int ch, val;
-
-       for (ch = 0; ch < 2; ch++) {
-               val = AC_AMP_SET_OUTPUT |
-                       (ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT);
-               if (!spec->dc_enable)
-                       val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0);
-               snd_hda_codec_write(codec, 0x17, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, val);
-       }
-}
-
-static void olpc_xo_update_mic_pins(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       int cur_input, val;
-       struct nid_path *path;
-
-       cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]];
-
-       /* Set up mic pins for port-B, C and F dynamically as the recording
-        * LED is turned on/off by these pin controls
-        */
-       if (!spec->dc_enable) {
-               /* disable DC bias path and pin for port F */
-               update_mic_pin(codec, 0x1e, 0);
-               snd_hda_activate_path(codec, spec->dc_mode_path, false, false);
-
-               /* update port B (ext mic) and C (int mic) */
-               /* OLPC defers mic widget control until when capture is
-                * started because the microphone LED comes on as soon as
-                * these settings are put in place. if we did this before
-                * recording, it would give the false indication that
-                * recording is happening when it is not.
-                */
-               update_mic_pin(codec, 0x1a, spec->recording ?
-                              snd_hda_codec_get_pin_target(codec, 0x1a) : 0);
-               update_mic_pin(codec, 0x1b, spec->recording ?
-                              snd_hda_codec_get_pin_target(codec, 0x1b) : 0);
-               /* enable normal mic path */
-               path = snd_hda_get_path_from_idx(codec, cur_input);
-               if (path)
-                       snd_hda_activate_path(codec, path, true, false);
-       } else {
-               /* disable normal mic path */
-               path = snd_hda_get_path_from_idx(codec, cur_input);
-               if (path)
-                       snd_hda_activate_path(codec, path, false, false);
-
-               /* Even though port F is the DC input, the bias is controlled
-                * on port B.  We also leave that port as an active input (but
-                * unselected) in DC mode just in case that is necessary to
-                * make the bias setting take effect.
-                */
-               if (spec->recording)
-                       val = olpc_xo_dc_bias.items[spec->dc_input_bias].index;
-               else
-                       val = 0;
-               update_mic_pin(codec, 0x1a, val);
-               update_mic_pin(codec, 0x1b, 0);
-               /* enable DC bias path and pin */
-               update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0);
-               snd_hda_activate_path(codec, spec->dc_mode_path, true, false);
-       }
-}
-
-/* mic_autoswitch hook */
-static void olpc_xo_automic(struct hda_codec *codec,
-                           struct hda_jack_callback *jack)
-{
-       struct conexant_spec *spec = codec->spec;
-
-       /* in DC mode, we don't handle automic */
-       if (!spec->dc_enable)
-               snd_hda_gen_mic_autoswitch(codec, jack);
-       olpc_xo_update_mic_pins(codec);
-       if (spec->dc_enable)
-               olpc_xo_update_mic_boost(codec);
-}
-
-/* pcm_capture hook */
-static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo,
-                                struct hda_codec *codec,
-                                struct snd_pcm_substream *substream,
-                                int action)
-{
-       struct conexant_spec *spec = codec->spec;
-
-       /* toggle spec->recording flag and update mic pins accordingly
-        * for turning on/off LED
-        */
-       switch (action) {
-       case HDA_GEN_PCM_ACT_PREPARE:
-               spec->recording = 1;
-               olpc_xo_update_mic_pins(codec);
-               break;
-       case HDA_GEN_PCM_ACT_CLEANUP:
-               spec->recording = 0;
-               olpc_xo_update_mic_pins(codec);
-               break;
-       }
-}
-
-static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       ucontrol->value.integer.value[0] = spec->dc_enable;
-       return 0;
-}
-
-static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       int dc_enable = !!ucontrol->value.integer.value[0];
-
-       if (dc_enable == spec->dc_enable)
-               return 0;
-
-       spec->dc_enable = dc_enable;
-       olpc_xo_update_mic_pins(codec);
-       olpc_xo_update_mic_boost(codec);
-       return 1;
-}
-
-static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       ucontrol->value.enumerated.item[0] = spec->dc_input_bias;
-       return 0;
-}
-
-static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_info *uinfo)
-{
-       return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo);
-}
-
-static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       const struct hda_input_mux *imux = &olpc_xo_dc_bias;
-       unsigned int idx;
-
-       idx = ucontrol->value.enumerated.item[0];
-       if (idx >= imux->num_items)
-               idx = imux->num_items - 1;
-       if (spec->dc_input_bias == idx)
-               return 0;
-
-       spec->dc_input_bias = idx;
-       if (spec->dc_enable)
-               olpc_xo_update_mic_pins(codec);
-       return 1;
-}
-
-static const struct snd_kcontrol_new olpc_xo_mixers[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "DC Mode Enable Switch",
-               .info = snd_ctl_boolean_mono_info,
-               .get = olpc_xo_dc_mode_get,
-               .put = olpc_xo_dc_mode_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "DC Input Bias Enum",
-               .info = olpc_xo_dc_bias_enum_info,
-               .get = olpc_xo_dc_bias_enum_get,
-               .put = olpc_xo_dc_bias_enum_put,
-       },
-       {}
-};
-
-/* overriding mic boost put callback; update mic boost volume only when
- * DC mode is disabled
- */
-static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct conexant_spec *spec = codec->spec;
-       int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol);
-       if (ret > 0 && spec->dc_enable)
-               olpc_xo_update_mic_boost(codec);
-       return ret;
-}
-
-static void cxt_fixup_olpc_xo(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct conexant_spec *spec = codec->spec;
-       struct snd_kcontrol_new *kctl;
-       int i;
-
-       if (action != HDA_FIXUP_ACT_PROBE)
-               return;
-
-       spec->gen.mic_autoswitch_hook = olpc_xo_automic;
-       spec->gen.pcm_capture_hook = olpc_xo_capture_hook;
-       spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0);
-
-       snd_hda_add_new_ctls(codec, olpc_xo_mixers);
-
-       /* OLPC's microphone port is DC coupled for use with external sensors,
-        * therefore we use a 50% mic bias in order to center the input signal
-        * with the DC input range of the codec.
-        */
-       snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50);
-
-       /* override mic boost control */
-       snd_array_for_each(&spec->gen.kctls, i, kctl) {
-               if (!strcmp(kctl->name, "Mic Boost Volume")) {
-                       kctl->put = olpc_xo_mic_boost_put;
-                       break;
-               }
-       }
-}
-
-static void cxt_fixup_mute_led_eapd(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct conexant_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_eapd = 0x1b;
-               spec->dynamic_eapd = true;
-               snd_hda_gen_add_mute_led_cdev(codec, cx_auto_vmaster_mute_led);
-       }
-}
-
-/*
- * Fix max input level on mixer widget to 0dB
- * (originally it has 0x2b steps with 0dB offset 0x14)
- */
-static void cxt_fixup_cap_mix_amp(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT,
-                                 (0x14 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (1 << AC_AMPCAP_MUTE_SHIFT));
-}
-
-/*
- * Fix max input level on mixer widget to 0dB
- * (originally it has 0x1e steps with 0 dB offset 0x17)
- */
-static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT,
-                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (1 << AC_AMPCAP_MUTE_SHIFT));
-}
-
-static void cxt_fixup_hp_gate_mic_jack(struct hda_codec *codec,
-                                      const struct hda_fixup *fix,
-                                      int action)
-{
-       /* the mic pin (0x19) doesn't give an unsolicited event;
-        * probe the mic pin together with the headphone pin (0x16)
-        */
-       if (action == HDA_FIXUP_ACT_PROBE)
-               snd_hda_jack_set_gating_jack(codec, 0x19, 0x16);
-}
-
-/* update LED status via GPIO */
-static void cxt_update_gpio_led(struct hda_codec *codec, unsigned int mask,
-                               bool led_on)
-{
-       struct conexant_spec *spec = codec->spec;
-       unsigned int oldval = spec->gpio_led;
-
-       if (spec->mute_led_polarity)
-               led_on = !led_on;
-
-       if (led_on)
-               spec->gpio_led |= mask;
-       else
-               spec->gpio_led &= ~mask;
-       codec_dbg(codec, "mask:%d enabled:%d gpio_led:%d\n",
-                       mask, led_on, spec->gpio_led);
-       if (spec->gpio_led != oldval)
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_led);
-}
-
-/* turn on/off mute LED via GPIO per vmaster hook */
-static int cxt_gpio_mute_update(struct led_classdev *led_cdev,
-                               enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct conexant_spec *spec = codec->spec;
-
-       cxt_update_gpio_led(codec, spec->gpio_mute_led_mask, brightness);
-       return 0;
-}
-
-/* turn on/off mic-mute LED via GPIO per capture hook */
-static int cxt_gpio_micmute_update(struct led_classdev *led_cdev,
-                                  enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct conexant_spec *spec = codec->spec;
-
-       cxt_update_gpio_led(codec, spec->gpio_mic_led_mask, brightness);
-       return 0;
-}
-
-static void cxt_setup_mute_led(struct hda_codec *codec,
-                              unsigned int mute, unsigned int mic_mute)
-{
-       struct conexant_spec *spec = codec->spec;
-
-       spec->gpio_led = 0;
-       spec->mute_led_polarity = 0;
-       if (mute) {
-               snd_hda_gen_add_mute_led_cdev(codec, cxt_gpio_mute_update);
-               spec->gpio_mute_led_mask = mute;
-       }
-       if (mic_mute) {
-               snd_hda_gen_add_micmute_led_cdev(codec, cxt_gpio_micmute_update);
-               spec->gpio_mic_led_mask = mic_mute;
-       }
-}
-
-static void cxt_setup_gpio_unmute(struct hda_codec *codec,
-                                 unsigned int gpio_mute_mask)
-{
-       if (gpio_mute_mask) {
-               // set gpio data to 0.
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, gpio_mute_mask);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, gpio_mute_mask);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_STICKY_MASK, 0);
-       }
-}
-
-static void cxt_fixup_mute_led_gpio(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               cxt_setup_mute_led(codec, 0x01, 0x02);
-}
-
-static void cxt_fixup_hp_zbook_mute_led(struct hda_codec *codec,
-                                       const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               cxt_setup_mute_led(codec, 0x10, 0x20);
-}
-
-static void cxt_fixup_hp_a_u(struct hda_codec *codec,
-                            const struct hda_fixup *fix, int action)
-{
-       // Init vers in BIOS mute the spk/hp by set gpio high to avoid pop noise,
-       // so need to unmute once by clearing the gpio data when runs into the system.
-       if (action == HDA_FIXUP_ACT_INIT)
-               cxt_setup_gpio_unmute(codec, 0x2);
-}
-
-/* ThinkPad X200 & co with cxt5051 */
-static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = {
-       { 0x16, 0x042140ff }, /* HP (seq# overridden) */
-       { 0x17, 0x21a11000 }, /* dock-mic */
-       { 0x19, 0x2121103f }, /* dock-HP */
-       { 0x1c, 0x21440100 }, /* dock SPDIF out */
-       {}
-};
-
-/* ThinkPad 410/420/510/520, X201 & co with cxt5066 */
-static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = {
-       { 0x19, 0x042110ff }, /* HP (seq# overridden) */
-       { 0x1a, 0x21a190f0 }, /* dock-mic */
-       { 0x1c, 0x212140ff }, /* dock-HP */
-       {}
-};
-
-/* Lemote A1004/A1205 with cxt5066 */
-static const struct hda_pintbl cxt_pincfg_lemote[] = {
-       { 0x1a, 0x90a10020 }, /* Internal mic */
-       { 0x1b, 0x03a11020 }, /* External mic */
-       { 0x1d, 0x400101f0 }, /* Not used */
-       { 0x1e, 0x40a701f0 }, /* Not used */
-       { 0x20, 0x404501f0 }, /* Not used */
-       { 0x22, 0x404401f0 }, /* Not used */
-       { 0x23, 0x40a701f0 }, /* Not used */
-       {}
-};
-
-/* SuoWoSi/South-holding JS201D with sn6140 */
-static const struct hda_pintbl cxt_pincfg_sws_js201d[] = {
-       { 0x16, 0x03211040 }, /* hp out */
-       { 0x17, 0x91170110 }, /* SPK/Class_D */
-       { 0x18, 0x95a70130 }, /* Internal mic */
-       { 0x19, 0x03a11020 }, /* Headset Mic */
-       { 0x1a, 0x40f001f0 }, /* Not used */
-       { 0x21, 0x40f001f0 }, /* Not used */
-       {}
-};
-
-static const struct hda_fixup cxt_fixups[] = {
-       [CXT_PINCFG_LENOVO_X200] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cxt_pincfg_lenovo_x200,
-       },
-       [CXT_PINCFG_LENOVO_TP410] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cxt_pincfg_lenovo_tp410,
-               .chained = true,
-               .chain_id = CXT_FIXUP_THINKPAD_ACPI,
-       },
-       [CXT_PINCFG_LEMOTE_A1004] = {
-               .type = HDA_FIXUP_PINS,
-               .chained = true,
-               .chain_id = CXT_FIXUP_INC_MIC_BOOST,
-               .v.pins = cxt_pincfg_lemote,
-       },
-       [CXT_PINCFG_LEMOTE_A1205] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cxt_pincfg_lemote,
-       },
-       [CXT_PINCFG_COMPAQ_CQ60] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* 0x17 was falsely set up as a mic, it should 0x1d */
-                       { 0x17, 0x400001f0 },
-                       { 0x1d, 0x97a70120 },
-                       { }
-               }
-       },
-       [CXT_FIXUP_STEREO_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_stereo_dmic,
-       },
-       [CXT_PINCFG_LENOVO_NOTEBOOK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x05d71030 },
-                       { }
-               },
-               .chain_id = CXT_FIXUP_STEREO_DMIC,
-       },
-       [CXT_FIXUP_INC_MIC_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt5066_increase_mic_boost,
-       },
-       [CXT_FIXUP_HEADPHONE_MIC_PIN] = {
-               .type = HDA_FIXUP_PINS,
-               .chained = true,
-               .chain_id = CXT_FIXUP_HEADPHONE_MIC,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
-                       { }
-               }
-       },
-       [CXT_FIXUP_HEADPHONE_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_headphone_mic,
-       },
-       [CXT_FIXUP_GPIO1] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 },
-                       { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 },
-                       { 0x01, AC_VERB_SET_GPIO_DATA, 0x01 },
-                       { }
-               },
-       },
-       [CXT_FIXUP_ASPIRE_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_stereo_dmic,
-               .chained = true,
-               .chain_id = CXT_FIXUP_GPIO1,
-       },
-       [CXT_FIXUP_THINKPAD_ACPI] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = hda_fixup_thinkpad_acpi,
-       },
-       [CXT_FIXUP_LENOVO_XPAD_ACPI] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = hda_fixup_ideapad_acpi,
-               .chained = true,
-               .chain_id = CXT_FIXUP_THINKPAD_ACPI,
-       },
-       [CXT_FIXUP_OLPC_XO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_olpc_xo,
-       },
-       [CXT_FIXUP_CAP_MIX_AMP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_cap_mix_amp,
-       },
-       [CXT_FIXUP_TOSHIBA_P105] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x10, 0x961701f0 }, /* speaker/hp */
-                       { 0x12, 0x02a1901e }, /* ext mic */
-                       { 0x14, 0x95a70110 }, /* int mic */
-                       {}
-               },
-       },
-       [CXT_FIXUP_HP_530] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x90a60160 }, /* int mic */
-                       {}
-               },
-               .chained = true,
-               .chain_id = CXT_FIXUP_CAP_MIX_AMP,
-       },
-       [CXT_FIXUP_CAP_MIX_AMP_5047] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_cap_mix_amp_5047,
-       },
-       [CXT_FIXUP_MUTE_LED_EAPD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_mute_led_eapd,
-       },
-       [CXT_FIXUP_HP_DOCK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x21011020 }, /* line-out */
-                       { 0x18, 0x2181103f }, /* line-in */
-                       { }
-               },
-               .chained = true,
-               .chain_id = CXT_FIXUP_MUTE_LED_GPIO,
-       },
-       [CXT_FIXUP_HP_SPECTRE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* enable NID 0x1d for the speaker on top */
-                       { 0x1d, 0x91170111 },
-                       { }
-               }
-       },
-       [CXT_FIXUP_HP_GATE_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_hp_gate_mic_jack,
-       },
-       [CXT_FIXUP_MUTE_LED_GPIO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_mute_led_gpio,
-       },
-       [CXT_FIXUP_HP_ELITEONE_OUT_DIS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_update_pinctl,
-       },
-       [CXT_FIXUP_HP_ZBOOK_MUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_hp_zbook_mute_led,
-       },
-       [CXT_FIXUP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_headset_mic,
-       },
-       [CXT_FIXUP_HP_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x02a1113c },
-                       { }
-               },
-               .chained = true,
-               .chain_id = CXT_FIXUP_HEADSET_MIC,
-       },
-       [CXT_PINCFG_SWS_JS201D] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cxt_pincfg_sws_js201d,
-       },
-       [CXT_PINCFG_TOP_SPEAKER] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1d, 0x82170111 },
-                       { }
-               },
-       },
-       [CXT_FIXUP_HP_A_U] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cxt_fixup_hp_a_u,
-       },
-};
-
-static const struct hda_quirk cxt5045_fixups[] = {
-       SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530),
-       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105),
-       /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have
-        * really bad sound over 0dB on NID 0x17.
-        */
-       SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP),
-       SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP),
-       SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP),
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP),
-       {}
-};
-
-static const struct hda_model_fixup cxt5045_fixup_models[] = {
-       { .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" },
-       { .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" },
-       { .id = CXT_FIXUP_HP_530, .name = "hp-530" },
-       {}
-};
-
-static const struct hda_quirk cxt5047_fixups[] = {
-       /* HP laptops have really bad sound over 0 dB on NID 0x10.
-        */
-       SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047),
-       {}
-};
-
-static const struct hda_model_fixup cxt5047_fixup_models[] = {
-       { .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" },
-       {}
-};
-
-static const struct hda_quirk cxt5051_fixups[] = {
-       SND_PCI_QUIRK(0x103c, 0x360b, "Compaq CQ60", CXT_PINCFG_COMPAQ_CQ60),
-       SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT_PINCFG_LENOVO_X200),
-       {}
-};
-
-static const struct hda_model_fixup cxt5051_fixup_models[] = {
-       { .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" },
-       {}
-};
-
-static const struct hda_quirk cxt5066_fixups[] = {
-       SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_ASPIRE_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x054f, "Acer Aspire 4830T", CXT_FIXUP_ASPIRE_DMIC),
-       SND_PCI_QUIRK(0x103c, 0x8079, "HP EliteBook 840 G3", CXT_FIXUP_HP_DOCK),
-       SND_PCI_QUIRK(0x103c, 0x807C, "HP EliteBook 820 G3", CXT_FIXUP_HP_DOCK),
-       SND_PCI_QUIRK(0x103c, 0x80FD, "HP ProBook 640 G2", CXT_FIXUP_HP_DOCK),
-       SND_PCI_QUIRK(0x103c, 0x8115, "HP Z1 Gen3", CXT_FIXUP_HP_GATE_MIC),
-       SND_PCI_QUIRK(0x103c, 0x814f, "HP ZBook 15u G3", CXT_FIXUP_MUTE_LED_GPIO),
-       SND_PCI_QUIRK(0x103c, 0x8174, "HP Spectre x360", CXT_FIXUP_HP_SPECTRE),
-       SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO),
-       SND_PCI_QUIRK(0x103c, 0x8231, "HP ProBook 450 G4", CXT_FIXUP_MUTE_LED_GPIO),
-       SND_PCI_QUIRK(0x103c, 0x828c, "HP EliteBook 840 G4", CXT_FIXUP_HP_DOCK),
-       SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x82b4, "HP ProDesk 600 G3", CXT_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x836e, "HP ProBook 455 G5", CXT_FIXUP_MUTE_LED_GPIO),
-       SND_PCI_QUIRK(0x103c, 0x837f, "HP ProBook 470 G5", CXT_FIXUP_MUTE_LED_GPIO),
-       SND_PCI_QUIRK(0x103c, 0x83b2, "HP EliteBook 840 G5", CXT_FIXUP_HP_DOCK),
-       SND_PCI_QUIRK(0x103c, 0x83b3, "HP EliteBook 830 G5", CXT_FIXUP_HP_DOCK),
-       SND_PCI_QUIRK(0x103c, 0x83d3, "HP ProBook 640 G4", CXT_FIXUP_HP_DOCK),
-       SND_PCI_QUIRK(0x103c, 0x83e5, "HP EliteOne 1000 G2", CXT_FIXUP_HP_ELITEONE_OUT_DIS),
-       SND_PCI_QUIRK(0x103c, 0x8402, "HP ProBook 645 G4", CXT_FIXUP_MUTE_LED_GPIO),
-       SND_PCI_QUIRK(0x103c, 0x8427, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x844f, "HP ZBook Studio G5", CXT_FIXUP_HP_ZBOOK_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x8456, "HP Z2 G4 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x8457, "HP Z2 G4 mini", CXT_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x8458, "HP Z2 G4 mini premium", CXT_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN),
-       SND_PCI_QUIRK(0x14f1, 0x0252, "MBX-Z60MR100", CXT_FIXUP_HP_A_U),
-       SND_PCI_QUIRK(0x14f1, 0x0265, "SWS JS201D", CXT_PINCFG_SWS_JS201D),
-       SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO),
-       SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410),
-       SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410),
-       SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410),
-       SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410),
-       SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410),
-       SND_PCI_QUIRK(0x17aa, 0x21d2, "Lenovo T420s", CXT_PINCFG_LENOVO_TP410),
-       SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410),
-       SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410),
-       SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo IdeaPad Z560", CXT_FIXUP_MUTE_LED_EAPD),
-       SND_PCI_QUIRK(0x17aa, 0x3905, "Lenovo G50-30", CXT_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x17aa, 0x390b, "Lenovo G50-80", CXT_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC),
-       /* NOTE: we'd need to extend the quirk for 17aa:3977 as the same
-        * PCI SSID is used on multiple Lenovo models
-        */
-       SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo G50-70", CXT_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad/Ideapad", CXT_FIXUP_LENOVO_XPAD_ACPI),
-       SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004),
-       SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205),
-       HDA_CODEC_QUIRK(0x2782, 0x12c3, "Sirius Gen1", CXT_PINCFG_TOP_SPEAKER),
-       HDA_CODEC_QUIRK(0x2782, 0x12c5, "Sirius Gen2", CXT_PINCFG_TOP_SPEAKER),
-       {}
-};
-
-static const struct hda_model_fixup cxt5066_fixup_models[] = {
-       { .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" },
-       { .id = CXT_FIXUP_GPIO1, .name = "gpio1" },
-       { .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" },
-       { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" },
-       { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" },
-       { .id = CXT_FIXUP_LENOVO_XPAD_ACPI, .name = "thinkpad-ideapad" },
-       { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" },
-       { .id = CXT_PINCFG_LEMOTE_A1205, .name = "lemote-a1205" },
-       { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" },
-       { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" },
-       { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" },
-       { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" },
-       { .id = CXT_FIXUP_HP_ZBOOK_MUTE_LED, .name = "hp-zbook-mute-led" },
-       { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" },
-       { .id = CXT_PINCFG_LENOVO_NOTEBOOK, .name = "lenovo-20149" },
-       { .id = CXT_PINCFG_SWS_JS201D, .name = "sws-js201d" },
-       { .id = CXT_PINCFG_TOP_SPEAKER, .name = "sirius-top-speaker" },
-       { .id = CXT_FIXUP_HP_A_U, .name = "HP-U-support" },
-       {}
-};
-
-/* add "fake" mute amp-caps to DACs on cx5051 so that mixer mute switches
- * can be created (bko#42825)
- */
-static void add_cx5051_fake_mutes(struct hda_codec *codec)
-{
-       struct conexant_spec *spec = codec->spec;
-       static const hda_nid_t out_nids[] = {
-               0x10, 0x11, 0
-       };
-       const hda_nid_t *p;
-
-       for (p = out_nids; *p; p++)
-               snd_hda_override_amp_caps(codec, *p, HDA_OUTPUT,
-                                         AC_AMPCAP_MIN_MUTE |
-                                         query_amp_caps(codec, *p, HDA_OUTPUT));
-       spec->gen.dac_min_mute = true;
-}
-
-static int patch_conexant_auto(struct hda_codec *codec)
-{
-       struct conexant_spec *spec;
-       int err;
-
-       codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       snd_hda_gen_spec_init(&spec->gen);
-       codec->spec = spec;
-       codec->patch_ops = cx_auto_patch_ops;
-
-       /* init cx11880/sn6140 flag and reset headset_present_flag */
-       switch (codec->core.vendor_id) {
-       case 0x14f11f86:
-       case 0x14f11f87:
-               spec->is_cx11880_sn6140 = true;
-               snd_hda_jack_detect_enable_callback(codec, 0x19, cx_update_headset_mic_vref);
-               break;
-       }
-
-       cx_auto_parse_eapd(codec);
-       spec->gen.own_eapd_ctl = 1;
-
-       switch (codec->core.vendor_id) {
-       case 0x14f15045:
-               codec->single_adc_amp = 1;
-               spec->gen.mixer_nid = 0x17;
-               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
-               snd_hda_pick_fixup(codec, cxt5045_fixup_models,
-                                  cxt5045_fixups, cxt_fixups);
-               break;
-       case 0x14f15047:
-               codec->pin_amp_workaround = 1;
-               spec->gen.mixer_nid = 0x19;
-               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
-               snd_hda_pick_fixup(codec, cxt5047_fixup_models,
-                                  cxt5047_fixups, cxt_fixups);
-               break;
-       case 0x14f15051:
-               add_cx5051_fake_mutes(codec);
-               codec->pin_amp_workaround = 1;
-               snd_hda_pick_fixup(codec, cxt5051_fixup_models,
-                                  cxt5051_fixups, cxt_fixups);
-               break;
-       case 0x14f15098:
-               codec->pin_amp_workaround = 1;
-               spec->gen.mixer_nid = 0x22;
-               spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
-               snd_hda_pick_fixup(codec, cxt5066_fixup_models,
-                                  cxt5066_fixups, cxt_fixups);
-               break;
-       case 0x14f150f2:
-               codec->power_save_node = 1;
-               fallthrough;
-       default:
-               codec->pin_amp_workaround = 1;
-               snd_hda_pick_fixup(codec, cxt5066_fixup_models,
-                                  cxt5066_fixups, cxt_fixups);
-               break;
-       }
-
-       if (!spec->gen.vmaster_mute.hook && spec->dynamic_eapd)
-               spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
-                                      spec->parse_flags);
-       if (err < 0)
-               goto error;
-
-       err = cx_auto_parse_beep(codec);
-       if (err < 0)
-               goto error;
-
-       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
-       if (err < 0)
-               goto error;
-
-       /* Some laptops with Conexant chips show stalls in S3 resume,
-        * which falls into the single-cmd mode.
-        * Better to make reset, then.
-        */
-       if (!codec->bus->core.sync_write) {
-               codec_info(codec,
-                          "Enable sync_write for stable communication\n");
-               codec->bus->core.sync_write = 1;
-               codec->bus->allow_bus_reset = 1;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       cx_auto_free(codec);
-       return err;
-}
-
-/*
- */
-
-static const struct hda_device_id snd_hda_id_conexant[] = {
-       HDA_CODEC_ENTRY(0x14f11f86, "CX11880", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f11f87, "SN6140", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f12008, "CX8200", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f120d0, "CX11970", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f120d1, "SN6180", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15045, "CX20549 (Venice)", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15047, "CX20551 (Waikiki)", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15051, "CX20561 (Hermosa)", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15066, "CX20582 (Pebble)", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15067, "CX20583 (Pebble HSF)", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15068, "CX20584", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15069, "CX20585", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f1506c, "CX20588", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f1506e, "CX20590", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15097, "CX20631", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15098, "CX20632", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150a1, "CX20641", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150a2, "CX20642", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150ab, "CX20651", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150ac, "CX20652", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150b8, "CX20664", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150b9, "CX20665", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150f1, "CX21722", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150f2, "CX20722", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150f3, "CX21724", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f150f4, "CX20724", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f1510f, "CX20751/2", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15110, "CX20751/2", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15111, "CX20753/4", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15113, "CX20755", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15114, "CX20756", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f15115, "CX20757", patch_conexant_auto),
-       HDA_CODEC_ENTRY(0x14f151d7, "CX20952", patch_conexant_auto),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_conexant);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Conexant HD-audio codec");
-
-static struct hda_codec_driver conexant_driver = {
-       .id = snd_hda_id_conexant,
-};
-
-module_hda_codec_driver(conexant_driver);
diff --git a/sound/pci/hda/patch_cs8409-tables.c b/sound/pci/hda/patch_cs8409-tables.c
deleted file mode 100644 (file)
index 0924013..0000000
+++ /dev/null
@@ -1,623 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * patch_cs8409-tables.c  --  HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
- *
- * Copyright (C) 2021 Cirrus Logic, Inc. and
- *                    Cirrus Logic International Semiconductor Ltd.
- *
- * Author: Lucas Tanure <tanureal@opensource.cirrus.com>
- */
-
-#include "patch_cs8409.h"
-
-/******************************************************************************
- *                          CS42L42 Specific Data
- *
- ******************************************************************************/
-
-static const DECLARE_TLV_DB_SCALE(cs42l42_dac_db_scale, CS42L42_HP_VOL_REAL_MIN * 100, 100, 1);
-
-static const DECLARE_TLV_DB_SCALE(cs42l42_adc_db_scale, CS42L42_AMIC_VOL_REAL_MIN * 100, 100, 1);
-
-const struct snd_kcontrol_new cs42l42_dac_volume_mixer = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .index = 0,
-       .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
-       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-       .info = cs42l42_volume_info,
-       .get = cs42l42_volume_get,
-       .put = cs42l42_volume_put,
-       .tlv = { .p = cs42l42_dac_db_scale },
-       .private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_TRANSMITTER_A, 3, CS8409_CODEC0,
-                        HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE
-};
-
-const struct snd_kcontrol_new cs42l42_adc_volume_mixer = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .index = 0,
-       .subdevice = (HDA_SUBDEV_AMP_FLAG | HDA_SUBDEV_NID_FLAG),
-       .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ),
-       .info = cs42l42_volume_info,
-       .get = cs42l42_volume_get,
-       .put = cs42l42_volume_put,
-       .tlv = { .p = cs42l42_adc_db_scale },
-       .private_value = HDA_COMPOSE_AMP_VAL_OFS(CS8409_PIN_ASP1_RECEIVER_A, 1, CS8409_CODEC0,
-                        HDA_INPUT, CS42L42_VOL_ADC) | HDA_AMP_VAL_MIN_MUTE
-};
-
-const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback = {
-       .rates = SNDRV_PCM_RATE_48000, /* fixed rate */
-};
-
-const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture = {
-       .rates = SNDRV_PCM_RATE_48000, /* fixed rate */
-};
-
-/******************************************************************************
- *                   BULLSEYE / WARLOCK / CYBORG Specific Arrays
- *                               CS8409/CS42L42
- ******************************************************************************/
-
-const struct hda_verb cs8409_cs42l42_init_verbs[] = {
-       { CS8409_PIN_AFG, AC_VERB_SET_GPIO_WAKE_MASK, 0x0018 },         /* WAKE from GPIO 3,4 */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_STATE, 0x0001 },   /* Enable VPW processing */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x0002 },   /* Configure GPIO 6,7 */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF,  0x0080 },   /* I2C mode */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x005b },   /* Set I2C bus speed */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF,  0x0200 },   /* 100kHz I2C_STO = 2 */
-       {} /* terminator */
-};
-
-static const struct hda_pintbl cs8409_cs42l42_pincfgs[] = {
-       { CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 },  /* ASP-1-TX */
-       { CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 },     /* ASP-1-RX */
-       { CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 },  /* ASP-2-TX */
-       { CS8409_PIN_DMIC1_IN, 0x90a00090 },            /* DMIC-1 */
-       {} /* terminator */
-};
-
-static const struct hda_pintbl cs8409_cs42l42_pincfgs_no_dmic[] = {
-       { CS8409_PIN_ASP1_TRANSMITTER_A, 0x042120f0 },  /* ASP-1-TX */
-       { CS8409_PIN_ASP1_RECEIVER_A, 0x04a12050 },     /* ASP-1-RX */
-       { CS8409_PIN_ASP2_TRANSMITTER_A, 0x901000f0 },  /* ASP-2-TX */
-       {} /* terminator */
-};
-
-/* Vendor specific HW configuration for CS42L42 */
-static const struct cs8409_i2c_param cs42l42_init_reg_seq[] = {
-       { CS42L42_I2C_TIMEOUT, 0xB0 },
-       { CS42L42_ADC_CTL, 0x00 },
-       { 0x1D02, 0x06 },
-       { CS42L42_ADC_VOLUME, 0x9F },
-       { CS42L42_OSC_SWITCH, 0x01 },
-       { CS42L42_MCLK_CTL, 0x02 },
-       { CS42L42_SRC_CTL, 0x03 },
-       { CS42L42_MCLK_SRC_SEL, 0x00 },
-       { CS42L42_ASP_FRM_CFG, 0x13 },
-       { CS42L42_FSYNC_P_LOWER, 0xFF },
-       { CS42L42_FSYNC_P_UPPER, 0x00 },
-       { CS42L42_ASP_CLK_CFG, 0x20 },
-       { CS42L42_SPDIF_CLK_CFG, 0x0D },
-       { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
-       { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
-       { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x20 },
-       { CS42L42_ASP_RX_DAI0_CH3_AP_RES, 0x02 },
-       { CS42L42_ASP_RX_DAI0_CH3_BIT_MSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH3_BIT_LSB, 0x80 },
-       { CS42L42_ASP_RX_DAI0_CH4_AP_RES, 0x02 },
-       { CS42L42_ASP_RX_DAI0_CH4_BIT_MSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH4_BIT_LSB, 0xA0 },
-       { CS42L42_ASP_RX_DAI0_EN, 0x0C },
-       { CS42L42_ASP_TX_CH_EN, 0x01 },
-       { CS42L42_ASP_TX_CH_AP_RES, 0x02 },
-       { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
-       { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
-       { CS42L42_ASP_TX_SZ_EN, 0x01 },
-       { CS42L42_PWR_CTL1, 0x0A },
-       { CS42L42_PWR_CTL2, 0x84 },
-       { CS42L42_MIXER_CHA_VOL, 0x3F },
-       { CS42L42_MIXER_CHB_VOL, 0x3F },
-       { CS42L42_MIXER_ADC_VOL, 0x3f },
-       { CS42L42_HP_CTL, 0x0D },
-       { CS42L42_MIC_DET_CTL1, 0xB6 },
-       { CS42L42_TIPSENSE_CTL, 0xC2 },
-       { CS42L42_HS_CLAMP_DISABLE, 0x01 },
-       { CS42L42_HS_SWITCH_CTL, 0xF3 },
-       { CS42L42_PWR_CTL3, 0x20 },
-       { CS42L42_RSENSE_CTL2, 0x00 },
-       { CS42L42_RSENSE_CTL3, 0x00 },
-       { CS42L42_TSENSE_CTL, 0x80 },
-       { CS42L42_HS_BIAS_CTL, 0xC0 },
-       { CS42L42_PWR_CTL1, 0x02, 10000 },
-       { CS42L42_ADC_OVFL_INT_MASK, 0xff },
-       { CS42L42_MIXER_INT_MASK, 0xff },
-       { CS42L42_SRC_INT_MASK, 0xff },
-       { CS42L42_ASP_RX_INT_MASK, 0xff },
-       { CS42L42_ASP_TX_INT_MASK, 0xff },
-       { CS42L42_CODEC_INT_MASK, 0xff },
-       { CS42L42_SRCPL_INT_MASK, 0xff },
-       { CS42L42_VPMON_INT_MASK, 0xff },
-       { CS42L42_PLL_LOCK_INT_MASK, 0xff },
-       { CS42L42_TSRS_PLUG_INT_MASK, 0xff },
-       { CS42L42_DET_INT1_MASK, 0xff },
-       { CS42L42_DET_INT2_MASK, 0xff },
-};
-
-/* Vendor specific hw configuration for CS8409 */
-const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[] = {
-       /* +PLL1/2_EN, +I2C_EN */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0xb008 },
-       /* ASP1/2_EN=0, ASP1_STP=1 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0002 },
-       /* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG3, 0x0a80 },
-       /* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL1, 0x0800 },
-       /* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL2, 0x0820 },
-       /* ASP2.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP2_A_TX_CTRL1, 0x0800 },
-       /* ASP2.A: TX.RAP=1, TX.RSZ=24 bits, TX.RCS=0 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP2_A_TX_CTRL2, 0x2800 },
-       /* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL1, 0x0800 },
-       /* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL2, 0x0800 },
-       /* ASP1: LCHI = 00h */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL1, 0x8000 },
-       /* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL2, 0x28ff },
-       /* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL3, 0x0062 },
-       /* ASP2: LCHI=1Fh */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL1, 0x801f },
-       /* ASP2: MC/SC_SRCSEL=PLL1, LCPR=3Fh */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL2, 0x283f },
-       /* ASP2: 5050=1, MCEN=0, FSD=010, SCPOL_IN/OUT=1, SCDIV=1:16 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP2_CLK_CTRL3, 0x805c },
-       /* DMIC1_MO=10b, DMIC1/2_SR=1 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DMIC_CFG, 0x0023 },
-       /* ASP1/2_BEEP=0 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_BEEP_CFG, 0x0000 },
-       /* ASP1/2_EN=1, ASP1_STP=1 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0062 },
-       /* -PLL2_EN */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0x9008 },
-       /* TX2.A: pre-scale att.=0 dB */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PRE_SCALE_ATTN2, 0x0000 },
-       /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=1 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PAD_CFG_SLW_RATE_CTRL, 0xfc03 },
-       /* test mode on */
-       { CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x9999 },
-       /* GPIO hysteresis = 30 us */
-       { CS8409_PIN_VENDOR_WIDGET, 0xc5, 0x0000 },
-       /* test mode off */
-       { CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x0000 },
-       {} /* Terminator */
-};
-
-const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[] = {
-       /* EQ_SEL=1, EQ1/2_EN=0 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_CTRL1, 0x4000 },
-       /* +EQ_ACC */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0x4000 },
-       /* +EQ2_EN */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_CTRL1, 0x4010 },
-       /* EQ_DATA_HI=0x0647 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x0647 },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=0, EQ_DATA_LO=0x67 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc0c7 },
-       /* EQ_DATA_HI=0x0647 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x0647 },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=1, EQ_DATA_LO=0x67 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc1c7 },
-       /* EQ_DATA_HI=0xf370 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xf370 },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=2, EQ_DATA_LO=0x71 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc271 },
-       /* EQ_DATA_HI=0x1ef8 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1ef8 },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=3, EQ_DATA_LO=0x48 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc348 },
-       /* EQ_DATA_HI=0xc110 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc110 },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=4, EQ_DATA_LO=0x5a */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc45a },
-       /* EQ_DATA_HI=0x1f29 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1f29 },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=5, EQ_DATA_LO=0x74 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc574 },
-       /* EQ_DATA_HI=0x1d7a */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1d7a },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=6, EQ_DATA_LO=0x53 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc653 },
-       /* EQ_DATA_HI=0xc38c */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc38c },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=7, EQ_DATA_LO=0x14 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc714 },
-       /* EQ_DATA_HI=0x1ca3 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0x1ca3 },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=8, EQ_DATA_LO=0xc7 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc8c7 },
-       /* EQ_DATA_HI=0xc38c */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W1, 0xc38c },
-       /* +EQ_WRT, +EQ_ACC, EQ_ADR=9, EQ_DATA_LO=0x14 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0xc914 },
-       /* -EQ_ACC, -EQ_WRT */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PFE_COEF_W2, 0x0000 },
-       {} /* Terminator */
-};
-
-struct sub_codec cs8409_cs42l42_codec = {
-       .addr = CS42L42_I2C_ADDR,
-       .reset_gpio = CS8409_CS42L42_RESET,
-       .irq_mask = CS8409_CS42L42_INT,
-       .init_seq = cs42l42_init_reg_seq,
-       .init_seq_num = ARRAY_SIZE(cs42l42_init_reg_seq),
-       .hp_jack_in = 0,
-       .mic_jack_in = 0,
-       .paged = 1,
-       .suspended = 1,
-       .no_type_dect = 0,
-};
-
-/******************************************************************************
- *                          Dolphin Specific Arrays
- *                            CS8409/ 2 X CS42L42
- ******************************************************************************/
-
-const struct hda_verb dolphin_init_verbs[] = {
-       { 0x01, AC_VERB_SET_GPIO_WAKE_MASK, DOLPHIN_WAKE }, /* WAKE from GPIO 0,4 */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_STATE, 0x0001 }, /* Enable VPW processing  */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x0002 }, /* Configure GPIO 6,7 */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF,  0x0080 }, /* I2C mode */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_COEF_INDEX, 0x005b }, /* Set I2C bus speed */
-       { CS8409_PIN_VENDOR_WIDGET, AC_VERB_SET_PROC_COEF,  0x0200 }, /* 100kHz I2C_STO = 2 */
-       {} /* terminator */
-};
-
-static const struct hda_pintbl dolphin_pincfgs[] = {
-       { 0x24, 0x022210f0 }, /* ASP-1-TX-A */
-       { 0x25, 0x010240f0 }, /* ASP-1-TX-B */
-       { 0x34, 0x02a21050 }, /* ASP-1-RX */
-       {} /* terminator */
-};
-
-/* Vendor specific HW configuration for CS42L42 */
-static const struct cs8409_i2c_param dolphin_c0_init_reg_seq[] = {
-       { CS42L42_I2C_TIMEOUT, 0xB0 },
-       { CS42L42_ADC_CTL, 0x00 },
-       { 0x1D02, 0x06 },
-       { CS42L42_ADC_VOLUME, 0x9F },
-       { CS42L42_OSC_SWITCH, 0x01 },
-       { CS42L42_MCLK_CTL, 0x02 },
-       { CS42L42_SRC_CTL, 0x03 },
-       { CS42L42_MCLK_SRC_SEL, 0x00 },
-       { CS42L42_ASP_FRM_CFG, 0x13 },
-       { CS42L42_FSYNC_P_LOWER, 0xFF },
-       { CS42L42_FSYNC_P_UPPER, 0x00 },
-       { CS42L42_ASP_CLK_CFG, 0x20 },
-       { CS42L42_SPDIF_CLK_CFG, 0x0D },
-       { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
-       { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
-       { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0x20 },
-       { CS42L42_ASP_RX_DAI0_EN, 0x0C },
-       { CS42L42_ASP_TX_CH_EN, 0x01 },
-       { CS42L42_ASP_TX_CH_AP_RES, 0x02 },
-       { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
-       { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
-       { CS42L42_ASP_TX_SZ_EN, 0x01 },
-       { CS42L42_PWR_CTL1, 0x0A },
-       { CS42L42_PWR_CTL2, 0x84 },
-       { CS42L42_HP_CTL, 0x0D },
-       { CS42L42_MIXER_CHA_VOL, 0x3F },
-       { CS42L42_MIXER_CHB_VOL, 0x3F },
-       { CS42L42_MIXER_ADC_VOL, 0x3f },
-       { CS42L42_MIC_DET_CTL1, 0xB6 },
-       { CS42L42_TIPSENSE_CTL, 0xC2 },
-       { CS42L42_HS_CLAMP_DISABLE, 0x01 },
-       { CS42L42_HS_SWITCH_CTL, 0xF3 },
-       { CS42L42_PWR_CTL3, 0x20 },
-       { CS42L42_RSENSE_CTL2, 0x00 },
-       { CS42L42_RSENSE_CTL3, 0x00 },
-       { CS42L42_TSENSE_CTL, 0x80 },
-       { CS42L42_HS_BIAS_CTL, 0xC0 },
-       { CS42L42_PWR_CTL1, 0x02, 10000 },
-       { CS42L42_ADC_OVFL_INT_MASK, 0xff },
-       { CS42L42_MIXER_INT_MASK, 0xff },
-       { CS42L42_SRC_INT_MASK, 0xff },
-       { CS42L42_ASP_RX_INT_MASK, 0xff },
-       { CS42L42_ASP_TX_INT_MASK, 0xff },
-       { CS42L42_CODEC_INT_MASK, 0xff },
-       { CS42L42_SRCPL_INT_MASK, 0xff },
-       { CS42L42_VPMON_INT_MASK, 0xff },
-       { CS42L42_PLL_LOCK_INT_MASK, 0xff },
-       { CS42L42_TSRS_PLUG_INT_MASK, 0xff },
-       { CS42L42_DET_INT1_MASK, 0xff },
-       { CS42L42_DET_INT2_MASK, 0xff }
-};
-
-static const struct cs8409_i2c_param dolphin_c1_init_reg_seq[] = {
-       { CS42L42_I2C_TIMEOUT, 0xB0 },
-       { CS42L42_ADC_CTL, 0x00 },
-       { 0x1D02, 0x06 },
-       { CS42L42_ADC_VOLUME, 0x9F },
-       { CS42L42_OSC_SWITCH, 0x01 },
-       { CS42L42_MCLK_CTL, 0x02 },
-       { CS42L42_SRC_CTL, 0x03 },
-       { CS42L42_MCLK_SRC_SEL, 0x00 },
-       { CS42L42_ASP_FRM_CFG, 0x13 },
-       { CS42L42_FSYNC_P_LOWER, 0xFF },
-       { CS42L42_FSYNC_P_UPPER, 0x00 },
-       { CS42L42_ASP_CLK_CFG, 0x20 },
-       { CS42L42_SPDIF_CLK_CFG, 0x0D },
-       { CS42L42_ASP_RX_DAI0_CH1_AP_RES, 0x02 },
-       { CS42L42_ASP_RX_DAI0_CH1_BIT_MSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH1_BIT_LSB, 0x80 },
-       { CS42L42_ASP_RX_DAI0_CH2_AP_RES, 0x02 },
-       { CS42L42_ASP_RX_DAI0_CH2_BIT_MSB, 0x00 },
-       { CS42L42_ASP_RX_DAI0_CH2_BIT_LSB, 0xA0 },
-       { CS42L42_ASP_RX_DAI0_EN, 0x0C },
-       { CS42L42_ASP_TX_CH_EN, 0x00 },
-       { CS42L42_ASP_TX_CH_AP_RES, 0x02 },
-       { CS42L42_ASP_TX_CH1_BIT_MSB, 0x00 },
-       { CS42L42_ASP_TX_CH1_BIT_LSB, 0x00 },
-       { CS42L42_ASP_TX_SZ_EN, 0x00 },
-       { CS42L42_PWR_CTL1, 0x0E },
-       { CS42L42_PWR_CTL2, 0x84 },
-       { CS42L42_HP_CTL, 0x0D },
-       { CS42L42_MIXER_CHA_VOL, 0x3F },
-       { CS42L42_MIXER_CHB_VOL, 0x3F },
-       { CS42L42_MIXER_ADC_VOL, 0x3f },
-       { CS42L42_MIC_DET_CTL1, 0xB6 },
-       { CS42L42_TIPSENSE_CTL, 0xC2 },
-       { CS42L42_HS_CLAMP_DISABLE, 0x01 },
-       { CS42L42_HS_SWITCH_CTL, 0xF3 },
-       { CS42L42_PWR_CTL3, 0x20 },
-       { CS42L42_RSENSE_CTL2, 0x00 },
-       { CS42L42_RSENSE_CTL3, 0x00 },
-       { CS42L42_TSENSE_CTL, 0x80 },
-       { CS42L42_HS_BIAS_CTL, 0xC0 },
-       { CS42L42_PWR_CTL1, 0x06, 10000 },
-       { CS42L42_ADC_OVFL_INT_MASK, 0xff },
-       { CS42L42_MIXER_INT_MASK, 0xff },
-       { CS42L42_SRC_INT_MASK, 0xff },
-       { CS42L42_ASP_RX_INT_MASK, 0xff },
-       { CS42L42_ASP_TX_INT_MASK, 0xff },
-       { CS42L42_CODEC_INT_MASK, 0xff },
-       { CS42L42_SRCPL_INT_MASK, 0xff },
-       { CS42L42_VPMON_INT_MASK, 0xff },
-       { CS42L42_PLL_LOCK_INT_MASK, 0xff },
-       { CS42L42_TSRS_PLUG_INT_MASK, 0xff },
-       { CS42L42_DET_INT1_MASK, 0xff },
-       { CS42L42_DET_INT2_MASK, 0xff }
-};
-
-/* Vendor specific hw configuration for CS8409 */
-const struct cs8409_cir_param dolphin_hw_cfg[] = {
-       /* +PLL1/2_EN, +I2C_EN */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0xb008 },
-       /* ASP1_EN=0, ASP1_STP=1 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0002 },
-       /* ASP1/2_BUS_IDLE=10, +GPIO_I2C */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG3, 0x0a80 },
-       /* ASP1.A: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=0 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL1, 0x0800 },
-       /* ASP1.A: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=32 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_TX_CTRL2, 0x0820 },
-       /* ASP1.B: TX.LAP=0, TX.LSZ=24 bits, TX.LCS=128 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_B_TX_CTRL1, 0x0880 },
-       /* ASP1.B: TX.RAP=0, TX.RSZ=24 bits, TX.RCS=160 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_B_TX_CTRL2, 0x08a0 },
-       /* ASP1.A: RX.LAP=0, RX.LSZ=24 bits, RX.LCS=0 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL1, 0x0800 },
-       /* ASP1.A: RX.RAP=0, RX.RSZ=24 bits, RX.RCS=0 */
-       { CS8409_PIN_VENDOR_WIDGET, ASP1_A_RX_CTRL2, 0x0800 },
-       /* ASP1: LCHI = 00h */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL1, 0x8000 },
-       /* ASP1: MC/SC_SRCSEL=PLL1, LCPR=FFh */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL2, 0x28ff },
-       /* ASP1: MCEN=0, FSD=011, SCPOL_IN/OUT=0, SCDIV=1:4 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_ASP1_CLK_CTRL3, 0x0062 },
-       /* ASP1/2_BEEP=0 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_BEEP_CFG, 0x0000 },
-       /* ASP1_EN=1, ASP1_STP=1 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG2, 0x0022 },
-       /* -PLL2_EN */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_DEV_CFG1, 0x9008 },
-       /* ASP1_xxx_EN=1, ASP1_MCLK_EN=0 */
-       { CS8409_PIN_VENDOR_WIDGET, CS8409_PAD_CFG_SLW_RATE_CTRL, 0x5400 },
-       /* test mode on */
-       { CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x9999 },
-       /* GPIO hysteresis = 30 us */
-       { CS8409_PIN_VENDOR_WIDGET, 0xc5, 0x0000 },
-       /* test mode off */
-       { CS8409_PIN_VENDOR_WIDGET, 0xc0, 0x0000 },
-       {} /* Terminator */
-};
-
-struct sub_codec dolphin_cs42l42_0 = {
-       .addr = DOLPHIN_C0_I2C_ADDR,
-       .reset_gpio = DOLPHIN_C0_RESET,
-       .irq_mask = DOLPHIN_C0_INT,
-       .init_seq = dolphin_c0_init_reg_seq,
-       .init_seq_num = ARRAY_SIZE(dolphin_c0_init_reg_seq),
-       .hp_jack_in = 0,
-       .mic_jack_in = 0,
-       .paged = 1,
-       .suspended = 1,
-       .no_type_dect = 0,
-};
-
-struct sub_codec dolphin_cs42l42_1 = {
-       .addr = DOLPHIN_C1_I2C_ADDR,
-       .reset_gpio = DOLPHIN_C1_RESET,
-       .irq_mask = DOLPHIN_C1_INT,
-       .init_seq = dolphin_c1_init_reg_seq,
-       .init_seq_num = ARRAY_SIZE(dolphin_c1_init_reg_seq),
-       .hp_jack_in = 0,
-       .mic_jack_in = 0,
-       .paged = 1,
-       .suspended = 1,
-       .no_type_dect = 1,
-};
-
-/******************************************************************************
- *                         CS8409 Patch Driver Structs
- *                    Arrays Used for all projects using CS8409
- ******************************************************************************/
-
-const struct hda_quirk cs8409_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1028, 0x0A11, "Bullseye", CS8409_BULLSEYE),
-       SND_PCI_QUIRK(0x1028, 0x0A12, "Bullseye", CS8409_BULLSEYE),
-       SND_PCI_QUIRK(0x1028, 0x0A23, "Bullseye", CS8409_BULLSEYE),
-       SND_PCI_QUIRK(0x1028, 0x0A24, "Bullseye", CS8409_BULLSEYE),
-       SND_PCI_QUIRK(0x1028, 0x0A25, "Bullseye", CS8409_BULLSEYE),
-       SND_PCI_QUIRK(0x1028, 0x0A29, "Bullseye", CS8409_BULLSEYE),
-       SND_PCI_QUIRK(0x1028, 0x0A2A, "Bullseye", CS8409_BULLSEYE),
-       SND_PCI_QUIRK(0x1028, 0x0A2B, "Bullseye", CS8409_BULLSEYE),
-       SND_PCI_QUIRK(0x1028, 0x0A77, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0A78, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0A79, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0A7A, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0A7D, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0A7E, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0A7F, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0A80, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AB0, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0AB2, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0AB1, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0AB3, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0AB4, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0AB5, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0ACF, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0AD0, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0AD1, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0AD2, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0AD3, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0AD9, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0ADA, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0ADB, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0ADC, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0ADF, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AE0, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AE1, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AE2, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AE9, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AEA, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AEB, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AEC, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AED, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AEE, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AEF, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AF0, "Cyborg", CS8409_CYBORG),
-       SND_PCI_QUIRK(0x1028, 0x0AF4, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0AF5, "Warlock", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0B92, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0B93, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0B94, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0B95, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0B96, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0B97, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0BA5, "Odin", CS8409_ODIN),
-       SND_PCI_QUIRK(0x1028, 0x0BA6, "Odin", CS8409_ODIN),
-       SND_PCI_QUIRK(0x1028, 0x0BA8, "Odin", CS8409_ODIN),
-       SND_PCI_QUIRK(0x1028, 0x0BAA, "Odin", CS8409_ODIN),
-       SND_PCI_QUIRK(0x1028, 0x0BAE, "Odin", CS8409_ODIN),
-       SND_PCI_QUIRK(0x1028, 0x0BB2, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0BB3, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0BB4, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0BB5, "Warlock N3 15 TGL-U Nuvoton EC", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0BB6, "Warlock V3 15 TGL-U Nuvoton EC", CS8409_WARLOCK),
-       SND_PCI_QUIRK(0x1028, 0x0BB8, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0BB9, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0BBA, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0BBB, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0BBC, "Warlock MLK", CS8409_WARLOCK_MLK),
-       SND_PCI_QUIRK(0x1028, 0x0BBD, "Warlock MLK Dual Mic", CS8409_WARLOCK_MLK_DUAL_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0BD4, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0BD5, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0BD6, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0BD7, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0BD8, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0C43, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0C50, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0C51, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0C52, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0C73, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0C75, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0C7D, "Dolphin", CS8409_DOLPHIN),
-       SND_PCI_QUIRK(0x1028, 0x0C7F, "Dolphin", CS8409_DOLPHIN),
-       {} /* terminator */
-};
-
-/* Dell Inspiron models with cs8409/cs42l42 */
-const struct hda_model_fixup cs8409_models[] = {
-       { .id = CS8409_BULLSEYE, .name = "bullseye" },
-       { .id = CS8409_WARLOCK, .name = "warlock" },
-       { .id = CS8409_WARLOCK_MLK, .name = "warlock mlk" },
-       { .id = CS8409_WARLOCK_MLK_DUAL_MIC, .name = "warlock mlk dual mic" },
-       { .id = CS8409_CYBORG, .name = "cyborg" },
-       { .id = CS8409_DOLPHIN, .name = "dolphin" },
-       { .id = CS8409_ODIN, .name = "odin" },
-       {}
-};
-
-const struct hda_fixup cs8409_fixups[] = {
-       [CS8409_BULLSEYE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cs8409_cs42l42_pincfgs,
-               .chained = true,
-               .chain_id = CS8409_FIXUPS,
-       },
-       [CS8409_WARLOCK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cs8409_cs42l42_pincfgs,
-               .chained = true,
-               .chain_id = CS8409_FIXUPS,
-       },
-       [CS8409_WARLOCK_MLK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cs8409_cs42l42_pincfgs,
-               .chained = true,
-               .chain_id = CS8409_FIXUPS,
-       },
-       [CS8409_WARLOCK_MLK_DUAL_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cs8409_cs42l42_pincfgs,
-               .chained = true,
-               .chain_id = CS8409_FIXUPS,
-       },
-       [CS8409_CYBORG] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cs8409_cs42l42_pincfgs,
-               .chained = true,
-               .chain_id = CS8409_FIXUPS,
-       },
-       [CS8409_FIXUPS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs8409_cs42l42_fixups,
-       },
-       [CS8409_DOLPHIN] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dolphin_pincfgs,
-               .chained = true,
-               .chain_id = CS8409_DOLPHIN_FIXUPS,
-       },
-       [CS8409_DOLPHIN_FIXUPS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = dolphin_fixups,
-       },
-       [CS8409_ODIN] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = cs8409_cs42l42_pincfgs_no_dmic,
-               .chained = true,
-               .chain_id = CS8409_FIXUPS,
-       },
-};
diff --git a/sound/pci/hda/patch_cs8409.c b/sound/pci/hda/patch_cs8409.c
deleted file mode 100644 (file)
index e500067..0000000
+++ /dev/null
@@ -1,1484 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
- *
- * Copyright (C) 2021 Cirrus Logic, Inc. and
- *                    Cirrus Logic International Semiconductor Ltd.
- */
-
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <linux/mutex.h>
-#include <linux/iopoll.h>
-
-#include "patch_cs8409.h"
-
-/******************************************************************************
- *                        CS8409 Specific Functions
- ******************************************************************************/
-
-static int cs8409_parse_auto_config(struct hda_codec *codec)
-{
-       struct cs8409_spec *spec = codec->spec;
-       int err;
-       int i;
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
-       if (err < 0)
-               return err;
-
-       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
-       if (err < 0)
-               return err;
-
-       /* keep the ADCs powered up when it's dynamically switchable */
-       if (spec->gen.dyn_adc_switch) {
-               unsigned int done = 0;
-
-               for (i = 0; i < spec->gen.input_mux.num_items; i++) {
-                       int idx = spec->gen.dyn_adc_idx[i];
-
-                       if (done & (1 << idx))
-                               continue;
-                       snd_hda_gen_fix_pin_power(codec, spec->gen.adc_nids[idx]);
-                       done |= 1 << idx;
-               }
-       }
-
-       return 0;
-}
-
-static void cs8409_disable_i2c_clock_worker(struct work_struct *work);
-
-static struct cs8409_spec *cs8409_alloc_spec(struct hda_codec *codec)
-{
-       struct cs8409_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return NULL;
-       codec->spec = spec;
-       spec->codec = codec;
-       codec->power_save_node = 1;
-       mutex_init(&spec->i2c_mux);
-       INIT_DELAYED_WORK(&spec->i2c_clk_work, cs8409_disable_i2c_clock_worker);
-       snd_hda_gen_spec_init(&spec->gen);
-
-       return spec;
-}
-
-static inline int cs8409_vendor_coef_get(struct hda_codec *codec, unsigned int idx)
-{
-       snd_hda_codec_write(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_SET_COEF_INDEX, idx);
-       return snd_hda_codec_read(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_GET_PROC_COEF, 0);
-}
-
-static inline void cs8409_vendor_coef_set(struct hda_codec *codec, unsigned int idx,
-                                         unsigned int coef)
-{
-       snd_hda_codec_write(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_SET_COEF_INDEX, idx);
-       snd_hda_codec_write(codec, CS8409_PIN_VENDOR_WIDGET, 0, AC_VERB_SET_PROC_COEF, coef);
-}
-
-/*
- * cs8409_enable_i2c_clock - Disable I2C clocks
- * @codec: the codec instance
- * Disable I2C clocks.
- * This must be called when the i2c mutex is unlocked.
- */
-static void cs8409_disable_i2c_clock(struct hda_codec *codec)
-{
-       struct cs8409_spec *spec = codec->spec;
-
-       mutex_lock(&spec->i2c_mux);
-       if (spec->i2c_clck_enabled) {
-               cs8409_vendor_coef_set(spec->codec, 0x0,
-                              cs8409_vendor_coef_get(spec->codec, 0x0) & 0xfffffff7);
-               spec->i2c_clck_enabled = 0;
-       }
-       mutex_unlock(&spec->i2c_mux);
-}
-
-/*
- * cs8409_disable_i2c_clock_worker - Worker that disable the I2C Clock after 25ms without use
- */
-static void cs8409_disable_i2c_clock_worker(struct work_struct *work)
-{
-       struct cs8409_spec *spec = container_of(work, struct cs8409_spec, i2c_clk_work.work);
-
-       cs8409_disable_i2c_clock(spec->codec);
-}
-
-/*
- * cs8409_enable_i2c_clock - Enable I2C clocks
- * @codec: the codec instance
- * Enable I2C clocks.
- * This must be called when the i2c mutex is locked.
- */
-static void cs8409_enable_i2c_clock(struct hda_codec *codec)
-{
-       struct cs8409_spec *spec = codec->spec;
-
-       /* Cancel the disable timer, but do not wait for any running disable functions to finish.
-        * If the disable timer runs out before cancel, the delayed work thread will be blocked,
-        * waiting for the mutex to become unlocked. This mutex will be locked for the duration of
-        * any i2c transaction, so the disable function will run to completion immediately
-        * afterwards in the scenario. The next enable call will re-enable the clock, regardless.
-        */
-       cancel_delayed_work(&spec->i2c_clk_work);
-
-       if (!spec->i2c_clck_enabled) {
-               cs8409_vendor_coef_set(codec, 0x0, cs8409_vendor_coef_get(codec, 0x0) | 0x8);
-               spec->i2c_clck_enabled = 1;
-       }
-       queue_delayed_work(system_power_efficient_wq, &spec->i2c_clk_work, msecs_to_jiffies(25));
-}
-
-/**
- * cs8409_i2c_wait_complete - Wait for I2C transaction
- * @codec: the codec instance
- *
- * Wait for I2C transaction to complete.
- * Return -ETIMEDOUT if transaction wait times out.
- */
-static int cs8409_i2c_wait_complete(struct hda_codec *codec)
-{
-       unsigned int retval;
-
-       return read_poll_timeout(cs8409_vendor_coef_get, retval, retval & 0x18,
-               CS42L42_I2C_SLEEP_US, CS42L42_I2C_TIMEOUT_US, false, codec, CS8409_I2C_STS);
-}
-
-/**
- * cs8409_set_i2c_dev_addr - Set i2c address for transaction
- * @codec: the codec instance
- * @addr: I2C Address
- */
-static void cs8409_set_i2c_dev_addr(struct hda_codec *codec, unsigned int addr)
-{
-       struct cs8409_spec *spec = codec->spec;
-
-       if (spec->dev_addr != addr) {
-               cs8409_vendor_coef_set(codec, CS8409_I2C_ADDR, addr);
-               spec->dev_addr = addr;
-       }
-}
-
-/**
- * cs8409_i2c_set_page - CS8409 I2C set page register.
- * @scodec: the codec instance
- * @i2c_reg: Page register
- *
- * Returns negative on error.
- */
-static int cs8409_i2c_set_page(struct sub_codec *scodec, unsigned int i2c_reg)
-{
-       struct hda_codec *codec = scodec->codec;
-
-       if (scodec->paged && (scodec->last_page != (i2c_reg >> 8))) {
-               cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg >> 8);
-               if (cs8409_i2c_wait_complete(codec) < 0)
-                       return -EIO;
-               scodec->last_page = i2c_reg >> 8;
-       }
-
-       return 0;
-}
-
-/**
- * cs8409_i2c_read - CS8409 I2C Read.
- * @scodec: the codec instance
- * @addr: Register to read
- *
- * Returns negative on error, otherwise returns read value in bits 0-7.
- */
-static int cs8409_i2c_read(struct sub_codec *scodec, unsigned int addr)
-{
-       struct hda_codec *codec = scodec->codec;
-       struct cs8409_spec *spec = codec->spec;
-       unsigned int i2c_reg_data;
-       unsigned int read_data;
-
-       if (scodec->suspended)
-               return -EPERM;
-
-       mutex_lock(&spec->i2c_mux);
-       cs8409_enable_i2c_clock(codec);
-       cs8409_set_i2c_dev_addr(codec, scodec->addr);
-
-       if (cs8409_i2c_set_page(scodec, addr))
-               goto error;
-
-       i2c_reg_data = (addr << 8) & 0x0ffff;
-       cs8409_vendor_coef_set(codec, CS8409_I2C_QREAD, i2c_reg_data);
-       if (cs8409_i2c_wait_complete(codec) < 0)
-               goto error;
-
-       /* Register in bits 15-8 and the data in 7-0 */
-       read_data = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD);
-
-       mutex_unlock(&spec->i2c_mux);
-
-       return read_data & 0x0ff;
-
-error:
-       mutex_unlock(&spec->i2c_mux);
-       codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr);
-       return -EIO;
-}
-
-/**
- * cs8409_i2c_bulk_read - CS8409 I2C Read Sequence.
- * @scodec: the codec instance
- * @seq: Register Sequence to read
- * @count: Number of registeres to read
- *
- * Returns negative on error, values are read into value element of cs8409_i2c_param sequence.
- */
-static int cs8409_i2c_bulk_read(struct sub_codec *scodec, struct cs8409_i2c_param *seq, int count)
-{
-       struct hda_codec *codec = scodec->codec;
-       struct cs8409_spec *spec = codec->spec;
-       unsigned int i2c_reg_data;
-       int i;
-
-       if (scodec->suspended)
-               return -EPERM;
-
-       mutex_lock(&spec->i2c_mux);
-       cs8409_set_i2c_dev_addr(codec, scodec->addr);
-
-       for (i = 0; i < count; i++) {
-               cs8409_enable_i2c_clock(codec);
-               if (cs8409_i2c_set_page(scodec, seq[i].addr))
-                       goto error;
-
-               i2c_reg_data = (seq[i].addr << 8) & 0x0ffff;
-               cs8409_vendor_coef_set(codec, CS8409_I2C_QREAD, i2c_reg_data);
-
-               if (cs8409_i2c_wait_complete(codec) < 0)
-                       goto error;
-
-               seq[i].value = cs8409_vendor_coef_get(codec, CS8409_I2C_QREAD) & 0xff;
-       }
-
-       mutex_unlock(&spec->i2c_mux);
-
-       return 0;
-
-error:
-       mutex_unlock(&spec->i2c_mux);
-       codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
-       return -EIO;
-}
-
-/**
- * cs8409_i2c_write - CS8409 I2C Write.
- * @scodec: the codec instance
- * @addr: Register to write to
- * @value: Data to write
- *
- * Returns negative on error, otherwise returns 0.
- */
-static int cs8409_i2c_write(struct sub_codec *scodec, unsigned int addr, unsigned int value)
-{
-       struct hda_codec *codec = scodec->codec;
-       struct cs8409_spec *spec = codec->spec;
-       unsigned int i2c_reg_data;
-
-       if (scodec->suspended)
-               return -EPERM;
-
-       mutex_lock(&spec->i2c_mux);
-
-       cs8409_enable_i2c_clock(codec);
-       cs8409_set_i2c_dev_addr(codec, scodec->addr);
-
-       if (cs8409_i2c_set_page(scodec, addr))
-               goto error;
-
-       i2c_reg_data = ((addr << 8) & 0x0ff00) | (value & 0x0ff);
-       cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg_data);
-
-       if (cs8409_i2c_wait_complete(codec) < 0)
-               goto error;
-
-       mutex_unlock(&spec->i2c_mux);
-       return 0;
-
-error:
-       mutex_unlock(&spec->i2c_mux);
-       codec_err(codec, "%s() Failed 0x%02x : 0x%04x\n", __func__, scodec->addr, addr);
-       return -EIO;
-}
-
-/**
- * cs8409_i2c_bulk_write - CS8409 I2C Write Sequence.
- * @scodec: the codec instance
- * @seq: Register Sequence to write
- * @count: Number of registeres to write
- *
- * Returns negative on error.
- */
-static int cs8409_i2c_bulk_write(struct sub_codec *scodec, const struct cs8409_i2c_param *seq,
-                                int count)
-{
-       struct hda_codec *codec = scodec->codec;
-       struct cs8409_spec *spec = codec->spec;
-       unsigned int i2c_reg_data;
-       int i;
-
-       if (scodec->suspended)
-               return -EPERM;
-
-       mutex_lock(&spec->i2c_mux);
-       cs8409_set_i2c_dev_addr(codec, scodec->addr);
-
-       for (i = 0; i < count; i++) {
-               cs8409_enable_i2c_clock(codec);
-               if (cs8409_i2c_set_page(scodec, seq[i].addr))
-                       goto error;
-
-               i2c_reg_data = ((seq[i].addr << 8) & 0x0ff00) | (seq[i].value & 0x0ff);
-               cs8409_vendor_coef_set(codec, CS8409_I2C_QWRITE, i2c_reg_data);
-
-               if (cs8409_i2c_wait_complete(codec) < 0)
-                       goto error;
-               /* Certain use cases may require a delay
-                * after a write operation before proceeding.
-                */
-               if (seq[i].delay)
-                       fsleep(seq[i].delay);
-       }
-
-       mutex_unlock(&spec->i2c_mux);
-
-       return 0;
-
-error:
-       mutex_unlock(&spec->i2c_mux);
-       codec_err(codec, "I2C Bulk Write Failed 0x%02x\n", scodec->addr);
-       return -EIO;
-}
-
-static int cs8409_init(struct hda_codec *codec)
-{
-       int ret = snd_hda_gen_init(codec);
-
-       if (!ret)
-               snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
-
-       return ret;
-}
-
-static int cs8409_build_controls(struct hda_codec *codec)
-{
-       int err;
-
-       err = snd_hda_gen_build_controls(codec);
-       if (err < 0)
-               return err;
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
-
-       return 0;
-}
-
-/* Enable/Disable Unsolicited Response */
-static void cs8409_enable_ur(struct hda_codec *codec, int flag)
-{
-       struct cs8409_spec *spec = codec->spec;
-       unsigned int ur_gpios = 0;
-       int i;
-
-       for (i = 0; i < spec->num_scodecs; i++)
-               ur_gpios |= spec->scodecs[i]->irq_mask;
-
-       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK,
-                           flag ? ur_gpios : 0);
-
-       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_UNSOLICITED_ENABLE,
-                           flag ? AC_UNSOL_ENABLED : 0);
-}
-
-static void cs8409_fix_caps(struct hda_codec *codec, unsigned int nid)
-{
-       int caps;
-
-       /* CS8409 is simple HDA bridge and intended to be used with a remote
-        * companion codec. Most of input/output PIN(s) have only basic
-        * capabilities. Receive and Transmit NID(s) have only OUTC and INC
-        * capabilities and no presence detect capable (PDC) and call to
-        * snd_hda_gen_build_controls() will mark them as non detectable
-        * phantom jacks. However, a companion codec may be
-        * connected to these pins which supports jack detect
-        * capabilities. We have to override pin capabilities,
-        * otherwise they will not be created as input devices.
-        */
-       caps = snd_hdac_read_parm(&codec->core, nid, AC_PAR_PIN_CAP);
-       if (caps >= 0)
-               snd_hdac_override_parm(&codec->core, nid, AC_PAR_PIN_CAP,
-                                      (caps | (AC_PINCAP_IMP_SENSE | AC_PINCAP_PRES_DETECT)));
-
-       snd_hda_override_wcaps(codec, nid, (get_wcaps(codec, nid) | AC_WCAP_UNSOL_CAP));
-}
-
-static int cs8409_spk_sw_gpio_get(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct cs8409_spec *spec = codec->spec;
-
-       ucontrol->value.integer.value[0] = !!(spec->gpio_data & spec->speaker_pdn_gpio);
-       return 0;
-}
-
-static int cs8409_spk_sw_gpio_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct cs8409_spec *spec = codec->spec;
-       unsigned int gpio_data;
-
-       gpio_data = (spec->gpio_data & ~spec->speaker_pdn_gpio) |
-               (ucontrol->value.integer.value[0] ? spec->speaker_pdn_gpio : 0);
-       if (gpio_data == spec->gpio_data)
-               return 0;
-       spec->gpio_data = gpio_data;
-       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
-       return 1;
-}
-
-static const struct snd_kcontrol_new cs8409_spk_sw_ctrl = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .info = snd_ctl_boolean_mono_info,
-       .get = cs8409_spk_sw_gpio_get,
-       .put = cs8409_spk_sw_gpio_put,
-};
-
-/******************************************************************************
- *                        CS42L42 Specific Functions
- ******************************************************************************/
-
-int cs42l42_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo)
-{
-       unsigned int ofs = get_amp_offset(kctrl);
-       u8 chs = get_amp_channels(kctrl);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->value.integer.step = 1;
-       uinfo->count = chs == 3 ? 2 : 1;
-
-       switch (ofs) {
-       case CS42L42_VOL_DAC:
-               uinfo->value.integer.min = CS42L42_HP_VOL_REAL_MIN;
-               uinfo->value.integer.max = CS42L42_HP_VOL_REAL_MAX;
-               break;
-       case CS42L42_VOL_ADC:
-               uinfo->value.integer.min = CS42L42_AMIC_VOL_REAL_MIN;
-               uinfo->value.integer.max = CS42L42_AMIC_VOL_REAL_MAX;
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kctrl);
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42 = spec->scodecs[get_amp_index(kctrl)];
-       int chs = get_amp_channels(kctrl);
-       unsigned int ofs = get_amp_offset(kctrl);
-       long *valp = uctrl->value.integer.value;
-
-       switch (ofs) {
-       case CS42L42_VOL_DAC:
-               if (chs & BIT(0))
-                       *valp++ = cs42l42->vol[ofs];
-               if (chs & BIT(1))
-                       *valp = cs42l42->vol[ofs+1];
-               break;
-       case CS42L42_VOL_ADC:
-               if (chs & BIT(0))
-                       *valp = cs42l42->vol[ofs];
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static void cs42l42_mute(struct sub_codec *cs42l42, int vol_type,
-       unsigned int chs, bool mute)
-{
-       if (mute) {
-               if (vol_type == CS42L42_VOL_DAC) {
-                       if (chs & BIT(0))
-                               cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHA_VOL, 0x3f);
-                       if (chs & BIT(1))
-                               cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHB_VOL, 0x3f);
-               } else if (vol_type == CS42L42_VOL_ADC) {
-                       if (chs & BIT(0))
-                               cs8409_i2c_write(cs42l42, CS42L42_ADC_VOLUME, 0x9f);
-               }
-       } else {
-               if (vol_type == CS42L42_VOL_DAC) {
-                       if (chs & BIT(0))
-                               cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHA_VOL,
-                                       -(cs42l42->vol[CS42L42_DAC_CH0_VOL_OFFSET])
-                                       & CS42L42_MIXER_CH_VOL_MASK);
-                       if (chs & BIT(1))
-                               cs8409_i2c_write(cs42l42, CS42L42_MIXER_CHB_VOL,
-                                       -(cs42l42->vol[CS42L42_DAC_CH1_VOL_OFFSET])
-                                       & CS42L42_MIXER_CH_VOL_MASK);
-               } else if (vol_type == CS42L42_VOL_ADC) {
-                       if (chs & BIT(0))
-                               cs8409_i2c_write(cs42l42, CS42L42_ADC_VOLUME,
-                                       cs42l42->vol[CS42L42_ADC_VOL_OFFSET]
-                                       & CS42L42_REG_AMIC_VOL_MASK);
-               }
-       }
-}
-
-int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kctrl);
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42 = spec->scodecs[get_amp_index(kctrl)];
-       int chs = get_amp_channels(kctrl);
-       unsigned int ofs = get_amp_offset(kctrl);
-       long *valp = uctrl->value.integer.value;
-
-       switch (ofs) {
-       case CS42L42_VOL_DAC:
-               if (chs & BIT(0))
-                       cs42l42->vol[ofs] = *valp;
-               if (chs & BIT(1)) {
-                       valp++;
-                       cs42l42->vol[ofs + 1] = *valp;
-               }
-               if (spec->playback_started)
-                       cs42l42_mute(cs42l42, CS42L42_VOL_DAC, chs, false);
-               break;
-       case CS42L42_VOL_ADC:
-               if (chs & BIT(0))
-                       cs42l42->vol[ofs] = *valp;
-               if (spec->capture_started)
-                       cs42l42_mute(cs42l42, CS42L42_VOL_ADC, chs, false);
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static void cs42l42_playback_pcm_hook(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream,
-                                  int action)
-{
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42;
-       int i;
-       bool mute;
-
-       switch (action) {
-       case HDA_GEN_PCM_ACT_PREPARE:
-               mute = false;
-               spec->playback_started = 1;
-               break;
-       case HDA_GEN_PCM_ACT_CLEANUP:
-               mute = true;
-               spec->playback_started = 0;
-               break;
-       default:
-               return;
-       }
-
-       for (i = 0; i < spec->num_scodecs; i++) {
-               cs42l42 = spec->scodecs[i];
-               cs42l42_mute(cs42l42, CS42L42_VOL_DAC, 0x3, mute);
-       }
-}
-
-static void cs42l42_capture_pcm_hook(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream,
-                                  int action)
-{
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42;
-       int i;
-       bool mute;
-
-       switch (action) {
-       case HDA_GEN_PCM_ACT_PREPARE:
-               mute = false;
-               spec->capture_started = 1;
-               break;
-       case HDA_GEN_PCM_ACT_CLEANUP:
-               mute = true;
-               spec->capture_started = 0;
-               break;
-       default:
-               return;
-       }
-
-       for (i = 0; i < spec->num_scodecs; i++) {
-               cs42l42 = spec->scodecs[i];
-               cs42l42_mute(cs42l42, CS42L42_VOL_ADC, 0x3, mute);
-       }
-}
-
-/* Configure CS42L42 slave codec for jack autodetect */
-static void cs42l42_enable_jack_detect(struct sub_codec *cs42l42)
-{
-       cs8409_i2c_write(cs42l42, CS42L42_HSBIAS_SC_AUTOCTL, cs42l42->hsbias_hiz);
-       /* Clear WAKE# */
-       cs8409_i2c_write(cs42l42, CS42L42_WAKE_CTL, 0x00C1);
-       /* Wait ~2.5ms */
-       usleep_range(2500, 3000);
-       /* Set mode WAKE# output follows the combination logic directly */
-       cs8409_i2c_write(cs42l42, CS42L42_WAKE_CTL, 0x00C0);
-       /* Clear interrupts status */
-       cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS);
-       /* Enable interrupt */
-       cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xF3);
-}
-
-/* Enable and run CS42L42 slave codec jack auto detect */
-static void cs42l42_run_jack_detect(struct sub_codec *cs42l42)
-{
-       /* Clear interrupts */
-       cs8409_i2c_read(cs42l42, CS42L42_CODEC_STATUS);
-       cs8409_i2c_read(cs42l42, CS42L42_DET_STATUS1);
-       cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xFF);
-       cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS);
-
-       cs8409_i2c_write(cs42l42, CS42L42_PWR_CTL2, 0x87);
-       cs8409_i2c_write(cs42l42, CS42L42_DAC_CTL2, 0x86);
-       cs8409_i2c_write(cs42l42, CS42L42_MISC_DET_CTL, 0x07);
-       cs8409_i2c_write(cs42l42, CS42L42_CODEC_INT_MASK, 0xFD);
-       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0x80);
-       /* Wait ~20ms*/
-       usleep_range(20000, 25000);
-       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1, 0x77);
-       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0xc0);
-}
-
-static int cs42l42_manual_hs_det(struct sub_codec *cs42l42)
-{
-       unsigned int hs_det_status;
-       unsigned int hs_det_comp1;
-       unsigned int hs_det_comp2;
-       unsigned int hs_det_sw;
-       unsigned int hs_type;
-
-       /* Set hs detect to manual, active mode */
-       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2,
-                        (1 << CS42L42_HSDET_CTRL_SHIFT) |
-                        (0 << CS42L42_HSDET_SET_SHIFT) |
-                        (0 << CS42L42_HSBIAS_REF_SHIFT) |
-                        (0 << CS42L42_HSDET_AUTO_TIME_SHIFT));
-
-       /* Configure HS DET comparator reference levels. */
-       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1,
-                        (CS42L42_HSDET_COMP1_LVL_VAL << CS42L42_HSDET_COMP1_LVL_SHIFT) |
-                        (CS42L42_HSDET_COMP2_LVL_VAL << CS42L42_HSDET_COMP2_LVL_SHIFT));
-
-       /* Open the SW_HSB_HS3 switch and close SW_HSB_HS4 for a Type 1 headset. */
-       cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP1);
-
-       msleep(100);
-
-       hs_det_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS);
-
-       hs_det_comp1 = (hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >>
-                       CS42L42_HSDET_COMP1_OUT_SHIFT;
-       hs_det_comp2 = (hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >>
-                       CS42L42_HSDET_COMP2_OUT_SHIFT;
-
-       /* Close the SW_HSB_HS3 switch for a Type 2 headset. */
-       cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, CS42L42_HSDET_SW_COMP2);
-
-       msleep(100);
-
-       hs_det_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS);
-
-       hs_det_comp1 |= ((hs_det_status & CS42L42_HSDET_COMP1_OUT_MASK) >>
-                       CS42L42_HSDET_COMP1_OUT_SHIFT) << 1;
-       hs_det_comp2 |= ((hs_det_status & CS42L42_HSDET_COMP2_OUT_MASK) >>
-                       CS42L42_HSDET_COMP2_OUT_SHIFT) << 1;
-
-       /* Use Comparator 1 with 1.25V Threshold. */
-       switch (hs_det_comp1) {
-       case CS42L42_HSDET_COMP_TYPE1:
-               hs_type = CS42L42_PLUG_CTIA;
-               hs_det_sw = CS42L42_HSDET_SW_TYPE1;
-               break;
-       case CS42L42_HSDET_COMP_TYPE2:
-               hs_type = CS42L42_PLUG_OMTP;
-               hs_det_sw = CS42L42_HSDET_SW_TYPE2;
-               break;
-       default:
-               /* Fallback to Comparator 2 with 1.75V Threshold. */
-               switch (hs_det_comp2) {
-               case CS42L42_HSDET_COMP_TYPE1:
-                       hs_type = CS42L42_PLUG_CTIA;
-                       hs_det_sw = CS42L42_HSDET_SW_TYPE1;
-                       break;
-               case CS42L42_HSDET_COMP_TYPE2:
-                       hs_type = CS42L42_PLUG_OMTP;
-                       hs_det_sw = CS42L42_HSDET_SW_TYPE2;
-                       break;
-               case CS42L42_HSDET_COMP_TYPE3:
-                       hs_type = CS42L42_PLUG_HEADPHONE;
-                       hs_det_sw = CS42L42_HSDET_SW_TYPE3;
-                       break;
-               default:
-                       hs_type = CS42L42_PLUG_INVALID;
-                       hs_det_sw = CS42L42_HSDET_SW_TYPE4;
-                       break;
-               }
-       }
-
-       /* Set Switches */
-       cs8409_i2c_write(cs42l42, CS42L42_HS_SWITCH_CTL, hs_det_sw);
-
-       /* Set HSDET mode to Manual—Disabled */
-       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2,
-                        (0 << CS42L42_HSDET_CTRL_SHIFT) |
-                        (0 << CS42L42_HSDET_SET_SHIFT) |
-                        (0 << CS42L42_HSBIAS_REF_SHIFT) |
-                        (0 << CS42L42_HSDET_AUTO_TIME_SHIFT));
-
-       /* Configure HS DET comparator reference levels. */
-       cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL1,
-                        (CS42L42_HSDET_COMP1_LVL_DEFAULT << CS42L42_HSDET_COMP1_LVL_SHIFT) |
-                        (CS42L42_HSDET_COMP2_LVL_DEFAULT << CS42L42_HSDET_COMP2_LVL_SHIFT));
-
-       return hs_type;
-}
-
-static int cs42l42_handle_tip_sense(struct sub_codec *cs42l42, unsigned int reg_ts_status)
-{
-       int status_changed = 0;
-
-       /* TIP_SENSE INSERT/REMOVE */
-       switch (reg_ts_status) {
-       case CS42L42_TS_PLUG:
-               if (cs42l42->no_type_dect) {
-                       status_changed = 1;
-                       cs42l42->hp_jack_in = 1;
-                       cs42l42->mic_jack_in = 0;
-               } else {
-                       cs42l42_run_jack_detect(cs42l42);
-               }
-               break;
-
-       case CS42L42_TS_UNPLUG:
-               status_changed = 1;
-               cs42l42->hp_jack_in = 0;
-               cs42l42->mic_jack_in = 0;
-               break;
-       default:
-               /* jack in transition */
-               break;
-       }
-
-       codec_dbg(cs42l42->codec, "Tip Sense Detection: (%d)\n", reg_ts_status);
-
-       return status_changed;
-}
-
-static int cs42l42_jack_unsol_event(struct sub_codec *cs42l42)
-{
-       int current_plug_status;
-       int status_changed = 0;
-       int reg_cdc_status;
-       int reg_hs_status;
-       int reg_ts_status;
-       int type;
-
-       /* Read jack detect status registers */
-       reg_cdc_status = cs8409_i2c_read(cs42l42, CS42L42_CODEC_STATUS);
-       reg_hs_status = cs8409_i2c_read(cs42l42, CS42L42_HS_DET_STATUS);
-       reg_ts_status = cs8409_i2c_read(cs42l42, CS42L42_TSRS_PLUG_STATUS);
-
-       /* If status values are < 0, read error has occurred. */
-       if (reg_cdc_status < 0 || reg_hs_status < 0 || reg_ts_status < 0)
-               return -EIO;
-
-       current_plug_status = (reg_ts_status & (CS42L42_TS_PLUG_MASK | CS42L42_TS_UNPLUG_MASK))
-                               >> CS42L42_TS_PLUG_SHIFT;
-
-       /* HSDET_AUTO_DONE */
-       if (reg_cdc_status & CS42L42_HSDET_AUTO_DONE_MASK) {
-
-               /* Disable HSDET_AUTO_DONE */
-               cs8409_i2c_write(cs42l42, CS42L42_CODEC_INT_MASK, 0xFF);
-
-               type = (reg_hs_status & CS42L42_HSDET_TYPE_MASK) >> CS42L42_HSDET_TYPE_SHIFT;
-
-               /* Configure the HSDET mode. */
-               cs8409_i2c_write(cs42l42, CS42L42_HSDET_CTL2, 0x80);
-
-               if (cs42l42->no_type_dect) {
-                       status_changed = cs42l42_handle_tip_sense(cs42l42, current_plug_status);
-               } else {
-                       if (type == CS42L42_PLUG_INVALID || type == CS42L42_PLUG_HEADPHONE) {
-                               codec_dbg(cs42l42->codec,
-                                         "Auto detect value not valid (%d), running manual det\n",
-                                         type);
-                               type = cs42l42_manual_hs_det(cs42l42);
-                       }
-
-                       switch (type) {
-                       case CS42L42_PLUG_CTIA:
-                       case CS42L42_PLUG_OMTP:
-                               status_changed = 1;
-                               cs42l42->hp_jack_in = 1;
-                               cs42l42->mic_jack_in = 1;
-                               break;
-                       case CS42L42_PLUG_HEADPHONE:
-                               status_changed = 1;
-                               cs42l42->hp_jack_in = 1;
-                               cs42l42->mic_jack_in = 0;
-                               break;
-                       default:
-                               status_changed = 1;
-                               cs42l42->hp_jack_in = 0;
-                               cs42l42->mic_jack_in = 0;
-                               break;
-                       }
-                       codec_dbg(cs42l42->codec, "Detection done (%d)\n", type);
-               }
-
-               /* Enable the HPOUT ground clamp and configure the HP pull-down */
-               cs8409_i2c_write(cs42l42, CS42L42_DAC_CTL2, 0x02);
-               /* Re-Enable Tip Sense Interrupt */
-               cs8409_i2c_write(cs42l42, CS42L42_TSRS_PLUG_INT_MASK, 0xF3);
-       } else {
-               status_changed = cs42l42_handle_tip_sense(cs42l42, current_plug_status);
-       }
-
-       return status_changed;
-}
-
-static void cs42l42_resume(struct sub_codec *cs42l42)
-{
-       struct hda_codec *codec = cs42l42->codec;
-       struct cs8409_spec *spec = codec->spec;
-       struct cs8409_i2c_param irq_regs[] = {
-               { CS42L42_CODEC_STATUS, 0x00 },
-               { CS42L42_DET_INT_STATUS1, 0x00 },
-               { CS42L42_DET_INT_STATUS2, 0x00 },
-               { CS42L42_TSRS_PLUG_STATUS, 0x00 },
-       };
-       unsigned int fsv;
-
-       /* Bring CS42L42 out of Reset */
-       spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
-       spec->gpio_data |= cs42l42->reset_gpio;
-       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
-       usleep_range(10000, 15000);
-
-       cs42l42->suspended = 0;
-
-       /* Initialize CS42L42 companion codec */
-       cs8409_i2c_bulk_write(cs42l42, cs42l42->init_seq, cs42l42->init_seq_num);
-
-       /* Clear interrupts, by reading interrupt status registers */
-       cs8409_i2c_bulk_read(cs42l42, irq_regs, ARRAY_SIZE(irq_regs));
-
-       fsv = cs8409_i2c_read(cs42l42, CS42L42_HP_CTL);
-       if (cs42l42->full_scale_vol) {
-               // Set the full scale volume bit
-               fsv |= CS42L42_FULL_SCALE_VOL_MASK;
-               cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv);
-       }
-       // Unmute analog channels A and B
-       fsv = (fsv & ~CS42L42_ANA_MUTE_AB);
-       cs8409_i2c_write(cs42l42, CS42L42_HP_CTL, fsv);
-
-       /* we have to explicitly allow unsol event handling even during the
-        * resume phase so that the jack event is processed properly
-        */
-       snd_hda_codec_allow_unsol_events(cs42l42->codec);
-
-       cs42l42_enable_jack_detect(cs42l42);
-}
-
-static void cs42l42_suspend(struct sub_codec *cs42l42)
-{
-       struct hda_codec *codec = cs42l42->codec;
-       struct cs8409_spec *spec = codec->spec;
-       int reg_cdc_status = 0;
-       const struct cs8409_i2c_param cs42l42_pwr_down_seq[] = {
-               { CS42L42_DAC_CTL2, 0x02 },
-               { CS42L42_HS_CLAMP_DISABLE, 0x00 },
-               { CS42L42_MIXER_CHA_VOL, 0x3F },
-               { CS42L42_MIXER_ADC_VOL, 0x3F },
-               { CS42L42_MIXER_CHB_VOL, 0x3F },
-               { CS42L42_HP_CTL, 0x0D },
-               { CS42L42_ASP_RX_DAI0_EN, 0x00 },
-               { CS42L42_ASP_CLK_CFG, 0x00 },
-               { CS42L42_PWR_CTL1, 0xFE },
-               { CS42L42_PWR_CTL2, 0x8C },
-               { CS42L42_PWR_CTL1, 0xFF },
-       };
-
-       cs8409_i2c_bulk_write(cs42l42, cs42l42_pwr_down_seq, ARRAY_SIZE(cs42l42_pwr_down_seq));
-
-       if (read_poll_timeout(cs8409_i2c_read, reg_cdc_status,
-                       (reg_cdc_status & 0x1), CS42L42_PDN_SLEEP_US, CS42L42_PDN_TIMEOUT_US,
-                       true, cs42l42, CS42L42_CODEC_STATUS) < 0)
-               codec_warn(codec, "Timeout waiting for PDN_DONE for CS42L42\n");
-
-       /* Power down CS42L42 ASP/EQ/MIX/HP */
-       cs8409_i2c_write(cs42l42, CS42L42_PWR_CTL2, 0x9C);
-       cs42l42->suspended = 1;
-       cs42l42->last_page = 0;
-       cs42l42->hp_jack_in = 0;
-       cs42l42->mic_jack_in = 0;
-
-       /* Put CS42L42 into Reset */
-       spec->gpio_data = snd_hda_codec_read(codec, CS8409_PIN_AFG, 0, AC_VERB_GET_GPIO_DATA, 0);
-       spec->gpio_data &= ~cs42l42->reset_gpio;
-       snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA, spec->gpio_data);
-}
-
-static void cs8409_free(struct hda_codec *codec)
-{
-       struct cs8409_spec *spec = codec->spec;
-
-       /* Cancel i2c clock disable timer, and disable clock if left enabled */
-       cancel_delayed_work_sync(&spec->i2c_clk_work);
-       cs8409_disable_i2c_clock(codec);
-
-       snd_hda_gen_free(codec);
-}
-
-/******************************************************************************
- *                   BULLSEYE / WARLOCK / CYBORG Specific Functions
- *                               CS8409/CS42L42
- ******************************************************************************/
-
-/*
- * In the case of CS8409 we do not have unsolicited events from NID's 0x24
- * and 0x34 where hs mic and hp are connected. Companion codec CS42L42 will
- * generate interrupt via gpio 4 to notify jack events. We have to overwrite
- * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
- * and then notify status via generic snd_hda_jack_unsol_event() call.
- */
-static void cs8409_cs42l42_jack_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
-       struct hda_jack_tbl *jk;
-
-       /* jack_unsol_event() will be called every time gpio line changing state.
-        * In this case gpio4 line goes up as a result of reading interrupt status
-        * registers in previous cs8409_jack_unsol_event() call.
-        * We don't need to handle this event, ignoring...
-        */
-       if (res & cs42l42->irq_mask)
-               return;
-
-       if (cs42l42_jack_unsol_event(cs42l42)) {
-               snd_hda_set_pin_ctl(codec, CS8409_CS42L42_SPK_PIN_NID,
-                                   cs42l42->hp_jack_in ? 0 : PIN_OUT);
-               /* Report jack*/
-               jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_HP_PIN_NID, 0);
-               if (jk)
-                       snd_hda_jack_unsol_event(codec, (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
-                                                       AC_UNSOL_RES_TAG);
-               /* Report jack*/
-               jk = snd_hda_jack_tbl_get_mst(codec, CS8409_CS42L42_AMIC_PIN_NID, 0);
-               if (jk)
-                       snd_hda_jack_unsol_event(codec, (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
-                                                        AC_UNSOL_RES_TAG);
-       }
-}
-
-/* Manage PDREF, when transition to D3hot */
-static int cs8409_cs42l42_suspend(struct hda_codec *codec)
-{
-       struct cs8409_spec *spec = codec->spec;
-       int i;
-
-       spec->init_done = 0;
-
-       cs8409_enable_ur(codec, 0);
-
-       for (i = 0; i < spec->num_scodecs; i++)
-               cs42l42_suspend(spec->scodecs[i]);
-
-       /* Cancel i2c clock disable timer, and disable clock if left enabled */
-       cancel_delayed_work_sync(&spec->i2c_clk_work);
-       cs8409_disable_i2c_clock(codec);
-
-       snd_hda_shutup_pins(codec);
-
-       return 0;
-}
-
-/* Vendor specific HW configuration
- * PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
- */
-static void cs8409_cs42l42_hw_init(struct hda_codec *codec)
-{
-       const struct cs8409_cir_param *seq = cs8409_cs42l42_hw_cfg;
-       const struct cs8409_cir_param *seq_bullseye = cs8409_cs42l42_bullseye_atn;
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
-
-       if (spec->gpio_mask) {
-               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_MASK,
-                       spec->gpio_mask);
-               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DIRECTION,
-                       spec->gpio_dir);
-               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA,
-                       spec->gpio_data);
-       }
-
-       for (; seq->nid; seq++)
-               cs8409_vendor_coef_set(codec, seq->cir, seq->coeff);
-
-       if (codec->fixup_id == CS8409_BULLSEYE) {
-               for (; seq_bullseye->nid; seq_bullseye++)
-                       cs8409_vendor_coef_set(codec, seq_bullseye->cir, seq_bullseye->coeff);
-       }
-
-       switch (codec->fixup_id) {
-       case CS8409_CYBORG:
-       case CS8409_WARLOCK_MLK_DUAL_MIC:
-               /* DMIC1_MO=00b, DMIC1/2_SR=1 */
-               cs8409_vendor_coef_set(codec, CS8409_DMIC_CFG, 0x0003);
-               break;
-       case CS8409_ODIN:
-               /* ASP1/2_xxx_EN=1, ASP1/2_MCLK_EN=0, DMIC1_SCL_EN=0 */
-               cs8409_vendor_coef_set(codec, CS8409_PAD_CFG_SLW_RATE_CTRL, 0xfc00);
-               break;
-       default:
-               break;
-       }
-
-       cs42l42_resume(cs42l42);
-
-       /* Enable Unsolicited Response */
-       cs8409_enable_ur(codec, 1);
-}
-
-static const struct hda_codec_ops cs8409_cs42l42_patch_ops = {
-       .build_controls = cs8409_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = cs8409_init,
-       .free = cs8409_free,
-       .unsol_event = cs8409_cs42l42_jack_unsol_event,
-       .suspend = cs8409_cs42l42_suspend,
-};
-
-static int cs8409_cs42l42_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
-                                   unsigned int *res)
-{
-       struct hda_codec *codec = container_of(dev, struct hda_codec, core);
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
-
-       unsigned int nid = ((cmd >> 20) & 0x07f);
-       unsigned int verb = ((cmd >> 8) & 0x0fff);
-
-       /* CS8409 pins have no AC_PINSENSE_PRESENCE
-        * capabilities. We have to intercept 2 calls for pins 0x24 and 0x34
-        * and return correct pin sense values for read_pin_sense() call from
-        * hda_jack based on CS42L42 jack detect status.
-        */
-       switch (nid) {
-       case CS8409_CS42L42_HP_PIN_NID:
-               if (verb == AC_VERB_GET_PIN_SENSE) {
-                       *res = (cs42l42->hp_jack_in) ? AC_PINSENSE_PRESENCE : 0;
-                       return 0;
-               }
-               break;
-       case CS8409_CS42L42_AMIC_PIN_NID:
-               if (verb == AC_VERB_GET_PIN_SENSE) {
-                       *res = (cs42l42->mic_jack_in) ? AC_PINSENSE_PRESENCE : 0;
-                       return 0;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return spec->exec_verb(dev, cmd, flags, res);
-}
-
-void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action)
-{
-       struct cs8409_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_add_verbs(codec, cs8409_cs42l42_init_verbs);
-               /* verb exec op override */
-               spec->exec_verb = codec->core.exec_verb;
-               codec->core.exec_verb = cs8409_cs42l42_exec_verb;
-
-               spec->scodecs[CS8409_CODEC0] = &cs8409_cs42l42_codec;
-               spec->num_scodecs = 1;
-               spec->scodecs[CS8409_CODEC0]->codec = codec;
-               codec->patch_ops = cs8409_cs42l42_patch_ops;
-
-               spec->gen.suppress_auto_mute = 1;
-               spec->gen.no_primary_hp = 1;
-               spec->gen.suppress_vmaster = 1;
-
-               spec->speaker_pdn_gpio = 0;
-
-               /* GPIO 5 out, 3,4 in */
-               spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio;
-               spec->gpio_data = 0;
-               spec->gpio_mask = 0x03f;
-
-               /* Basic initial sequence for specific hw configuration */
-               snd_hda_sequence_write(codec, cs8409_cs42l42_init_verbs);
-
-               cs8409_fix_caps(codec, CS8409_CS42L42_HP_PIN_NID);
-               cs8409_fix_caps(codec, CS8409_CS42L42_AMIC_PIN_NID);
-
-               spec->scodecs[CS8409_CODEC0]->hsbias_hiz = 0x0020;
-
-               switch (codec->fixup_id) {
-               case CS8409_CYBORG:
-                       spec->scodecs[CS8409_CODEC0]->full_scale_vol =
-                               CS42L42_FULL_SCALE_VOL_MINUS6DB;
-                       spec->speaker_pdn_gpio = CS8409_CYBORG_SPEAKER_PDN;
-                       break;
-               case CS8409_ODIN:
-                       spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_0DB;
-                       spec->speaker_pdn_gpio = CS8409_CYBORG_SPEAKER_PDN;
-                       break;
-               case CS8409_WARLOCK_MLK:
-               case CS8409_WARLOCK_MLK_DUAL_MIC:
-                       spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_0DB;
-                       spec->speaker_pdn_gpio = CS8409_WARLOCK_SPEAKER_PDN;
-                       break;
-               default:
-                       spec->scodecs[CS8409_CODEC0]->full_scale_vol =
-                               CS42L42_FULL_SCALE_VOL_MINUS6DB;
-                       spec->speaker_pdn_gpio = CS8409_WARLOCK_SPEAKER_PDN;
-                       break;
-               }
-
-               if (spec->speaker_pdn_gpio > 0) {
-                       spec->gpio_dir |= spec->speaker_pdn_gpio;
-                       spec->gpio_data |= spec->speaker_pdn_gpio;
-               }
-
-               break;
-       case HDA_FIXUP_ACT_PROBE:
-               /* Fix Sample Rate to 48kHz */
-               spec->gen.stream_analog_playback = &cs42l42_48k_pcm_analog_playback;
-               spec->gen.stream_analog_capture = &cs42l42_48k_pcm_analog_capture;
-               /* add hooks */
-               spec->gen.pcm_playback_hook = cs42l42_playback_pcm_hook;
-               spec->gen.pcm_capture_hook = cs42l42_capture_pcm_hook;
-               if (codec->fixup_id != CS8409_ODIN)
-                       /* Set initial DMIC volume to -26 dB */
-                       snd_hda_codec_amp_init_stereo(codec, CS8409_CS42L42_DMIC_ADC_PIN_NID,
-                                                     HDA_INPUT, 0, 0xff, 0x19);
-               snd_hda_gen_add_kctl(&spec->gen, "Headphone Playback Volume",
-                               &cs42l42_dac_volume_mixer);
-               snd_hda_gen_add_kctl(&spec->gen, "Mic Capture Volume",
-                               &cs42l42_adc_volume_mixer);
-               if (spec->speaker_pdn_gpio > 0)
-                       snd_hda_gen_add_kctl(&spec->gen, "Speaker Playback Switch",
-                                            &cs8409_spk_sw_ctrl);
-               /* Disable Unsolicited Response during boot */
-               cs8409_enable_ur(codec, 0);
-               snd_hda_codec_set_name(codec, "CS8409/CS42L42");
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               cs8409_cs42l42_hw_init(codec);
-               spec->init_done = 1;
-               if (spec->init_done && spec->build_ctrl_done
-                       && !spec->scodecs[CS8409_CODEC0]->hp_jack_in)
-                       cs42l42_run_jack_detect(spec->scodecs[CS8409_CODEC0]);
-               break;
-       case HDA_FIXUP_ACT_BUILD:
-               spec->build_ctrl_done = 1;
-               /* Run jack auto detect first time on boot
-                * after controls have been added, to check if jack has
-                * been already plugged in.
-                * Run immediately after init.
-                */
-               if (spec->init_done && spec->build_ctrl_done
-                       && !spec->scodecs[CS8409_CODEC0]->hp_jack_in)
-                       cs42l42_run_jack_detect(spec->scodecs[CS8409_CODEC0]);
-               break;
-       default:
-               break;
-       }
-}
-
-/******************************************************************************
- *                          Dolphin Specific Functions
- *                               CS8409/ 2 X CS42L42
- ******************************************************************************/
-
-/*
- * In the case of CS8409 we do not have unsolicited events when
- * hs mic and hp are connected. Companion codec CS42L42 will
- * generate interrupt via irq_mask to notify jack events. We have to overwrite
- * generic snd_hda_jack_unsol_event(), read CS42L42 jack detect status registers
- * and then notify status via generic snd_hda_jack_unsol_event() call.
- */
-static void dolphin_jack_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42;
-       struct hda_jack_tbl *jk;
-
-       cs42l42 = spec->scodecs[CS8409_CODEC0];
-       if (!cs42l42->suspended && (~res & cs42l42->irq_mask) &&
-           cs42l42_jack_unsol_event(cs42l42)) {
-               jk = snd_hda_jack_tbl_get_mst(codec, DOLPHIN_HP_PIN_NID, 0);
-               if (jk)
-                       snd_hda_jack_unsol_event(codec,
-                                                (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
-                                                 AC_UNSOL_RES_TAG);
-
-               jk = snd_hda_jack_tbl_get_mst(codec, DOLPHIN_AMIC_PIN_NID, 0);
-               if (jk)
-                       snd_hda_jack_unsol_event(codec,
-                                                (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
-                                                 AC_UNSOL_RES_TAG);
-       }
-
-       cs42l42 = spec->scodecs[CS8409_CODEC1];
-       if (!cs42l42->suspended && (~res & cs42l42->irq_mask) &&
-           cs42l42_jack_unsol_event(cs42l42)) {
-               jk = snd_hda_jack_tbl_get_mst(codec, DOLPHIN_LO_PIN_NID, 0);
-               if (jk)
-                       snd_hda_jack_unsol_event(codec,
-                                                (jk->tag << AC_UNSOL_RES_TAG_SHIFT) &
-                                                 AC_UNSOL_RES_TAG);
-       }
-}
-
-/* Vendor specific HW configuration
- * PLL, ASP, I2C, SPI, GPIOs, DMIC etc...
- */
-static void dolphin_hw_init(struct hda_codec *codec)
-{
-       const struct cs8409_cir_param *seq = dolphin_hw_cfg;
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42;
-       int i;
-
-       if (spec->gpio_mask) {
-               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_MASK,
-                                   spec->gpio_mask);
-               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DIRECTION,
-                                   spec->gpio_dir);
-               snd_hda_codec_write(codec, CS8409_PIN_AFG, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_data);
-       }
-
-       for (; seq->nid; seq++)
-               cs8409_vendor_coef_set(codec, seq->cir, seq->coeff);
-
-       for (i = 0; i < spec->num_scodecs; i++) {
-               cs42l42 = spec->scodecs[i];
-               cs42l42_resume(cs42l42);
-       }
-
-       /* Enable Unsolicited Response */
-       cs8409_enable_ur(codec, 1);
-}
-
-static const struct hda_codec_ops cs8409_dolphin_patch_ops = {
-       .build_controls = cs8409_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = cs8409_init,
-       .free = cs8409_free,
-       .unsol_event = dolphin_jack_unsol_event,
-       .suspend = cs8409_cs42l42_suspend,
-};
-
-static int dolphin_exec_verb(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
-                            unsigned int *res)
-{
-       struct hda_codec *codec = container_of(dev, struct hda_codec, core);
-       struct cs8409_spec *spec = codec->spec;
-       struct sub_codec *cs42l42 = spec->scodecs[CS8409_CODEC0];
-
-       unsigned int nid = ((cmd >> 20) & 0x07f);
-       unsigned int verb = ((cmd >> 8) & 0x0fff);
-
-       /* CS8409 pins have no AC_PINSENSE_PRESENCE
-        * capabilities. We have to intercept calls for CS42L42 pins
-        * and return correct pin sense values for read_pin_sense() call from
-        * hda_jack based on CS42L42 jack detect status.
-        */
-       switch (nid) {
-       case DOLPHIN_HP_PIN_NID:
-       case DOLPHIN_LO_PIN_NID:
-               if (nid == DOLPHIN_LO_PIN_NID)
-                       cs42l42 = spec->scodecs[CS8409_CODEC1];
-               if (verb == AC_VERB_GET_PIN_SENSE) {
-                       *res = (cs42l42->hp_jack_in) ? AC_PINSENSE_PRESENCE : 0;
-                       return 0;
-               }
-               break;
-       case DOLPHIN_AMIC_PIN_NID:
-               if (verb == AC_VERB_GET_PIN_SENSE) {
-                       *res = (cs42l42->mic_jack_in) ? AC_PINSENSE_PRESENCE : 0;
-                       return 0;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return spec->exec_verb(dev, cmd, flags, res);
-}
-
-void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action)
-{
-       struct cs8409_spec *spec = codec->spec;
-       struct snd_kcontrol_new *kctrl;
-       int i;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_add_verbs(codec, dolphin_init_verbs);
-               /* verb exec op override */
-               spec->exec_verb = codec->core.exec_verb;
-               codec->core.exec_verb = dolphin_exec_verb;
-
-               spec->scodecs[CS8409_CODEC0] = &dolphin_cs42l42_0;
-               spec->scodecs[CS8409_CODEC0]->codec = codec;
-               spec->scodecs[CS8409_CODEC1] = &dolphin_cs42l42_1;
-               spec->scodecs[CS8409_CODEC1]->codec = codec;
-               spec->num_scodecs = 2;
-               spec->gen.suppress_vmaster = 1;
-
-               codec->patch_ops = cs8409_dolphin_patch_ops;
-
-               /* GPIO 1,5 out, 0,4 in */
-               spec->gpio_dir = spec->scodecs[CS8409_CODEC0]->reset_gpio |
-                                spec->scodecs[CS8409_CODEC1]->reset_gpio;
-               spec->gpio_data = 0;
-               spec->gpio_mask = 0x03f;
-
-               /* Basic initial sequence for specific hw configuration */
-               snd_hda_sequence_write(codec, dolphin_init_verbs);
-
-               snd_hda_jack_add_kctl(codec, DOLPHIN_LO_PIN_NID, "Line Out", true,
-                                     SND_JACK_HEADPHONE, NULL);
-
-               snd_hda_jack_add_kctl(codec, DOLPHIN_AMIC_PIN_NID, "Microphone", true,
-                                     SND_JACK_MICROPHONE, NULL);
-
-               cs8409_fix_caps(codec, DOLPHIN_HP_PIN_NID);
-               cs8409_fix_caps(codec, DOLPHIN_LO_PIN_NID);
-               cs8409_fix_caps(codec, DOLPHIN_AMIC_PIN_NID);
-
-               spec->scodecs[CS8409_CODEC0]->full_scale_vol = CS42L42_FULL_SCALE_VOL_MINUS6DB;
-               spec->scodecs[CS8409_CODEC1]->full_scale_vol = CS42L42_FULL_SCALE_VOL_MINUS6DB;
-
-               break;
-       case HDA_FIXUP_ACT_PROBE:
-               /* Fix Sample Rate to 48kHz */
-               spec->gen.stream_analog_playback = &cs42l42_48k_pcm_analog_playback;
-               spec->gen.stream_analog_capture = &cs42l42_48k_pcm_analog_capture;
-               /* add hooks */
-               spec->gen.pcm_playback_hook = cs42l42_playback_pcm_hook;
-               spec->gen.pcm_capture_hook = cs42l42_capture_pcm_hook;
-               snd_hda_gen_add_kctl(&spec->gen, "Headphone Playback Volume",
-                                    &cs42l42_dac_volume_mixer);
-               snd_hda_gen_add_kctl(&spec->gen, "Mic Capture Volume", &cs42l42_adc_volume_mixer);
-               kctrl = snd_hda_gen_add_kctl(&spec->gen, "Line Out Playback Volume",
-                                            &cs42l42_dac_volume_mixer);
-               /* Update Line Out kcontrol template */
-               if (kctrl)
-                       kctrl->private_value = HDA_COMPOSE_AMP_VAL_OFS(DOLPHIN_HP_PIN_NID, 3, CS8409_CODEC1,
-                                              HDA_OUTPUT, CS42L42_VOL_DAC) | HDA_AMP_VAL_MIN_MUTE;
-               cs8409_enable_ur(codec, 0);
-               snd_hda_codec_set_name(codec, "CS8409/CS42L42");
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               dolphin_hw_init(codec);
-               spec->init_done = 1;
-               if (spec->init_done && spec->build_ctrl_done) {
-                       for (i = 0; i < spec->num_scodecs; i++) {
-                               if (!spec->scodecs[i]->hp_jack_in)
-                                       cs42l42_run_jack_detect(spec->scodecs[i]);
-                       }
-               }
-               break;
-       case HDA_FIXUP_ACT_BUILD:
-               spec->build_ctrl_done = 1;
-               /* Run jack auto detect first time on boot
-                * after controls have been added, to check if jack has
-                * been already plugged in.
-                * Run immediately after init.
-                */
-               if (spec->init_done && spec->build_ctrl_done) {
-                       for (i = 0; i < spec->num_scodecs; i++) {
-                               if (!spec->scodecs[i]->hp_jack_in)
-                                       cs42l42_run_jack_detect(spec->scodecs[i]);
-                       }
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-static int patch_cs8409(struct hda_codec *codec)
-{
-       int err;
-
-       if (!cs8409_alloc_spec(codec))
-               return -ENOMEM;
-
-       snd_hda_pick_fixup(codec, cs8409_models, cs8409_fixup_tbl, cs8409_fixups);
-
-       codec_dbg(codec, "Picked ID=%d, VID=%08x, DEV=%08x\n", codec->fixup_id,
-                        codec->bus->pci->subsystem_vendor,
-                        codec->bus->pci->subsystem_device);
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = cs8409_parse_auto_config(codec);
-       if (err < 0) {
-               cs8409_free(codec);
-               return err;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-       return 0;
-}
-
-static const struct hda_device_id snd_hda_id_cs8409[] = {
-       HDA_CODEC_ENTRY(0x10138409, "CS8409", patch_cs8409),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cs8409);
-
-static struct hda_codec_driver cs8409_driver = {
-       .id = snd_hda_id_cs8409,
-};
-module_hda_codec_driver(cs8409_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Cirrus Logic HDA bridge");
diff --git a/sound/pci/hda/patch_cs8409.h b/sound/pci/hda/patch_cs8409.h
deleted file mode 100644 (file)
index e4bd2e1..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- * HD audio interface patch for Cirrus Logic CS8409 HDA bridge chip
- *
- * Copyright (C) 2021 Cirrus Logic, Inc. and
- *                    Cirrus Logic International Semiconductor Ltd.
- */
-
-#ifndef __CS8409_PATCH_H
-#define __CS8409_PATCH_H
-
-#include <linux/pci.h>
-#include <sound/tlv.h>
-#include <linux/workqueue.h>
-#include <sound/cs42l42.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-/* CS8409 Specific Definitions */
-
-enum cs8409_pins {
-       CS8409_PIN_ROOT,
-       CS8409_PIN_AFG,
-       CS8409_PIN_ASP1_OUT_A,
-       CS8409_PIN_ASP1_OUT_B,
-       CS8409_PIN_ASP1_OUT_C,
-       CS8409_PIN_ASP1_OUT_D,
-       CS8409_PIN_ASP1_OUT_E,
-       CS8409_PIN_ASP1_OUT_F,
-       CS8409_PIN_ASP1_OUT_G,
-       CS8409_PIN_ASP1_OUT_H,
-       CS8409_PIN_ASP2_OUT_A,
-       CS8409_PIN_ASP2_OUT_B,
-       CS8409_PIN_ASP2_OUT_C,
-       CS8409_PIN_ASP2_OUT_D,
-       CS8409_PIN_ASP2_OUT_E,
-       CS8409_PIN_ASP2_OUT_F,
-       CS8409_PIN_ASP2_OUT_G,
-       CS8409_PIN_ASP2_OUT_H,
-       CS8409_PIN_ASP1_IN_A,
-       CS8409_PIN_ASP1_IN_B,
-       CS8409_PIN_ASP1_IN_C,
-       CS8409_PIN_ASP1_IN_D,
-       CS8409_PIN_ASP1_IN_E,
-       CS8409_PIN_ASP1_IN_F,
-       CS8409_PIN_ASP1_IN_G,
-       CS8409_PIN_ASP1_IN_H,
-       CS8409_PIN_ASP2_IN_A,
-       CS8409_PIN_ASP2_IN_B,
-       CS8409_PIN_ASP2_IN_C,
-       CS8409_PIN_ASP2_IN_D,
-       CS8409_PIN_ASP2_IN_E,
-       CS8409_PIN_ASP2_IN_F,
-       CS8409_PIN_ASP2_IN_G,
-       CS8409_PIN_ASP2_IN_H,
-       CS8409_PIN_DMIC1,
-       CS8409_PIN_DMIC2,
-       CS8409_PIN_ASP1_TRANSMITTER_A,
-       CS8409_PIN_ASP1_TRANSMITTER_B,
-       CS8409_PIN_ASP1_TRANSMITTER_C,
-       CS8409_PIN_ASP1_TRANSMITTER_D,
-       CS8409_PIN_ASP1_TRANSMITTER_E,
-       CS8409_PIN_ASP1_TRANSMITTER_F,
-       CS8409_PIN_ASP1_TRANSMITTER_G,
-       CS8409_PIN_ASP1_TRANSMITTER_H,
-       CS8409_PIN_ASP2_TRANSMITTER_A,
-       CS8409_PIN_ASP2_TRANSMITTER_B,
-       CS8409_PIN_ASP2_TRANSMITTER_C,
-       CS8409_PIN_ASP2_TRANSMITTER_D,
-       CS8409_PIN_ASP2_TRANSMITTER_E,
-       CS8409_PIN_ASP2_TRANSMITTER_F,
-       CS8409_PIN_ASP2_TRANSMITTER_G,
-       CS8409_PIN_ASP2_TRANSMITTER_H,
-       CS8409_PIN_ASP1_RECEIVER_A,
-       CS8409_PIN_ASP1_RECEIVER_B,
-       CS8409_PIN_ASP1_RECEIVER_C,
-       CS8409_PIN_ASP1_RECEIVER_D,
-       CS8409_PIN_ASP1_RECEIVER_E,
-       CS8409_PIN_ASP1_RECEIVER_F,
-       CS8409_PIN_ASP1_RECEIVER_G,
-       CS8409_PIN_ASP1_RECEIVER_H,
-       CS8409_PIN_ASP2_RECEIVER_A,
-       CS8409_PIN_ASP2_RECEIVER_B,
-       CS8409_PIN_ASP2_RECEIVER_C,
-       CS8409_PIN_ASP2_RECEIVER_D,
-       CS8409_PIN_ASP2_RECEIVER_E,
-       CS8409_PIN_ASP2_RECEIVER_F,
-       CS8409_PIN_ASP2_RECEIVER_G,
-       CS8409_PIN_ASP2_RECEIVER_H,
-       CS8409_PIN_DMIC1_IN,
-       CS8409_PIN_DMIC2_IN,
-       CS8409_PIN_BEEP_GEN,
-       CS8409_PIN_VENDOR_WIDGET
-};
-
-enum cs8409_coefficient_index_registers {
-       CS8409_DEV_CFG1,
-       CS8409_DEV_CFG2,
-       CS8409_DEV_CFG3,
-       CS8409_ASP1_CLK_CTRL1,
-       CS8409_ASP1_CLK_CTRL2,
-       CS8409_ASP1_CLK_CTRL3,
-       CS8409_ASP2_CLK_CTRL1,
-       CS8409_ASP2_CLK_CTRL2,
-       CS8409_ASP2_CLK_CTRL3,
-       CS8409_DMIC_CFG,
-       CS8409_BEEP_CFG,
-       ASP1_RX_NULL_INS_RMV,
-       ASP1_Rx_RATE1,
-       ASP1_Rx_RATE2,
-       ASP1_Tx_NULL_INS_RMV,
-       ASP1_Tx_RATE1,
-       ASP1_Tx_RATE2,
-       ASP2_Rx_NULL_INS_RMV,
-       ASP2_Rx_RATE1,
-       ASP2_Rx_RATE2,
-       ASP2_Tx_NULL_INS_RMV,
-       ASP2_Tx_RATE1,
-       ASP2_Tx_RATE2,
-       ASP1_SYNC_CTRL,
-       ASP2_SYNC_CTRL,
-       ASP1_A_TX_CTRL1,
-       ASP1_A_TX_CTRL2,
-       ASP1_B_TX_CTRL1,
-       ASP1_B_TX_CTRL2,
-       ASP1_C_TX_CTRL1,
-       ASP1_C_TX_CTRL2,
-       ASP1_D_TX_CTRL1,
-       ASP1_D_TX_CTRL2,
-       ASP1_E_TX_CTRL1,
-       ASP1_E_TX_CTRL2,
-       ASP1_F_TX_CTRL1,
-       ASP1_F_TX_CTRL2,
-       ASP1_G_TX_CTRL1,
-       ASP1_G_TX_CTRL2,
-       ASP1_H_TX_CTRL1,
-       ASP1_H_TX_CTRL2,
-       ASP2_A_TX_CTRL1,
-       ASP2_A_TX_CTRL2,
-       ASP2_B_TX_CTRL1,
-       ASP2_B_TX_CTRL2,
-       ASP2_C_TX_CTRL1,
-       ASP2_C_TX_CTRL2,
-       ASP2_D_TX_CTRL1,
-       ASP2_D_TX_CTRL2,
-       ASP2_E_TX_CTRL1,
-       ASP2_E_TX_CTRL2,
-       ASP2_F_TX_CTRL1,
-       ASP2_F_TX_CTRL2,
-       ASP2_G_TX_CTRL1,
-       ASP2_G_TX_CTRL2,
-       ASP2_H_TX_CTRL1,
-       ASP2_H_TX_CTRL2,
-       ASP1_A_RX_CTRL1,
-       ASP1_A_RX_CTRL2,
-       ASP1_B_RX_CTRL1,
-       ASP1_B_RX_CTRL2,
-       ASP1_C_RX_CTRL1,
-       ASP1_C_RX_CTRL2,
-       ASP1_D_RX_CTRL1,
-       ASP1_D_RX_CTRL2,
-       ASP1_E_RX_CTRL1,
-       ASP1_E_RX_CTRL2,
-       ASP1_F_RX_CTRL1,
-       ASP1_F_RX_CTRL2,
-       ASP1_G_RX_CTRL1,
-       ASP1_G_RX_CTRL2,
-       ASP1_H_RX_CTRL1,
-       ASP1_H_RX_CTRL2,
-       ASP2_A_RX_CTRL1,
-       ASP2_A_RX_CTRL2,
-       ASP2_B_RX_CTRL1,
-       ASP2_B_RX_CTRL2,
-       ASP2_C_RX_CTRL1,
-       ASP2_C_RX_CTRL2,
-       ASP2_D_RX_CTRL1,
-       ASP2_D_RX_CTRL2,
-       ASP2_E_RX_CTRL1,
-       ASP2_E_RX_CTRL2,
-       ASP2_F_RX_CTRL1,
-       ASP2_F_RX_CTRL2,
-       ASP2_G_RX_CTRL1,
-       ASP2_G_RX_CTRL2,
-       ASP2_H_RX_CTRL1,
-       ASP2_H_RX_CTRL2,
-       CS8409_I2C_ADDR,
-       CS8409_I2C_DATA,
-       CS8409_I2C_CTRL,
-       CS8409_I2C_STS,
-       CS8409_I2C_QWRITE,
-       CS8409_I2C_QREAD,
-       CS8409_SPI_CTRL,
-       CS8409_SPI_TX_DATA,
-       CS8409_SPI_RX_DATA,
-       CS8409_SPI_STS,
-       CS8409_PFE_COEF_W1, /* Parametric filter engine coefficient write 1*/
-       CS8409_PFE_COEF_W2,
-       CS8409_PFE_CTRL1,
-       CS8409_PFE_CTRL2,
-       CS8409_PRE_SCALE_ATTN1,
-       CS8409_PRE_SCALE_ATTN2,
-       CS8409_PFE_COEF_MON1, /* Parametric filter engine coefficient monitor 1*/
-       CS8409_PFE_COEF_MON2,
-       CS8409_ASP1_INTRN_STS,
-       CS8409_ASP2_INTRN_STS,
-       CS8409_ASP1_RX_SCLK_COUNT,
-       CS8409_ASP1_TX_SCLK_COUNT,
-       CS8409_ASP2_RX_SCLK_COUNT,
-       CS8409_ASP2_TX_SCLK_COUNT,
-       CS8409_ASP_UNS_RESP_MASK,
-       CS8409_LOOPBACK_CTRL = 0x80,
-       CS8409_PAD_CFG_SLW_RATE_CTRL = 0x82, /* Pad Config and Slew Rate Control (CIR = 0x0082) */
-};
-
-/* CS42L42 Specific Definitions */
-
-#define CS8409_MAX_CODECS                      8
-#define CS42L42_VOLUMES                                (4U)
-#define CS42L42_HP_VOL_REAL_MIN                        (-63)
-#define CS42L42_HP_VOL_REAL_MAX                        (0)
-#define CS42L42_AMIC_VOL_REAL_MIN              (-97)
-#define CS42L42_AMIC_VOL_REAL_MAX              (12)
-#define CS42L42_REG_AMIC_VOL_MASK              (0x00FF)
-#define CS42L42_HSTYPE_MASK                    (0x03)
-#define CS42L42_I2C_TIMEOUT_US                 (20000)
-#define CS42L42_I2C_SLEEP_US                   (2000)
-#define CS42L42_PDN_TIMEOUT_US                 (250000)
-#define CS42L42_PDN_SLEEP_US                   (2000)
-#define CS42L42_ANA_MUTE_AB                    (0x0C)
-#define CS42L42_FULL_SCALE_VOL_MASK            (2)
-#define CS42L42_FULL_SCALE_VOL_0DB             (0)
-#define CS42L42_FULL_SCALE_VOL_MINUS6DB                (1)
-
-/* Dell BULLSEYE / WARLOCK / CYBORG Specific Definitions */
-
-#define CS42L42_I2C_ADDR                       (0x48 << 1)
-#define CS8409_CS42L42_RESET                   GENMASK(5, 5) /* CS8409_GPIO5 */
-#define CS8409_CS42L42_INT                     GENMASK(4, 4) /* CS8409_GPIO4 */
-#define CS8409_CYBORG_SPEAKER_PDN              GENMASK(2, 2) /* CS8409_GPIO2 */
-#define CS8409_WARLOCK_SPEAKER_PDN             GENMASK(1, 1) /* CS8409_GPIO1 */
-#define CS8409_CS42L42_HP_PIN_NID              CS8409_PIN_ASP1_TRANSMITTER_A
-#define CS8409_CS42L42_SPK_PIN_NID             CS8409_PIN_ASP2_TRANSMITTER_A
-#define CS8409_CS42L42_AMIC_PIN_NID            CS8409_PIN_ASP1_RECEIVER_A
-#define CS8409_CS42L42_DMIC_PIN_NID            CS8409_PIN_DMIC1_IN
-#define CS8409_CS42L42_DMIC_ADC_PIN_NID                CS8409_PIN_DMIC1
-
-/* Dolphin */
-
-#define DOLPHIN_C0_I2C_ADDR                    (0x48 << 1)
-#define DOLPHIN_C1_I2C_ADDR                    (0x49 << 1)
-#define DOLPHIN_HP_PIN_NID                     CS8409_PIN_ASP1_TRANSMITTER_A
-#define DOLPHIN_LO_PIN_NID                     CS8409_PIN_ASP1_TRANSMITTER_B
-#define DOLPHIN_AMIC_PIN_NID                   CS8409_PIN_ASP1_RECEIVER_A
-
-#define DOLPHIN_C0_INT                         GENMASK(4, 4)
-#define DOLPHIN_C1_INT                         GENMASK(0, 0)
-#define DOLPHIN_C0_RESET                       GENMASK(5, 5)
-#define DOLPHIN_C1_RESET                       GENMASK(1, 1)
-#define DOLPHIN_WAKE                           (DOLPHIN_C0_INT | DOLPHIN_C1_INT)
-
-enum {
-       CS8409_BULLSEYE,
-       CS8409_WARLOCK,
-       CS8409_WARLOCK_MLK,
-       CS8409_WARLOCK_MLK_DUAL_MIC,
-       CS8409_CYBORG,
-       CS8409_FIXUPS,
-       CS8409_DOLPHIN,
-       CS8409_DOLPHIN_FIXUPS,
-       CS8409_ODIN,
-};
-
-enum {
-       CS8409_CODEC0,
-       CS8409_CODEC1
-};
-
-enum {
-       CS42L42_VOL_ADC,
-       CS42L42_VOL_DAC,
-};
-
-#define CS42L42_ADC_VOL_OFFSET                 (CS42L42_VOL_ADC)
-#define CS42L42_DAC_CH0_VOL_OFFSET             (CS42L42_VOL_DAC)
-#define CS42L42_DAC_CH1_VOL_OFFSET             (CS42L42_VOL_DAC + 1)
-
-struct cs8409_i2c_param {
-       unsigned int addr;
-       unsigned int value;
-       unsigned int delay;
-};
-
-struct cs8409_cir_param {
-       unsigned int nid;
-       unsigned int cir;
-       unsigned int coeff;
-};
-
-struct sub_codec {
-       struct hda_codec *codec;
-       unsigned int addr;
-       unsigned int reset_gpio;
-       unsigned int irq_mask;
-       const struct cs8409_i2c_param *init_seq;
-       unsigned int init_seq_num;
-
-       unsigned int hp_jack_in:1;
-       unsigned int mic_jack_in:1;
-       unsigned int suspended:1;
-       unsigned int paged:1;
-       unsigned int last_page;
-       unsigned int hsbias_hiz;
-       unsigned int full_scale_vol:1;
-       unsigned int no_type_dect:1;
-
-       s8 vol[CS42L42_VOLUMES];
-};
-
-struct cs8409_spec {
-       struct hda_gen_spec gen;
-       struct hda_codec *codec;
-
-       struct sub_codec *scodecs[CS8409_MAX_CODECS];
-       unsigned int num_scodecs;
-
-       unsigned int gpio_mask;
-       unsigned int gpio_dir;
-       unsigned int gpio_data;
-
-       int speaker_pdn_gpio;
-
-       struct mutex i2c_mux;
-       unsigned int i2c_clck_enabled;
-       unsigned int dev_addr;
-       struct delayed_work i2c_clk_work;
-
-       unsigned int playback_started:1;
-       unsigned int capture_started:1;
-       unsigned int init_done:1;
-       unsigned int build_ctrl_done:1;
-
-       /* verb exec op override */
-       int (*exec_verb)(struct hdac_device *dev, unsigned int cmd, unsigned int flags,
-                        unsigned int *res);
-};
-
-extern const struct snd_kcontrol_new cs42l42_dac_volume_mixer;
-extern const struct snd_kcontrol_new cs42l42_adc_volume_mixer;
-
-int cs42l42_volume_info(struct snd_kcontrol *kctrl, struct snd_ctl_elem_info *uinfo);
-int cs42l42_volume_get(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl);
-int cs42l42_volume_put(struct snd_kcontrol *kctrl, struct snd_ctl_elem_value *uctrl);
-
-extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_playback;
-extern const struct hda_pcm_stream cs42l42_48k_pcm_analog_capture;
-extern const struct hda_quirk cs8409_fixup_tbl[];
-extern const struct hda_model_fixup cs8409_models[];
-extern const struct hda_fixup cs8409_fixups[];
-extern const struct hda_verb cs8409_cs42l42_init_verbs[];
-extern const struct cs8409_cir_param cs8409_cs42l42_hw_cfg[];
-extern const struct cs8409_cir_param cs8409_cs42l42_bullseye_atn[];
-extern struct sub_codec cs8409_cs42l42_codec;
-
-extern const struct hda_verb dolphin_init_verbs[];
-extern const struct cs8409_cir_param dolphin_hw_cfg[];
-extern struct sub_codec dolphin_cs42l42_0;
-extern struct sub_codec dolphin_cs42l42_1;
-
-void cs8409_cs42l42_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
-void dolphin_fixups(struct hda_codec *codec, const struct hda_fixup *fix, int action);
-
-#endif
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
deleted file mode 100644 (file)
index 9a7793e..0000000
+++ /dev/null
@@ -1,4695 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- *  patch_hdmi.c - routines for HDMI/DisplayPort codecs
- *
- *  Copyright(c) 2008-2010 Intel Corporation
- *  Copyright (c) 2006 ATI Technologies Inc.
- *  Copyright (c) 2008 NVIDIA Corp.  All rights reserved.
- *  Copyright (c) 2008 Wei Ni <wni@nvidia.com>
- *  Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi>
- *
- *  Authors:
- *                     Wu Fengguang <wfg@linux.intel.com>
- *
- *  Maintained by:
- *                     Wu Fengguang <wfg@linux.intel.com>
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/pm_runtime.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/asoundef.h>
-#include <sound/tlv.h>
-#include <sound/hdaudio.h>
-#include <sound/hda_i915.h>
-#include <sound/hda_chmap.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_jack.h"
-#include "hda_controller.h"
-
-static bool static_hdmi_pcm;
-module_param(static_hdmi_pcm, bool, 0644);
-MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info");
-
-static bool enable_acomp = true;
-module_param(enable_acomp, bool, 0444);
-MODULE_PARM_DESC(enable_acomp, "Enable audio component binding (default=yes)");
-
-static bool enable_silent_stream =
-IS_ENABLED(CONFIG_SND_HDA_INTEL_HDMI_SILENT_STREAM);
-module_param(enable_silent_stream, bool, 0644);
-MODULE_PARM_DESC(enable_silent_stream, "Enable Silent Stream for HDMI devices");
-
-static bool enable_all_pins;
-module_param(enable_all_pins, bool, 0444);
-MODULE_PARM_DESC(enable_all_pins, "Forcibly enable all pins");
-
-struct hdmi_spec_per_cvt {
-       hda_nid_t cvt_nid;
-       bool assigned;          /* the stream has been assigned */
-       bool silent_stream;     /* silent stream activated */
-       unsigned int channels_min;
-       unsigned int channels_max;
-       u32 rates;
-       u64 formats;
-       unsigned int maxbps;
-};
-
-/* max. connections to a widget */
-#define HDA_MAX_CONNECTIONS    32
-
-struct hdmi_spec_per_pin {
-       hda_nid_t pin_nid;
-       int dev_id;
-       /* pin idx, different device entries on the same pin use the same idx */
-       int pin_nid_idx;
-       int num_mux_nids;
-       hda_nid_t mux_nids[HDA_MAX_CONNECTIONS];
-       int mux_idx;
-       hda_nid_t cvt_nid;
-
-       struct hda_codec *codec;
-       struct hdmi_eld sink_eld;
-       struct mutex lock;
-       struct delayed_work work;
-       struct hdmi_pcm *pcm; /* pointer to spec->pcm_rec[n] dynamically*/
-       int pcm_idx; /* which pcm is attached. -1 means no pcm is attached */
-       int prev_pcm_idx; /* previously assigned pcm index */
-       int repoll_count;
-       bool setup; /* the stream has been set up by prepare callback */
-       bool silent_stream;
-       int channels; /* current number of channels */
-       bool non_pcm;
-       bool chmap_set;         /* channel-map override by ALSA API? */
-       unsigned char chmap[8]; /* ALSA API channel-map */
-#ifdef CONFIG_SND_PROC_FS
-       struct snd_info_entry *proc_entry;
-#endif
-};
-
-/* operations used by generic code that can be overridden by patches */
-struct hdmi_ops {
-       int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid,
-                          int dev_id, unsigned char *buf, int *eld_size);
-
-       void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid,
-                                   int dev_id,
-                                   int ca, int active_channels, int conn_type);
-
-       /* enable/disable HBR (HD passthrough) */
-       int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid,
-                            int dev_id, bool hbr);
-
-       int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid,
-                           hda_nid_t pin_nid, int dev_id, u32 stream_tag,
-                           int format);
-
-       void (*pin_cvt_fixup)(struct hda_codec *codec,
-                             struct hdmi_spec_per_pin *per_pin,
-                             hda_nid_t cvt_nid);
-};
-
-struct hdmi_pcm {
-       struct hda_pcm *pcm;
-       struct snd_jack *jack;
-       struct snd_kcontrol *eld_ctl;
-};
-
-enum {
-       SILENT_STREAM_OFF = 0,
-       SILENT_STREAM_KAE,      /* use standard HDA Keep-Alive */
-       SILENT_STREAM_I915,     /* Intel i915 extension */
-};
-
-struct hdmi_spec {
-       struct hda_codec *codec;
-       int num_cvts;
-       struct snd_array cvts; /* struct hdmi_spec_per_cvt */
-       hda_nid_t cvt_nids[4]; /* only for haswell fix */
-
-       /*
-        * num_pins is the number of virtual pins
-        * for example, there are 3 pins, and each pin
-        * has 4 device entries, then the num_pins is 12
-        */
-       int num_pins;
-       /*
-        * num_nids is the number of real pins
-        * In the above example, num_nids is 3
-        */
-       int num_nids;
-       /*
-        * dev_num is the number of device entries
-        * on each pin.
-        * In the above example, dev_num is 4
-        */
-       int dev_num;
-       struct snd_array pins; /* struct hdmi_spec_per_pin */
-       struct hdmi_pcm pcm_rec[8];
-       struct mutex pcm_lock;
-       struct mutex bind_lock; /* for audio component binding */
-       /* pcm_bitmap means which pcms have been assigned to pins*/
-       unsigned long pcm_bitmap;
-       int pcm_used;   /* counter of pcm_rec[] */
-       /* bitmap shows whether the pcm is opened in user space
-        * bit 0 means the first playback PCM (PCM3);
-        * bit 1 means the second playback PCM, and so on.
-        */
-       unsigned long pcm_in_use;
-
-       struct hdmi_eld temp_eld;
-       struct hdmi_ops ops;
-
-       bool dyn_pin_out;
-       bool static_pcm_mapping;
-       /* hdmi interrupt trigger control flag for Nvidia codec */
-       bool hdmi_intr_trig_ctrl;
-       bool nv_dp_workaround; /* workaround DP audio infoframe for Nvidia */
-
-       bool intel_hsw_fixup;   /* apply Intel platform-specific fixups */
-       /*
-        * Non-generic VIA/NVIDIA specific
-        */
-       struct hda_multi_out multiout;
-       struct hda_pcm_stream pcm_playback;
-
-       bool use_acomp_notifier; /* use eld_notify callback for hotplug */
-       bool acomp_registered; /* audio component registered in this driver */
-       bool force_connect; /* force connectivity */
-       struct drm_audio_component_audio_ops drm_audio_ops;
-       int (*port2pin)(struct hda_codec *, int); /* reverse port/pin mapping */
-
-       struct hdac_chmap chmap;
-       hda_nid_t vendor_nid;
-       const int *port_map;
-       int port_num;
-       int silent_stream_type;
-};
-
-#ifdef CONFIG_SND_HDA_COMPONENT
-static inline bool codec_has_acomp(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return spec->use_acomp_notifier;
-}
-#else
-#define codec_has_acomp(codec) false
-#endif
-
-struct hdmi_audio_infoframe {
-       u8 type; /* 0x84 */
-       u8 ver;  /* 0x01 */
-       u8 len;  /* 0x0a */
-
-       u8 checksum;
-
-       u8 CC02_CT47;   /* CC in bits 0:2, CT in 4:7 */
-       u8 SS01_SF24;
-       u8 CXT04;
-       u8 CA;
-       u8 LFEPBL01_LSV36_DM_INH7;
-};
-
-struct dp_audio_infoframe {
-       u8 type; /* 0x84 */
-       u8 len;  /* 0x1b */
-       u8 ver;  /* 0x11 << 2 */
-
-       u8 CC02_CT47;   /* match with HDMI infoframe from this on */
-       u8 SS01_SF24;
-       u8 CXT04;
-       u8 CA;
-       u8 LFEPBL01_LSV36_DM_INH7;
-};
-
-union audio_infoframe {
-       struct hdmi_audio_infoframe hdmi;
-       struct dp_audio_infoframe dp;
-       DECLARE_FLEX_ARRAY(u8, bytes);
-};
-
-/*
- * HDMI routines
- */
-
-#define get_pin(spec, idx) \
-       ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx))
-#define get_cvt(spec, idx) \
-       ((struct hdmi_spec_per_cvt  *)snd_array_elem(&spec->cvts, idx))
-/* obtain hdmi_pcm object assigned to idx */
-#define get_hdmi_pcm(spec, idx)        (&(spec)->pcm_rec[idx])
-/* obtain hda_pcm object assigned to idx */
-#define get_pcm_rec(spec, idx) (get_hdmi_pcm(spec, idx)->pcm)
-
-static int pin_id_to_pin_index(struct hda_codec *codec,
-                              hda_nid_t pin_nid, int dev_id)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx;
-       struct hdmi_spec_per_pin *per_pin;
-
-       /*
-        * (dev_id == -1) means it is NON-MST pin
-        * return the first virtual pin on this port
-        */
-       if (dev_id == -1)
-               dev_id = 0;
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               per_pin = get_pin(spec, pin_idx);
-               if ((per_pin->pin_nid == pin_nid) &&
-                       (per_pin->dev_id == dev_id))
-                       return pin_idx;
-       }
-
-       codec_warn(codec, "HDMI: pin NID 0x%x not registered\n", pin_nid);
-       return -EINVAL;
-}
-
-static int hinfo_to_pcm_index(struct hda_codec *codec,
-                       struct hda_pcm_stream *hinfo)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pcm_idx;
-
-       for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++)
-               if (get_pcm_rec(spec, pcm_idx)->stream == hinfo)
-                       return pcm_idx;
-
-       codec_warn(codec, "HDMI: hinfo %p not tied to a PCM\n", hinfo);
-       return -EINVAL;
-}
-
-static int hinfo_to_pin_index(struct hda_codec *codec,
-                             struct hda_pcm_stream *hinfo)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin;
-       int pin_idx;
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               per_pin = get_pin(spec, pin_idx);
-               if (per_pin->pcm &&
-                       per_pin->pcm->pcm->stream == hinfo)
-                       return pin_idx;
-       }
-
-       codec_dbg(codec, "HDMI: hinfo %p (pcm %d) not registered\n", hinfo,
-                 hinfo_to_pcm_index(codec, hinfo));
-       return -EINVAL;
-}
-
-static struct hdmi_spec_per_pin *pcm_idx_to_pin(struct hdmi_spec *spec,
-                                               int pcm_idx)
-{
-       int i;
-       struct hdmi_spec_per_pin *per_pin;
-
-       for (i = 0; i < spec->num_pins; i++) {
-               per_pin = get_pin(spec, i);
-               if (per_pin->pcm_idx == pcm_idx)
-                       return per_pin;
-       }
-       return NULL;
-}
-
-static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int cvt_idx;
-
-       for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++)
-               if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid)
-                       return cvt_idx;
-
-       codec_warn(codec, "HDMI: cvt NID 0x%x not registered\n", cvt_nid);
-       return -EINVAL;
-}
-
-static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin;
-       struct hdmi_eld *eld;
-       int pcm_idx;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
-
-       pcm_idx = kcontrol->private_value;
-       mutex_lock(&spec->pcm_lock);
-       per_pin = pcm_idx_to_pin(spec, pcm_idx);
-       if (!per_pin) {
-               /* no pin is bound to the pcm */
-               uinfo->count = 0;
-               goto unlock;
-       }
-       eld = &per_pin->sink_eld;
-       uinfo->count = eld->eld_valid ? eld->eld_size : 0;
-
- unlock:
-       mutex_unlock(&spec->pcm_lock);
-       return 0;
-}
-
-static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin;
-       struct hdmi_eld *eld;
-       int pcm_idx;
-       int err = 0;
-
-       pcm_idx = kcontrol->private_value;
-       mutex_lock(&spec->pcm_lock);
-       per_pin = pcm_idx_to_pin(spec, pcm_idx);
-       if (!per_pin) {
-               /* no pin is bound to the pcm */
-               memset(ucontrol->value.bytes.data, 0,
-                      ARRAY_SIZE(ucontrol->value.bytes.data));
-               goto unlock;
-       }
-
-       eld = &per_pin->sink_eld;
-       if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
-           eld->eld_size > ELD_MAX_SIZE) {
-               snd_BUG();
-               err = -EINVAL;
-               goto unlock;
-       }
-
-       memset(ucontrol->value.bytes.data, 0,
-              ARRAY_SIZE(ucontrol->value.bytes.data));
-       if (eld->eld_valid)
-               memcpy(ucontrol->value.bytes.data, eld->eld_buffer,
-                      eld->eld_size);
-
- unlock:
-       mutex_unlock(&spec->pcm_lock);
-       return err;
-}
-
-static const struct snd_kcontrol_new eld_bytes_ctl = {
-       .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE |
-               SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK,
-       .iface = SNDRV_CTL_ELEM_IFACE_PCM,
-       .name = "ELD",
-       .info = hdmi_eld_ctl_info,
-       .get = hdmi_eld_ctl_get,
-};
-
-static int hdmi_create_eld_ctl(struct hda_codec *codec, int pcm_idx,
-                       int device)
-{
-       struct snd_kcontrol *kctl;
-       struct hdmi_spec *spec = codec->spec;
-       int err;
-
-       kctl = snd_ctl_new1(&eld_bytes_ctl, codec);
-       if (!kctl)
-               return -ENOMEM;
-       kctl->private_value = pcm_idx;
-       kctl->id.device = device;
-
-       /* no pin nid is associated with the kctl now
-        * tbd: associate pin nid to eld ctl later
-        */
-       err = snd_hda_ctl_add(codec, 0, kctl);
-       if (err < 0)
-               return err;
-
-       get_hdmi_pcm(spec, pcm_idx)->eld_ctl = kctl;
-       return 0;
-}
-
-#ifdef BE_PARANOID
-static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
-                               int *packet_index, int *byte_index)
-{
-       int val;
-
-       val = snd_hda_codec_read(codec, pin_nid, 0,
-                                AC_VERB_GET_HDMI_DIP_INDEX, 0);
-
-       *packet_index = val >> 5;
-       *byte_index = val & 0x1f;
-}
-#endif
-
-static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid,
-                               int packet_index, int byte_index)
-{
-       int val;
-
-       val = (packet_index << 5) | (byte_index & 0x1f);
-
-       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val);
-}
-
-static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
-                               unsigned char val)
-{
-       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val);
-}
-
-static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_out;
-
-       /* Unmute */
-       if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
-               snd_hda_codec_write(codec, pin_nid, 0,
-                               AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-
-       if (spec->dyn_pin_out)
-               /* Disable pin out until stream is active */
-               pin_out = 0;
-       else
-               /* Enable pin out: some machines with GM965 gets broken output
-                * when the pin is disabled or changed while using with HDMI
-                */
-               pin_out = PIN_OUT;
-
-       snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
-}
-
-/*
- * ELD proc files
- */
-
-#ifdef CONFIG_SND_PROC_FS
-static void print_eld_info(struct snd_info_entry *entry,
-                          struct snd_info_buffer *buffer)
-{
-       struct hdmi_spec_per_pin *per_pin = entry->private_data;
-
-       mutex_lock(&per_pin->lock);
-       snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer, per_pin->pin_nid,
-                               per_pin->dev_id, per_pin->cvt_nid);
-       mutex_unlock(&per_pin->lock);
-}
-
-static void write_eld_info(struct snd_info_entry *entry,
-                          struct snd_info_buffer *buffer)
-{
-       struct hdmi_spec_per_pin *per_pin = entry->private_data;
-
-       mutex_lock(&per_pin->lock);
-       snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer);
-       mutex_unlock(&per_pin->lock);
-}
-
-static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index)
-{
-       char name[32];
-       struct hda_codec *codec = per_pin->codec;
-       struct snd_info_entry *entry;
-       int err;
-
-       snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index);
-       err = snd_card_proc_new(codec->card, name, &entry);
-       if (err < 0)
-               return err;
-
-       snd_info_set_text_ops(entry, per_pin, print_eld_info);
-       entry->c.text.write = write_eld_info;
-       entry->mode |= 0200;
-       per_pin->proc_entry = entry;
-
-       return 0;
-}
-
-static void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
-{
-       if (!per_pin->codec->bus->shutdown) {
-               snd_info_free_entry(per_pin->proc_entry);
-               per_pin->proc_entry = NULL;
-       }
-}
-#else
-static inline int eld_proc_new(struct hdmi_spec_per_pin *per_pin,
-                              int index)
-{
-       return 0;
-}
-static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin)
-{
-}
-#endif
-
-/*
- * Audio InfoFrame routines
- */
-
-/*
- * Enable Audio InfoFrame Transmission
- */
-static void hdmi_start_infoframe_trans(struct hda_codec *codec,
-                                      hda_nid_t pin_nid)
-{
-       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
-                                               AC_DIPXMIT_BEST);
-}
-
-/*
- * Disable Audio InfoFrame Transmission
- */
-static void hdmi_stop_infoframe_trans(struct hda_codec *codec,
-                                     hda_nid_t pin_nid)
-{
-       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT,
-                                               AC_DIPXMIT_DISABLE);
-}
-
-static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-#ifdef CONFIG_SND_DEBUG_VERBOSE
-       int i;
-       int size;
-
-       size = snd_hdmi_get_eld_size(codec, pin_nid);
-       codec_dbg(codec, "HDMI: ELD buf size is %d\n", size);
-
-       for (i = 0; i < 8; i++) {
-               size = snd_hda_codec_read(codec, pin_nid, 0,
-                                               AC_VERB_GET_HDMI_DIP_SIZE, i);
-               codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size);
-       }
-#endif
-}
-
-static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-#ifdef BE_PARANOID
-       int i, j;
-       int size;
-       int pi, bi;
-       for (i = 0; i < 8; i++) {
-               size = snd_hda_codec_read(codec, pin_nid, 0,
-                                               AC_VERB_GET_HDMI_DIP_SIZE, i);
-               if (size == 0)
-                       continue;
-
-               hdmi_set_dip_index(codec, pin_nid, i, 0x0);
-               for (j = 1; j < 1000; j++) {
-                       hdmi_write_dip_byte(codec, pin_nid, 0x0);
-                       hdmi_get_dip_index(codec, pin_nid, &pi, &bi);
-                       if (pi != i)
-                               codec_dbg(codec, "dip index %d: %d != %d\n",
-                                               bi, pi, i);
-                       if (bi == 0) /* byte index wrapped around */
-                               break;
-               }
-               codec_dbg(codec,
-                       "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n",
-                       i, size, j);
-       }
-#endif
-}
-
-static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *hdmi_ai)
-{
-       u8 *bytes = (u8 *)hdmi_ai;
-       u8 sum = 0;
-       int i;
-
-       hdmi_ai->checksum = 0;
-
-       for (i = 0; i < sizeof(*hdmi_ai); i++)
-               sum += bytes[i];
-
-       hdmi_ai->checksum = -sum;
-}
-
-static void hdmi_fill_audio_infoframe(struct hda_codec *codec,
-                                     hda_nid_t pin_nid,
-                                     u8 *dip, int size)
-{
-       int i;
-
-       hdmi_debug_dip_size(codec, pin_nid);
-       hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */
-
-       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       for (i = 0; i < size; i++)
-               hdmi_write_dip_byte(codec, pin_nid, dip[i]);
-}
-
-static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid,
-                                   u8 *dip, int size)
-{
-       u8 val;
-       int i;
-
-       hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0);
-       if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0)
-                                                           != AC_DIPXMIT_BEST)
-               return false;
-
-       for (i = 0; i < size; i++) {
-               val = snd_hda_codec_read(codec, pin_nid, 0,
-                                        AC_VERB_GET_HDMI_DIP_DATA, 0);
-               if (val != dip[i])
-                       return false;
-       }
-
-       return true;
-}
-
-static int hdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
-                           int dev_id, unsigned char *buf, int *eld_size)
-{
-       snd_hda_set_dev_select(codec, nid, dev_id);
-
-       return snd_hdmi_get_eld(codec, nid, buf, eld_size);
-}
-
-static void hdmi_pin_setup_infoframe(struct hda_codec *codec,
-                                    hda_nid_t pin_nid, int dev_id,
-                                    int ca, int active_channels,
-                                    int conn_type)
-{
-       struct hdmi_spec *spec = codec->spec;
-       union audio_infoframe ai;
-
-       memset(&ai, 0, sizeof(ai));
-       if ((conn_type == 0) || /* HDMI */
-               /* Nvidia DisplayPort: Nvidia HW expects same layout as HDMI */
-               (conn_type == 1 && spec->nv_dp_workaround)) {
-               struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi;
-
-               if (conn_type == 0) { /* HDMI */
-                       hdmi_ai->type           = 0x84;
-                       hdmi_ai->ver            = 0x01;
-                       hdmi_ai->len            = 0x0a;
-               } else {/* Nvidia DP */
-                       hdmi_ai->type           = 0x84;
-                       hdmi_ai->ver            = 0x1b;
-                       hdmi_ai->len            = 0x11 << 2;
-               }
-               hdmi_ai->CC02_CT47      = active_channels - 1;
-               hdmi_ai->CA             = ca;
-               hdmi_checksum_audio_infoframe(hdmi_ai);
-       } else if (conn_type == 1) { /* DisplayPort */
-               struct dp_audio_infoframe *dp_ai = &ai.dp;
-
-               dp_ai->type             = 0x84;
-               dp_ai->len              = 0x1b;
-               dp_ai->ver              = 0x11 << 2;
-               dp_ai->CC02_CT47        = active_channels - 1;
-               dp_ai->CA               = ca;
-       } else {
-               codec_dbg(codec, "HDMI: unknown connection type at pin NID 0x%x\n", pin_nid);
-               return;
-       }
-
-       snd_hda_set_dev_select(codec, pin_nid, dev_id);
-
-       /*
-        * sizeof(ai) is used instead of sizeof(*hdmi_ai) or
-        * sizeof(*dp_ai) to avoid partial match/update problems when
-        * the user switches between HDMI/DP monitors.
-        */
-       if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes,
-                                       sizeof(ai))) {
-               codec_dbg(codec, "%s: pin NID=0x%x channels=%d ca=0x%02x\n",
-                         __func__, pin_nid, active_channels, ca);
-               hdmi_stop_infoframe_trans(codec, pin_nid);
-               hdmi_fill_audio_infoframe(codec, pin_nid,
-                                           ai.bytes, sizeof(ai));
-               hdmi_start_infoframe_trans(codec, pin_nid);
-       }
-}
-
-static void hdmi_setup_audio_infoframe(struct hda_codec *codec,
-                                      struct hdmi_spec_per_pin *per_pin,
-                                      bool non_pcm)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdac_chmap *chmap = &spec->chmap;
-       hda_nid_t pin_nid = per_pin->pin_nid;
-       int dev_id = per_pin->dev_id;
-       int channels = per_pin->channels;
-       int active_channels;
-       struct hdmi_eld *eld;
-       int ca;
-
-       if (!channels)
-               return;
-
-       snd_hda_set_dev_select(codec, pin_nid, dev_id);
-
-       /* some HW (e.g. HSW+) needs reprogramming the amp at each time */
-       if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
-               snd_hda_codec_write(codec, pin_nid, 0,
-                                           AC_VERB_SET_AMP_GAIN_MUTE,
-                                           AMP_OUT_UNMUTE);
-
-       eld = &per_pin->sink_eld;
-
-       ca = snd_hdac_channel_allocation(&codec->core,
-                       eld->info.spk_alloc, channels,
-                       per_pin->chmap_set, non_pcm, per_pin->chmap);
-
-       active_channels = snd_hdac_get_active_channels(ca);
-
-       chmap->ops.set_channel_count(&codec->core, per_pin->cvt_nid,
-                                               active_channels);
-
-       /*
-        * always configure channel mapping, it may have been changed by the
-        * user in the meantime
-        */
-       snd_hdac_setup_channel_mapping(&spec->chmap,
-                               pin_nid, non_pcm, ca, channels,
-                               per_pin->chmap, per_pin->chmap_set);
-
-       spec->ops.pin_setup_infoframe(codec, pin_nid, dev_id,
-                                     ca, active_channels, eld->info.conn_type);
-
-       per_pin->non_pcm = non_pcm;
-}
-
-/*
- * Unsolicited events
- */
-
-static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll);
-
-static void check_presence_and_report(struct hda_codec *codec, hda_nid_t nid,
-                                     int dev_id)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx = pin_id_to_pin_index(codec, nid, dev_id);
-
-       if (pin_idx < 0)
-               return;
-       mutex_lock(&spec->pcm_lock);
-       hdmi_present_sense(get_pin(spec, pin_idx), 1);
-       mutex_unlock(&spec->pcm_lock);
-}
-
-static void jack_callback(struct hda_codec *codec,
-                         struct hda_jack_callback *jack)
-{
-       /* stop polling when notification is enabled */
-       if (codec_has_acomp(codec))
-               return;
-
-       check_presence_and_report(codec, jack->nid, jack->dev_id);
-}
-
-static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res,
-                                struct hda_jack_tbl *jack)
-{
-       jack->jack_dirty = 1;
-
-       codec_dbg(codec,
-               "HDMI hot plug event: Codec=%d NID=0x%x Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n",
-               codec->addr, jack->nid, jack->dev_id, !!(res & AC_UNSOL_RES_IA),
-               !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV));
-
-       check_presence_and_report(codec, jack->nid, jack->dev_id);
-}
-
-static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res)
-{
-       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
-       int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
-       int cp_state = !!(res & AC_UNSOL_RES_CP_STATE);
-       int cp_ready = !!(res & AC_UNSOL_RES_CP_READY);
-
-       codec_info(codec,
-               "HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n",
-               codec->addr,
-               tag,
-               subtag,
-               cp_state,
-               cp_ready);
-
-       /* TODO */
-       if (cp_state) {
-               ;
-       }
-       if (cp_ready) {
-               ;
-       }
-}
-
-
-static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       int tag = res >> AC_UNSOL_RES_TAG_SHIFT;
-       int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT;
-       struct hda_jack_tbl *jack;
-
-       if (codec_has_acomp(codec))
-               return;
-
-       if (codec->dp_mst) {
-               int dev_entry =
-                       (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT;
-
-               jack = snd_hda_jack_tbl_get_from_tag(codec, tag, dev_entry);
-       } else {
-               jack = snd_hda_jack_tbl_get_from_tag(codec, tag, 0);
-       }
-
-       if (!jack) {
-               codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag);
-               return;
-       }
-
-       if (subtag == 0)
-               hdmi_intrinsic_event(codec, res, jack);
-       else
-               hdmi_non_intrinsic_event(codec, res);
-}
-
-static void haswell_verify_D0(struct hda_codec *codec,
-               hda_nid_t cvt_nid, hda_nid_t nid)
-{
-       int pwr;
-
-       /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
-        * thus pins could only choose converter 0 for use. Make sure the
-        * converters are in correct power state */
-       if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0))
-               snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-
-       if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) {
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE,
-                                   AC_PWRST_D0);
-               msleep(40);
-               pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
-               pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
-               codec_dbg(codec, "Haswell HDMI audio: Power for NID 0x%x is now D%d\n", nid, pwr);
-       }
-}
-
-/*
- * Callbacks
- */
-
-/* HBR should be Non-PCM, 8 channels */
-#define is_hbr_format(format) \
-       ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7)
-
-static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
-                             int dev_id, bool hbr)
-{
-       int pinctl, new_pinctl;
-
-       if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
-               snd_hda_set_dev_select(codec, pin_nid, dev_id);
-               pinctl = snd_hda_codec_read(codec, pin_nid, 0,
-                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-
-               if (pinctl < 0)
-                       return hbr ? -EINVAL : 0;
-
-               new_pinctl = pinctl & ~AC_PINCTL_EPT;
-               if (hbr)
-                       new_pinctl |= AC_PINCTL_EPT_HBR;
-               else
-                       new_pinctl |= AC_PINCTL_EPT_NATIVE;
-
-               codec_dbg(codec,
-                         "hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n",
-                           pin_nid,
-                           pinctl == new_pinctl ? "" : "new-",
-                           new_pinctl);
-
-               if (pinctl != new_pinctl)
-                       snd_hda_codec_write(codec, pin_nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           new_pinctl);
-       } else if (hbr)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
-                             hda_nid_t pin_nid, int dev_id,
-                             u32 stream_tag, int format)
-{
-       struct hdmi_spec *spec = codec->spec;
-       unsigned int param;
-       int err;
-
-       err = spec->ops.pin_hbr_setup(codec, pin_nid, dev_id,
-                                     is_hbr_format(format));
-
-       if (err) {
-               codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n");
-               return err;
-       }
-
-       if (spec->intel_hsw_fixup) {
-
-               /*
-                * on recent platforms IEC Coding Type is required for HBR
-                * support, read current Digital Converter settings and set
-                * ICT bitfield if needed.
-                */
-               param = snd_hda_codec_read(codec, cvt_nid, 0,
-                                          AC_VERB_GET_DIGI_CONVERT_1, 0);
-
-               param = (param >> 16) & ~(AC_DIG3_ICT);
-
-               /* on recent platforms ICT mode is required for HBR support */
-               if (is_hbr_format(format))
-                       param |= 0x1;
-
-               snd_hda_codec_write(codec, cvt_nid, 0,
-                                   AC_VERB_SET_DIGI_CONVERT_3, param);
-       }
-
-       snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format);
-       return 0;
-}
-
-/* Try to find an available converter
- * If pin_idx is less then zero, just try to find an available converter.
- * Otherwise, try to find an available converter and get the cvt mux index
- * of the pin.
- */
-static int hdmi_choose_cvt(struct hda_codec *codec,
-                          int pin_idx, int *cvt_id,
-                          bool silent)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin;
-       struct hdmi_spec_per_cvt *per_cvt = NULL;
-       int cvt_idx, mux_idx = 0;
-
-       /* pin_idx < 0 means no pin will be bound to the converter */
-       if (pin_idx < 0)
-               per_pin = NULL;
-       else
-               per_pin = get_pin(spec, pin_idx);
-
-       if (per_pin && per_pin->silent_stream) {
-               cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
-               per_cvt = get_cvt(spec, cvt_idx);
-               if (per_cvt->assigned && !silent)
-                       return -EBUSY;
-               if (cvt_id)
-                       *cvt_id = cvt_idx;
-               return 0;
-       }
-
-       /* Dynamically assign converter to stream */
-       for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
-               per_cvt = get_cvt(spec, cvt_idx);
-
-               /* Must not already be assigned */
-               if (per_cvt->assigned || per_cvt->silent_stream)
-                       continue;
-               if (per_pin == NULL)
-                       break;
-               /* Must be in pin's mux's list of converters */
-               for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
-                       if (per_pin->mux_nids[mux_idx] == per_cvt->cvt_nid)
-                               break;
-               /* Not in mux list */
-               if (mux_idx == per_pin->num_mux_nids)
-                       continue;
-               break;
-       }
-
-       /* No free converters */
-       if (cvt_idx == spec->num_cvts)
-               return -EBUSY;
-
-       if (per_pin != NULL)
-               per_pin->mux_idx = mux_idx;
-
-       if (cvt_id)
-               *cvt_id = cvt_idx;
-
-       return 0;
-}
-
-/* Assure the pin select the right convetor */
-static void intel_verify_pin_cvt_connect(struct hda_codec *codec,
-                       struct hdmi_spec_per_pin *per_pin)
-{
-       hda_nid_t pin_nid = per_pin->pin_nid;
-       int mux_idx, curr;
-
-       mux_idx = per_pin->mux_idx;
-       curr = snd_hda_codec_read(codec, pin_nid, 0,
-                                         AC_VERB_GET_CONNECT_SEL, 0);
-       if (curr != mux_idx)
-               snd_hda_codec_write_cache(codec, pin_nid, 0,
-                                           AC_VERB_SET_CONNECT_SEL,
-                                           mux_idx);
-}
-
-/* get the mux index for the converter of the pins
- * converter's mux index is the same for all pins on Intel platform
- */
-static int intel_cvt_id_to_mux_idx(struct hdmi_spec *spec,
-                       hda_nid_t cvt_nid)
-{
-       int i;
-
-       for (i = 0; i < spec->num_cvts; i++)
-               if (spec->cvt_nids[i] == cvt_nid)
-                       return i;
-       return -EINVAL;
-}
-
-/* Intel HDMI workaround to fix audio routing issue:
- * For some Intel display codecs, pins share the same connection list.
- * So a conveter can be selected by multiple pins and playback on any of these
- * pins will generate sound on the external display, because audio flows from
- * the same converter to the display pipeline. Also muting one pin may make
- * other pins have no sound output.
- * So this function assures that an assigned converter for a pin is not selected
- * by any other pins.
- */
-static void intel_not_share_assigned_cvt(struct hda_codec *codec,
-                                        hda_nid_t pin_nid,
-                                        int dev_id, int mux_idx)
-{
-       struct hdmi_spec *spec = codec->spec;
-       hda_nid_t nid;
-       int cvt_idx, curr;
-       struct hdmi_spec_per_cvt *per_cvt;
-       struct hdmi_spec_per_pin *per_pin;
-       int pin_idx;
-
-       /* configure the pins connections */
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               int dev_id_saved;
-               int dev_num;
-
-               per_pin = get_pin(spec, pin_idx);
-               /*
-                * pin not connected to monitor
-                * no need to operate on it
-                */
-               if (!per_pin->pcm)
-                       continue;
-
-               if ((per_pin->pin_nid == pin_nid) &&
-                       (per_pin->dev_id == dev_id))
-                       continue;
-
-               /*
-                * if per_pin->dev_id >= dev_num,
-                * snd_hda_get_dev_select() will fail,
-                * and the following operation is unpredictable.
-                * So skip this situation.
-                */
-               dev_num = snd_hda_get_num_devices(codec, per_pin->pin_nid) + 1;
-               if (per_pin->dev_id >= dev_num)
-                       continue;
-
-               nid = per_pin->pin_nid;
-
-               /*
-                * Calling this function should not impact
-                * on the device entry selection
-                * So let's save the dev id for each pin,
-                * and restore it when return
-                */
-               dev_id_saved = snd_hda_get_dev_select(codec, nid);
-               snd_hda_set_dev_select(codec, nid, per_pin->dev_id);
-               curr = snd_hda_codec_read(codec, nid, 0,
-                                         AC_VERB_GET_CONNECT_SEL, 0);
-               if (curr != mux_idx) {
-                       snd_hda_set_dev_select(codec, nid, dev_id_saved);
-                       continue;
-               }
-
-
-               /* choose an unassigned converter. The conveters in the
-                * connection list are in the same order as in the codec.
-                */
-               for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
-                       per_cvt = get_cvt(spec, cvt_idx);
-                       if (!per_cvt->assigned) {
-                               codec_dbg(codec,
-                                         "choose cvt %d for pin NID 0x%x\n",
-                                         cvt_idx, nid);
-                               snd_hda_codec_write_cache(codec, nid, 0,
-                                           AC_VERB_SET_CONNECT_SEL,
-                                           cvt_idx);
-                               break;
-                       }
-               }
-               snd_hda_set_dev_select(codec, nid, dev_id_saved);
-       }
-}
-
-/* A wrapper of intel_not_share_asigned_cvt() */
-static void intel_not_share_assigned_cvt_nid(struct hda_codec *codec,
-                       hda_nid_t pin_nid, int dev_id, hda_nid_t cvt_nid)
-{
-       int mux_idx;
-       struct hdmi_spec *spec = codec->spec;
-
-       /* On Intel platform, the mapping of converter nid to
-        * mux index of the pins are always the same.
-        * The pin nid may be 0, this means all pins will not
-        * share the converter.
-        */
-       mux_idx = intel_cvt_id_to_mux_idx(spec, cvt_nid);
-       if (mux_idx >= 0)
-               intel_not_share_assigned_cvt(codec, pin_nid, dev_id, mux_idx);
-}
-
-/* skeleton caller of pin_cvt_fixup ops */
-static void pin_cvt_fixup(struct hda_codec *codec,
-                         struct hdmi_spec_per_pin *per_pin,
-                         hda_nid_t cvt_nid)
-{
-       struct hdmi_spec *spec = codec->spec;
-
-       if (spec->ops.pin_cvt_fixup)
-               spec->ops.pin_cvt_fixup(codec, per_pin, cvt_nid);
-}
-
-/* called in hdmi_pcm_open when no pin is assigned to the PCM */
-static int hdmi_pcm_open_no_pin(struct hda_pcm_stream *hinfo,
-                        struct hda_codec *codec,
-                        struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int cvt_idx, pcm_idx;
-       struct hdmi_spec_per_cvt *per_cvt = NULL;
-       int err;
-
-       pcm_idx = hinfo_to_pcm_index(codec, hinfo);
-       if (pcm_idx < 0)
-               return -EINVAL;
-
-       err = hdmi_choose_cvt(codec, -1, &cvt_idx, false);
-       if (err)
-               return err;
-
-       per_cvt = get_cvt(spec, cvt_idx);
-       per_cvt->assigned = true;
-       hinfo->nid = per_cvt->cvt_nid;
-
-       pin_cvt_fixup(codec, NULL, per_cvt->cvt_nid);
-
-       set_bit(pcm_idx, &spec->pcm_in_use);
-       /* todo: setup spdif ctls assign */
-
-       /* Initially set the converter's capabilities */
-       hinfo->channels_min = per_cvt->channels_min;
-       hinfo->channels_max = per_cvt->channels_max;
-       hinfo->rates = per_cvt->rates;
-       hinfo->formats = per_cvt->formats;
-       hinfo->maxbps = per_cvt->maxbps;
-
-       /* Store the updated parameters */
-       runtime->hw.channels_min = hinfo->channels_min;
-       runtime->hw.channels_max = hinfo->channels_max;
-       runtime->hw.formats = hinfo->formats;
-       runtime->hw.rates = hinfo->rates;
-
-       snd_pcm_hw_constraint_step(substream->runtime, 0,
-                                  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
-       return 0;
-}
-
-/*
- * HDA PCM callbacks
- */
-static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
-                        struct hda_codec *codec,
-                        struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       int pin_idx, cvt_idx, pcm_idx;
-       struct hdmi_spec_per_pin *per_pin;
-       struct hdmi_eld *eld;
-       struct hdmi_spec_per_cvt *per_cvt = NULL;
-       int err;
-
-       /* Validate hinfo */
-       pcm_idx = hinfo_to_pcm_index(codec, hinfo);
-       if (pcm_idx < 0)
-               return -EINVAL;
-
-       mutex_lock(&spec->pcm_lock);
-       pin_idx = hinfo_to_pin_index(codec, hinfo);
-       /* no pin is assigned to the PCM
-        * PA need pcm open successfully when probe
-        */
-       if (pin_idx < 0) {
-               err = hdmi_pcm_open_no_pin(hinfo, codec, substream);
-               goto unlock;
-       }
-
-       err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, false);
-       if (err < 0)
-               goto unlock;
-
-       per_cvt = get_cvt(spec, cvt_idx);
-       /* Claim converter */
-       per_cvt->assigned = true;
-
-       set_bit(pcm_idx, &spec->pcm_in_use);
-       per_pin = get_pin(spec, pin_idx);
-       per_pin->cvt_nid = per_cvt->cvt_nid;
-       hinfo->nid = per_cvt->cvt_nid;
-
-       /* flip stripe flag for the assigned stream if supported */
-       if (get_wcaps(codec, per_cvt->cvt_nid) & AC_WCAP_STRIPE)
-               azx_stream(get_azx_dev(substream))->stripe = 1;
-
-       snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
-       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
-                           AC_VERB_SET_CONNECT_SEL,
-                           per_pin->mux_idx);
-
-       /* configure unused pins to choose other converters */
-       pin_cvt_fixup(codec, per_pin, 0);
-
-       snd_hda_spdif_ctls_assign(codec, pcm_idx, per_cvt->cvt_nid);
-
-       /* Initially set the converter's capabilities */
-       hinfo->channels_min = per_cvt->channels_min;
-       hinfo->channels_max = per_cvt->channels_max;
-       hinfo->rates = per_cvt->rates;
-       hinfo->formats = per_cvt->formats;
-       hinfo->maxbps = per_cvt->maxbps;
-
-       eld = &per_pin->sink_eld;
-       /* Restrict capabilities by ELD if this isn't disabled */
-       if (!static_hdmi_pcm && eld->eld_valid) {
-               snd_hdmi_eld_update_pcm_info(&eld->info, hinfo);
-               if (hinfo->channels_min > hinfo->channels_max ||
-                   !hinfo->rates || !hinfo->formats) {
-                       per_cvt->assigned = false;
-                       hinfo->nid = 0;
-                       snd_hda_spdif_ctls_unassign(codec, pcm_idx);
-                       err = -ENODEV;
-                       goto unlock;
-               }
-       }
-
-       /* Store the updated parameters */
-       runtime->hw.channels_min = hinfo->channels_min;
-       runtime->hw.channels_max = hinfo->channels_max;
-       runtime->hw.formats = hinfo->formats;
-       runtime->hw.rates = hinfo->rates;
-
-       snd_pcm_hw_constraint_step(substream->runtime, 0,
-                                  SNDRV_PCM_HW_PARAM_CHANNELS, 2);
- unlock:
-       mutex_unlock(&spec->pcm_lock);
-       return err;
-}
-
-/*
- * HDA/HDMI auto parsing
- */
-static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-       hda_nid_t pin_nid = per_pin->pin_nid;
-       int dev_id = per_pin->dev_id;
-       int conns;
-
-       if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) {
-               codec_warn(codec,
-                          "HDMI: pin NID 0x%x wcaps %#x does not support connection list\n",
-                          pin_nid, get_wcaps(codec, pin_nid));
-               return -EINVAL;
-       }
-
-       snd_hda_set_dev_select(codec, pin_nid, dev_id);
-
-       if (spec->intel_hsw_fixup) {
-               conns = spec->num_cvts;
-               memcpy(per_pin->mux_nids, spec->cvt_nids,
-                      sizeof(hda_nid_t) * conns);
-       } else {
-               conns = snd_hda_get_raw_connections(codec, pin_nid,
-                                                   per_pin->mux_nids,
-                                                   HDA_MAX_CONNECTIONS);
-       }
-
-       /* all the device entries on the same pin have the same conn list */
-       per_pin->num_mux_nids = conns;
-
-       return 0;
-}
-
-static int hdmi_find_pcm_slot(struct hdmi_spec *spec,
-                             struct hdmi_spec_per_pin *per_pin)
-{
-       int i;
-
-       for (i = 0; i < spec->pcm_used; i++) {
-               if (!test_bit(i, &spec->pcm_bitmap))
-                       return i;
-       }
-       return -EBUSY;
-}
-
-static void hdmi_attach_hda_pcm(struct hdmi_spec *spec,
-                               struct hdmi_spec_per_pin *per_pin)
-{
-       int idx;
-
-       /* pcm already be attached to the pin */
-       if (per_pin->pcm)
-               return;
-       /* try the previously used slot at first */
-       idx = per_pin->prev_pcm_idx;
-       if (idx >= 0) {
-               if (!test_bit(idx, &spec->pcm_bitmap))
-                       goto found;
-               per_pin->prev_pcm_idx = -1; /* no longer valid, clear it */
-       }
-       idx = hdmi_find_pcm_slot(spec, per_pin);
-       if (idx == -EBUSY)
-               return;
- found:
-       per_pin->pcm_idx = idx;
-       per_pin->pcm = get_hdmi_pcm(spec, idx);
-       set_bit(idx, &spec->pcm_bitmap);
-}
-
-static void hdmi_detach_hda_pcm(struct hdmi_spec *spec,
-                               struct hdmi_spec_per_pin *per_pin)
-{
-       int idx;
-
-       /* pcm already be detached from the pin */
-       if (!per_pin->pcm)
-               return;
-       idx = per_pin->pcm_idx;
-       per_pin->pcm_idx = -1;
-       per_pin->prev_pcm_idx = idx; /* remember the previous index */
-       per_pin->pcm = NULL;
-       if (idx >= 0 && idx < spec->pcm_used)
-               clear_bit(idx, &spec->pcm_bitmap);
-}
-
-static int hdmi_get_pin_cvt_mux(struct hdmi_spec *spec,
-               struct hdmi_spec_per_pin *per_pin, hda_nid_t cvt_nid)
-{
-       int mux_idx;
-
-       for (mux_idx = 0; mux_idx < per_pin->num_mux_nids; mux_idx++)
-               if (per_pin->mux_nids[mux_idx] == cvt_nid)
-                       break;
-       return mux_idx;
-}
-
-static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid);
-
-static void hdmi_pcm_setup_pin(struct hdmi_spec *spec,
-                          struct hdmi_spec_per_pin *per_pin)
-{
-       struct hda_codec *codec = per_pin->codec;
-       struct hda_pcm *pcm;
-       struct hda_pcm_stream *hinfo;
-       struct snd_pcm_substream *substream;
-       int mux_idx;
-       bool non_pcm;
-
-       if (per_pin->pcm_idx < 0 || per_pin->pcm_idx >= spec->pcm_used)
-               return;
-       pcm = get_pcm_rec(spec, per_pin->pcm_idx);
-       if (!pcm->pcm)
-               return;
-       if (!test_bit(per_pin->pcm_idx, &spec->pcm_in_use))
-               return;
-
-       /* hdmi audio only uses playback and one substream */
-       hinfo = pcm->stream;
-       substream = pcm->pcm->streams[0].substream;
-
-       per_pin->cvt_nid = hinfo->nid;
-
-       mux_idx = hdmi_get_pin_cvt_mux(spec, per_pin, hinfo->nid);
-       if (mux_idx < per_pin->num_mux_nids) {
-               snd_hda_set_dev_select(codec, per_pin->pin_nid,
-                                  per_pin->dev_id);
-               snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
-                               AC_VERB_SET_CONNECT_SEL,
-                               mux_idx);
-       }
-       snd_hda_spdif_ctls_assign(codec, per_pin->pcm_idx, hinfo->nid);
-
-       non_pcm = check_non_pcm_per_cvt(codec, hinfo->nid);
-       if (substream->runtime)
-               per_pin->channels = substream->runtime->channels;
-       per_pin->setup = true;
-       per_pin->mux_idx = mux_idx;
-
-       hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
-}
-
-static void hdmi_pcm_reset_pin(struct hdmi_spec *spec,
-                          struct hdmi_spec_per_pin *per_pin)
-{
-       if (per_pin->pcm_idx >= 0 && per_pin->pcm_idx < spec->pcm_used)
-               snd_hda_spdif_ctls_unassign(per_pin->codec, per_pin->pcm_idx);
-
-       per_pin->chmap_set = false;
-       memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
-
-       per_pin->setup = false;
-       per_pin->channels = 0;
-}
-
-static struct snd_jack *pin_idx_to_pcm_jack(struct hda_codec *codec,
-                                           struct hdmi_spec_per_pin *per_pin)
-{
-       struct hdmi_spec *spec = codec->spec;
-
-       if (per_pin->pcm_idx >= 0)
-               return spec->pcm_rec[per_pin->pcm_idx].jack;
-       else
-               return NULL;
-}
-
-/* update per_pin ELD from the given new ELD;
- * setup info frame and notification accordingly
- * also notify ELD kctl and report jack status changes
- */
-static void update_eld(struct hda_codec *codec,
-                      struct hdmi_spec_per_pin *per_pin,
-                      struct hdmi_eld *eld,
-                      int repoll)
-{
-       struct hdmi_eld *pin_eld = &per_pin->sink_eld;
-       struct hdmi_spec *spec = codec->spec;
-       struct snd_jack *pcm_jack;
-       bool old_eld_valid = pin_eld->eld_valid;
-       bool eld_changed;
-       int pcm_idx;
-
-       if (eld->eld_valid) {
-               if (eld->eld_size <= 0 ||
-                   snd_parse_eld(hda_codec_dev(codec), &eld->info,
-                                 eld->eld_buffer, eld->eld_size) < 0) {
-                       eld->eld_valid = false;
-                       if (repoll) {
-                               schedule_delayed_work(&per_pin->work,
-                                                     msecs_to_jiffies(300));
-                               return;
-                       }
-               }
-       }
-
-       if (!eld->eld_valid || eld->eld_size <= 0 || eld->info.sad_count <= 0) {
-               eld->eld_valid = false;
-               eld->eld_size = 0;
-       }
-
-       /* for monitor disconnection, save pcm_idx firstly */
-       pcm_idx = per_pin->pcm_idx;
-
-       /*
-        * pcm_idx >=0 before update_eld() means it is in monitor
-        * disconnected event. Jack must be fetched before update_eld().
-        */
-       pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
-
-       if (!spec->static_pcm_mapping) {
-               if (eld->eld_valid) {
-                       hdmi_attach_hda_pcm(spec, per_pin);
-                       hdmi_pcm_setup_pin(spec, per_pin);
-               } else {
-                       hdmi_pcm_reset_pin(spec, per_pin);
-                       hdmi_detach_hda_pcm(spec, per_pin);
-               }
-       }
-
-       /* if pcm_idx == -1, it means this is in monitor connection event
-        * we can get the correct pcm_idx now.
-        */
-       if (pcm_idx == -1)
-               pcm_idx = per_pin->pcm_idx;
-       if (!pcm_jack)
-               pcm_jack = pin_idx_to_pcm_jack(codec, per_pin);
-
-       if (eld->eld_valid)
-               snd_show_eld(hda_codec_dev(codec), &eld->info);
-
-       eld_changed = (pin_eld->eld_valid != eld->eld_valid);
-       eld_changed |= (pin_eld->monitor_present != eld->monitor_present);
-       if (!eld_changed && eld->eld_valid && pin_eld->eld_valid)
-               if (pin_eld->eld_size != eld->eld_size ||
-                   memcmp(pin_eld->eld_buffer, eld->eld_buffer,
-                          eld->eld_size) != 0)
-                       eld_changed = true;
-
-       if (eld_changed) {
-               pin_eld->monitor_present = eld->monitor_present;
-               pin_eld->eld_valid = eld->eld_valid;
-               pin_eld->eld_size = eld->eld_size;
-               if (eld->eld_valid)
-                       memcpy(pin_eld->eld_buffer, eld->eld_buffer,
-                              eld->eld_size);
-               pin_eld->info = eld->info;
-       }
-
-       /*
-        * Re-setup pin and infoframe. This is needed e.g. when
-        * - sink is first plugged-in
-        * - transcoder can change during stream playback on Haswell
-        *   and this can make HW reset converter selection on a pin.
-        */
-       if (eld->eld_valid && !old_eld_valid && per_pin->setup) {
-               pin_cvt_fixup(codec, per_pin, 0);
-               hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
-       }
-
-       if (eld_changed && pcm_idx >= 0)
-               snd_ctl_notify(codec->card,
-                              SNDRV_CTL_EVENT_MASK_VALUE |
-                              SNDRV_CTL_EVENT_MASK_INFO,
-                              &get_hdmi_pcm(spec, pcm_idx)->eld_ctl->id);
-
-       if (eld_changed && pcm_jack)
-               snd_jack_report(pcm_jack,
-                               (eld->monitor_present && eld->eld_valid) ?
-                               SND_JACK_AVOUT : 0);
-}
-
-/* update ELD and jack state via HD-audio verbs */
-static void hdmi_present_sense_via_verbs(struct hdmi_spec_per_pin *per_pin,
-                                        int repoll)
-{
-       struct hda_codec *codec = per_pin->codec;
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_eld *eld = &spec->temp_eld;
-       struct device *dev = hda_codec_dev(codec);
-       hda_nid_t pin_nid = per_pin->pin_nid;
-       int dev_id = per_pin->dev_id;
-       /*
-        * Always execute a GetPinSense verb here, even when called from
-        * hdmi_intrinsic_event; for some NVIDIA HW, the unsolicited
-        * response's PD bit is not the real PD value, but indicates that
-        * the real PD value changed. An older version of the HD-audio
-        * specification worked this way. Hence, we just ignore the data in
-        * the unsolicited response to avoid custom WARs.
-        */
-       int present;
-       int ret;
-
-#ifdef CONFIG_PM
-       if (dev->power.runtime_status == RPM_SUSPENDING)
-               return;
-#endif
-
-       ret = snd_hda_power_up_pm(codec);
-       if (ret < 0 && pm_runtime_suspended(dev))
-               goto out;
-
-       present = snd_hda_jack_pin_sense(codec, pin_nid, dev_id);
-
-       mutex_lock(&per_pin->lock);
-       eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
-       if (eld->monitor_present)
-               eld->eld_valid  = !!(present & AC_PINSENSE_ELDV);
-       else
-               eld->eld_valid = false;
-
-       codec_dbg(codec,
-               "HDMI status: Codec=%d NID=0x%x Presence_Detect=%d ELD_Valid=%d\n",
-               codec->addr, pin_nid, eld->monitor_present, eld->eld_valid);
-
-       if (eld->eld_valid) {
-               if (spec->ops.pin_get_eld(codec, pin_nid, dev_id,
-                                         eld->eld_buffer, &eld->eld_size) < 0)
-                       eld->eld_valid = false;
-       }
-
-       update_eld(codec, per_pin, eld, repoll);
-       mutex_unlock(&per_pin->lock);
- out:
-       snd_hda_power_down_pm(codec);
-}
-
-#define I915_SILENT_RATE               48000
-#define I915_SILENT_CHANNELS           2
-#define I915_SILENT_FORMAT_BITS        16
-#define I915_SILENT_FMT_MASK           0xf
-
-static void silent_stream_enable_i915(struct hda_codec *codec,
-                                     struct hdmi_spec_per_pin *per_pin)
-{
-       unsigned int format;
-
-       snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
-                                per_pin->dev_id, I915_SILENT_RATE);
-
-       /* trigger silent stream generation in hw */
-       format = snd_hdac_stream_format(I915_SILENT_CHANNELS, I915_SILENT_FORMAT_BITS,
-                                       I915_SILENT_RATE);
-       snd_hda_codec_setup_stream(codec, per_pin->cvt_nid,
-                                  I915_SILENT_FMT_MASK, I915_SILENT_FMT_MASK, format);
-       usleep_range(100, 200);
-       snd_hda_codec_setup_stream(codec, per_pin->cvt_nid, I915_SILENT_FMT_MASK, 0, format);
-
-       per_pin->channels = I915_SILENT_CHANNELS;
-       hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
-}
-
-static void silent_stream_set_kae(struct hda_codec *codec,
-                                 struct hdmi_spec_per_pin *per_pin,
-                                 bool enable)
-{
-       unsigned int param;
-
-       codec_dbg(codec, "HDMI: KAE %d cvt-NID=0x%x\n", enable, per_pin->cvt_nid);
-
-       param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0, AC_VERB_GET_DIGI_CONVERT_1, 0);
-       param = (param >> 16) & 0xff;
-
-       if (enable)
-               param |= AC_DIG3_KAE;
-       else
-               param &= ~AC_DIG3_KAE;
-
-       snd_hda_codec_write(codec, per_pin->cvt_nid, 0, AC_VERB_SET_DIGI_CONVERT_3, param);
-}
-
-static void silent_stream_enable(struct hda_codec *codec,
-                                struct hdmi_spec_per_pin *per_pin)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_cvt *per_cvt;
-       int cvt_idx, pin_idx, err;
-       int keep_power = 0;
-
-       /*
-        * Power-up will call hdmi_present_sense, so the PM calls
-        * have to be done without mutex held.
-        */
-
-       err = snd_hda_power_up_pm(codec);
-       if (err < 0 && err != -EACCES) {
-               codec_err(codec,
-                         "Failed to power up codec for silent stream enable ret=[%d]\n", err);
-               snd_hda_power_down_pm(codec);
-               return;
-       }
-
-       mutex_lock(&per_pin->lock);
-
-       if (per_pin->setup) {
-               codec_dbg(codec, "hdmi: PCM already open, no silent stream\n");
-               err = -EBUSY;
-               goto unlock_out;
-       }
-
-       pin_idx = pin_id_to_pin_index(codec, per_pin->pin_nid, per_pin->dev_id);
-       err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, true);
-       if (err) {
-               codec_err(codec, "hdmi: no free converter to enable silent mode\n");
-               goto unlock_out;
-       }
-
-       per_cvt = get_cvt(spec, cvt_idx);
-       per_cvt->silent_stream = true;
-       per_pin->cvt_nid = per_cvt->cvt_nid;
-       per_pin->silent_stream = true;
-
-       codec_dbg(codec, "hdmi: enabling silent stream pin-NID=0x%x cvt-NID=0x%x\n",
-                 per_pin->pin_nid, per_cvt->cvt_nid);
-
-       snd_hda_set_dev_select(codec, per_pin->pin_nid, per_pin->dev_id);
-       snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
-                                 AC_VERB_SET_CONNECT_SEL,
-                                 per_pin->mux_idx);
-
-       /* configure unused pins to choose other converters */
-       pin_cvt_fixup(codec, per_pin, 0);
-
-       switch (spec->silent_stream_type) {
-       case SILENT_STREAM_KAE:
-               silent_stream_enable_i915(codec, per_pin);
-               silent_stream_set_kae(codec, per_pin, true);
-               break;
-       case SILENT_STREAM_I915:
-               silent_stream_enable_i915(codec, per_pin);
-               keep_power = 1;
-               break;
-       default:
-               break;
-       }
-
- unlock_out:
-       mutex_unlock(&per_pin->lock);
-
-       if (err || !keep_power)
-               snd_hda_power_down_pm(codec);
-}
-
-static void silent_stream_disable(struct hda_codec *codec,
-                                 struct hdmi_spec_per_pin *per_pin)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_cvt *per_cvt;
-       int cvt_idx, err;
-
-       err = snd_hda_power_up_pm(codec);
-       if (err < 0 && err != -EACCES) {
-               codec_err(codec,
-                         "Failed to power up codec for silent stream disable ret=[%d]\n",
-                         err);
-               snd_hda_power_down_pm(codec);
-               return;
-       }
-
-       mutex_lock(&per_pin->lock);
-       if (!per_pin->silent_stream)
-               goto unlock_out;
-
-       codec_dbg(codec, "HDMI: disable silent stream on pin-NID=0x%x cvt-NID=0x%x\n",
-                 per_pin->pin_nid, per_pin->cvt_nid);
-
-       cvt_idx = cvt_nid_to_cvt_index(codec, per_pin->cvt_nid);
-       if (cvt_idx >= 0 && cvt_idx < spec->num_cvts) {
-               per_cvt = get_cvt(spec, cvt_idx);
-               per_cvt->silent_stream = false;
-       }
-
-       if (spec->silent_stream_type == SILENT_STREAM_I915) {
-               /* release ref taken in silent_stream_enable() */
-               snd_hda_power_down_pm(codec);
-       } else if (spec->silent_stream_type == SILENT_STREAM_KAE) {
-               silent_stream_set_kae(codec, per_pin, false);
-       }
-
-       per_pin->cvt_nid = 0;
-       per_pin->silent_stream = false;
-
- unlock_out:
-       mutex_unlock(&per_pin->lock);
-
-       snd_hda_power_down_pm(codec);
-}
-
-/* update ELD and jack state via audio component */
-static void sync_eld_via_acomp(struct hda_codec *codec,
-                              struct hdmi_spec_per_pin *per_pin)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_eld *eld = &spec->temp_eld;
-       bool monitor_prev, monitor_next;
-
-       mutex_lock(&per_pin->lock);
-       eld->monitor_present = false;
-       monitor_prev = per_pin->sink_eld.monitor_present;
-       eld->eld_size = snd_hdac_acomp_get_eld(&codec->core, per_pin->pin_nid,
-                                     per_pin->dev_id, &eld->monitor_present,
-                                     eld->eld_buffer, ELD_MAX_SIZE);
-       eld->eld_valid = (eld->eld_size > 0);
-       update_eld(codec, per_pin, eld, 0);
-       monitor_next = per_pin->sink_eld.monitor_present;
-       mutex_unlock(&per_pin->lock);
-
-       if (spec->silent_stream_type) {
-               if (!monitor_prev && monitor_next)
-                       silent_stream_enable(codec, per_pin);
-               else if (monitor_prev && !monitor_next)
-                       silent_stream_disable(codec, per_pin);
-       }
-}
-
-static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
-{
-       struct hda_codec *codec = per_pin->codec;
-
-       if (!codec_has_acomp(codec))
-               hdmi_present_sense_via_verbs(per_pin, repoll);
-       else
-               sync_eld_via_acomp(codec, per_pin);
-}
-
-static void hdmi_repoll_eld(struct work_struct *work)
-{
-       struct hdmi_spec_per_pin *per_pin =
-       container_of(to_delayed_work(work), struct hdmi_spec_per_pin, work);
-       struct hda_codec *codec = per_pin->codec;
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_jack_tbl *jack;
-
-       jack = snd_hda_jack_tbl_get_mst(codec, per_pin->pin_nid,
-                                       per_pin->dev_id);
-       if (jack)
-               jack->jack_dirty = 1;
-
-       if (per_pin->repoll_count++ > 6)
-               per_pin->repoll_count = 0;
-
-       mutex_lock(&spec->pcm_lock);
-       hdmi_present_sense(per_pin, per_pin->repoll_count);
-       mutex_unlock(&spec->pcm_lock);
-}
-
-static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid)
-{
-       struct hdmi_spec *spec = codec->spec;
-       unsigned int caps, config;
-       int pin_idx;
-       struct hdmi_spec_per_pin *per_pin;
-       int err;
-       int dev_num, i;
-
-       caps = snd_hda_query_pin_caps(codec, pin_nid);
-       if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP)))
-               return 0;
-
-       /*
-        * For DP MST audio, Configuration Default is the same for
-        * all device entries on the same pin
-        */
-       config = snd_hda_codec_get_pincfg(codec, pin_nid);
-       if (get_defcfg_connect(config) == AC_JACK_PORT_NONE &&
-           !spec->force_connect)
-               return 0;
-
-       /*
-        * To simplify the implementation, malloc all
-        * the virtual pins in the initialization statically
-        */
-       if (spec->intel_hsw_fixup) {
-               /*
-                * On Intel platforms, device entries count returned
-                * by AC_PAR_DEVLIST_LEN is dynamic, and depends on
-                * the type of receiver that is connected. Allocate pin
-                * structures based on worst case.
-                */
-               dev_num = spec->dev_num;
-       } else if (codec->dp_mst) {
-               dev_num = snd_hda_get_num_devices(codec, pin_nid) + 1;
-               /*
-                * spec->dev_num is the maxinum number of device entries
-                * among all the pins
-                */
-               spec->dev_num = (spec->dev_num > dev_num) ?
-                       spec->dev_num : dev_num;
-       } else {
-               /*
-                * If the platform doesn't support DP MST,
-                * manually set dev_num to 1. This means
-                * the pin has only one device entry.
-                */
-               dev_num = 1;
-               spec->dev_num = 1;
-       }
-
-       for (i = 0; i < dev_num; i++) {
-               pin_idx = spec->num_pins;
-               per_pin = snd_array_new(&spec->pins);
-
-               if (!per_pin)
-                       return -ENOMEM;
-
-               per_pin->pcm = NULL;
-               per_pin->pcm_idx = -1;
-               per_pin->prev_pcm_idx = -1;
-               per_pin->pin_nid = pin_nid;
-               per_pin->pin_nid_idx = spec->num_nids;
-               per_pin->dev_id = i;
-               per_pin->non_pcm = false;
-               snd_hda_set_dev_select(codec, pin_nid, i);
-               err = hdmi_read_pin_conn(codec, pin_idx);
-               if (err < 0)
-                       return err;
-               if (!is_jack_detectable(codec, pin_nid))
-                       codec_warn(codec, "HDMI: pin NID 0x%x - jack not detectable\n", pin_nid);
-               spec->num_pins++;
-       }
-       spec->num_nids++;
-
-       return 0;
-}
-
-static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_cvt *per_cvt;
-       unsigned int chans;
-       int err;
-
-       chans = get_wcaps(codec, cvt_nid);
-       chans = get_wcaps_channels(chans);
-
-       per_cvt = snd_array_new(&spec->cvts);
-       if (!per_cvt)
-               return -ENOMEM;
-
-       per_cvt->cvt_nid = cvt_nid;
-       per_cvt->channels_min = 2;
-       if (chans <= 16) {
-               per_cvt->channels_max = chans;
-               if (chans > spec->chmap.channels_max)
-                       spec->chmap.channels_max = chans;
-       }
-
-       err = snd_hda_query_supported_pcm(codec, cvt_nid,
-                                         &per_cvt->rates,
-                                         &per_cvt->formats,
-                                         NULL,
-                                         &per_cvt->maxbps);
-       if (err < 0)
-               return err;
-
-       if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids))
-               spec->cvt_nids[spec->num_cvts] = cvt_nid;
-       spec->num_cvts++;
-
-       return 0;
-}
-
-static const struct snd_pci_quirk force_connect_list[] = {
-       SND_PCI_QUIRK(0x103c, 0x83e2, "HP EliteDesk 800 G4", 1),
-       SND_PCI_QUIRK(0x103c, 0x83ef, "HP MP9 G4 Retail System AMS", 1),
-       SND_PCI_QUIRK(0x103c, 0x870f, "HP", 1),
-       SND_PCI_QUIRK(0x103c, 0x871a, "HP", 1),
-       SND_PCI_QUIRK(0x103c, 0x8711, "HP", 1),
-       SND_PCI_QUIRK(0x103c, 0x8715, "HP", 1),
-       SND_PCI_QUIRK(0x1043, 0x86ae, "ASUS", 1),  /* Z170 PRO */
-       SND_PCI_QUIRK(0x1043, 0x86c7, "ASUS", 1),  /* Z170M PLUS */
-       SND_PCI_QUIRK(0x1462, 0xec94, "MS-7C94", 1),
-       SND_PCI_QUIRK(0x8086, 0x2060, "Intel NUC5CPYB", 1),
-       SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", 1),
-       {}
-};
-
-static int hdmi_parse_codec(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       hda_nid_t start_nid;
-       unsigned int caps;
-       int i, nodes;
-       const struct snd_pci_quirk *q;
-
-       nodes = snd_hda_get_sub_nodes(codec, codec->core.afg, &start_nid);
-       if (!start_nid || nodes < 0) {
-               codec_warn(codec, "HDMI: failed to get afg sub nodes\n");
-               return -EINVAL;
-       }
-
-       if (enable_all_pins)
-               spec->force_connect = true;
-
-       q = snd_pci_quirk_lookup(codec->bus->pci, force_connect_list);
-
-       if (q && q->value)
-               spec->force_connect = true;
-
-       /*
-        * hdmi_add_pin() assumes total amount of converters to
-        * be known, so first discover all converters
-        */
-       for (i = 0; i < nodes; i++) {
-               hda_nid_t nid = start_nid + i;
-
-               caps = get_wcaps(codec, nid);
-
-               if (!(caps & AC_WCAP_DIGITAL))
-                       continue;
-
-               if (get_wcaps_type(caps) == AC_WID_AUD_OUT)
-                       hdmi_add_cvt(codec, nid);
-       }
-
-       /* discover audio pins */
-       for (i = 0; i < nodes; i++) {
-               hda_nid_t nid = start_nid + i;
-
-               caps = get_wcaps(codec, nid);
-
-               if (!(caps & AC_WCAP_DIGITAL))
-                       continue;
-
-               if (get_wcaps_type(caps) == AC_WID_PIN)
-                       hdmi_add_pin(codec, nid);
-       }
-
-       return 0;
-}
-
-/*
- */
-static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid)
-{
-       struct hda_spdif_out *spdif;
-       bool non_pcm;
-
-       mutex_lock(&codec->spdif_mutex);
-       spdif = snd_hda_spdif_out_of_nid(codec, cvt_nid);
-       /* Add sanity check to pass klockwork check.
-        * This should never happen.
-        */
-       if (WARN_ON(spdif == NULL)) {
-               mutex_unlock(&codec->spdif_mutex);
-               return true;
-       }
-       non_pcm = !!(spdif->status & IEC958_AES0_NONAUDIO);
-       mutex_unlock(&codec->spdif_mutex);
-       return non_pcm;
-}
-
-/*
- * HDMI callbacks
- */
-
-static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                          struct hda_codec *codec,
-                                          unsigned int stream_tag,
-                                          unsigned int format,
-                                          struct snd_pcm_substream *substream)
-{
-       hda_nid_t cvt_nid = hinfo->nid;
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx;
-       struct hdmi_spec_per_pin *per_pin;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       bool non_pcm;
-       int pinctl, stripe;
-       int err = 0;
-
-       mutex_lock(&spec->pcm_lock);
-       pin_idx = hinfo_to_pin_index(codec, hinfo);
-       if (pin_idx < 0) {
-               /* when pcm is not bound to a pin skip pin setup and return 0
-                * to make audio playback be ongoing
-                */
-               pin_cvt_fixup(codec, NULL, cvt_nid);
-               snd_hda_codec_setup_stream(codec, cvt_nid,
-                                       stream_tag, 0, format);
-               goto unlock;
-       }
-
-       per_pin = get_pin(spec, pin_idx);
-
-       /* Verify pin:cvt selections to avoid silent audio after S3.
-        * After S3, the audio driver restores pin:cvt selections
-        * but this can happen before gfx is ready and such selection
-        * is overlooked by HW. Thus multiple pins can share a same
-        * default convertor and mute control will affect each other,
-        * which can cause a resumed audio playback become silent
-        * after S3.
-        */
-       pin_cvt_fixup(codec, per_pin, 0);
-
-       /* Call sync_audio_rate to set the N/CTS/M manually if necessary */
-       /* Todo: add DP1.2 MST audio support later */
-       if (codec_has_acomp(codec))
-               snd_hdac_sync_audio_rate(&codec->core, per_pin->pin_nid,
-                                        per_pin->dev_id, runtime->rate);
-
-       non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
-       mutex_lock(&per_pin->lock);
-       per_pin->channels = substream->runtime->channels;
-       per_pin->setup = true;
-
-       if (get_wcaps(codec, cvt_nid) & AC_WCAP_STRIPE) {
-               stripe = snd_hdac_get_stream_stripe_ctl(&codec->bus->core,
-                                                       substream);
-               snd_hda_codec_write(codec, cvt_nid, 0,
-                                   AC_VERB_SET_STRIPE_CONTROL,
-                                   stripe);
-       }
-
-       hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
-       mutex_unlock(&per_pin->lock);
-       if (spec->dyn_pin_out) {
-               snd_hda_set_dev_select(codec, per_pin->pin_nid,
-                                      per_pin->dev_id);
-               pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
-                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-               snd_hda_codec_write(codec, per_pin->pin_nid, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                   pinctl | PIN_OUT);
-       }
-
-       /* snd_hda_set_dev_select() has been called before */
-       err = spec->ops.setup_stream(codec, cvt_nid, per_pin->pin_nid,
-                                    per_pin->dev_id, stream_tag, format);
- unlock:
-       mutex_unlock(&spec->pcm_lock);
-       return err;
-}
-
-static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                            struct hda_codec *codec,
-                                            struct snd_pcm_substream *substream)
-{
-       snd_hda_codec_cleanup_stream(codec, hinfo->nid);
-       return 0;
-}
-
-static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
-                         struct hda_codec *codec,
-                         struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int cvt_idx, pin_idx, pcm_idx;
-       struct hdmi_spec_per_cvt *per_cvt;
-       struct hdmi_spec_per_pin *per_pin;
-       int pinctl;
-       int err = 0;
-
-       mutex_lock(&spec->pcm_lock);
-       if (hinfo->nid) {
-               pcm_idx = hinfo_to_pcm_index(codec, hinfo);
-               if (snd_BUG_ON(pcm_idx < 0)) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
-               cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid);
-               if (snd_BUG_ON(cvt_idx < 0)) {
-                       err = -EINVAL;
-                       goto unlock;
-               }
-               per_cvt = get_cvt(spec, cvt_idx);
-               per_cvt->assigned = false;
-               hinfo->nid = 0;
-
-               azx_stream(get_azx_dev(substream))->stripe = 0;
-
-               snd_hda_spdif_ctls_unassign(codec, pcm_idx);
-               clear_bit(pcm_idx, &spec->pcm_in_use);
-               pin_idx = hinfo_to_pin_index(codec, hinfo);
-               /*
-                * In such a case, return 0 to match the behavior in
-                * hdmi_pcm_open()
-                */
-               if (pin_idx < 0)
-                       goto unlock;
-
-               per_pin = get_pin(spec, pin_idx);
-
-               if (spec->dyn_pin_out) {
-                       snd_hda_set_dev_select(codec, per_pin->pin_nid,
-                                              per_pin->dev_id);
-                       pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
-                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-                       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                           pinctl & ~PIN_OUT);
-               }
-
-               mutex_lock(&per_pin->lock);
-               per_pin->chmap_set = false;
-               memset(per_pin->chmap, 0, sizeof(per_pin->chmap));
-
-               per_pin->setup = false;
-               per_pin->channels = 0;
-               mutex_unlock(&per_pin->lock);
-       }
-
-unlock:
-       mutex_unlock(&spec->pcm_lock);
-
-       return err;
-}
-
-static const struct hda_pcm_ops generic_ops = {
-       .open = hdmi_pcm_open,
-       .close = hdmi_pcm_close,
-       .prepare = generic_hdmi_playback_pcm_prepare,
-       .cleanup = generic_hdmi_playback_pcm_cleanup,
-};
-
-static int hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
-{
-       struct hda_codec *codec = hdac_to_hda_codec(hdac);
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
-
-       if (!per_pin)
-               return 0;
-
-       return per_pin->sink_eld.info.spk_alloc;
-}
-
-static void hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
-                                       unsigned char *chmap)
-{
-       struct hda_codec *codec = hdac_to_hda_codec(hdac);
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
-
-       /* chmap is already set to 0 in caller */
-       if (!per_pin)
-               return;
-
-       memcpy(chmap, per_pin->chmap, ARRAY_SIZE(per_pin->chmap));
-}
-
-static void hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
-                               unsigned char *chmap, int prepared)
-{
-       struct hda_codec *codec = hdac_to_hda_codec(hdac);
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
-
-       if (!per_pin)
-               return;
-       mutex_lock(&per_pin->lock);
-       per_pin->chmap_set = true;
-       memcpy(per_pin->chmap, chmap, ARRAY_SIZE(per_pin->chmap));
-       if (prepared)
-               hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm);
-       mutex_unlock(&per_pin->lock);
-}
-
-static bool is_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
-{
-       struct hda_codec *codec = hdac_to_hda_codec(hdac);
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = pcm_idx_to_pin(spec, pcm_idx);
-
-       return per_pin ? true:false;
-}
-
-static int generic_hdmi_build_pcms(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int idx, pcm_num;
-
-       /* limit the PCM devices to the codec converters or available PINs */
-       pcm_num = min(spec->num_cvts, spec->num_pins);
-       codec_dbg(codec, "hdmi: pcm_num set to %d\n", pcm_num);
-
-       for (idx = 0; idx < pcm_num; idx++) {
-               struct hdmi_spec_per_cvt *per_cvt;
-               struct hda_pcm *info;
-               struct hda_pcm_stream *pstr;
-
-               info = snd_hda_codec_pcm_new(codec, "HDMI %d", idx);
-               if (!info)
-                       return -ENOMEM;
-
-               spec->pcm_rec[idx].pcm = info;
-               spec->pcm_used++;
-               info->pcm_type = HDA_PCM_TYPE_HDMI;
-               info->own_chmap = true;
-
-               pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
-               pstr->substreams = 1;
-               pstr->ops = generic_ops;
-
-               per_cvt = get_cvt(spec, 0);
-               pstr->channels_min = per_cvt->channels_min;
-               pstr->channels_max = per_cvt->channels_max;
-
-               /* pcm number is less than pcm_rec array size */
-               if (spec->pcm_used >= ARRAY_SIZE(spec->pcm_rec))
-                       break;
-               /* other pstr fields are set in open */
-       }
-
-       return 0;
-}
-
-static void free_hdmi_jack_priv(struct snd_jack *jack)
-{
-       struct hdmi_pcm *pcm = jack->private_data;
-
-       pcm->jack = NULL;
-}
-
-static int generic_hdmi_build_jack(struct hda_codec *codec, int pcm_idx)
-{
-       char hdmi_str[32] = "HDMI/DP";
-       struct hdmi_spec *spec = codec->spec;
-       struct snd_jack *jack;
-       int pcmdev = get_pcm_rec(spec, pcm_idx)->device;
-       int err;
-
-       if (pcmdev > 0)
-               sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev);
-
-       err = snd_jack_new(codec->card, hdmi_str, SND_JACK_AVOUT, &jack,
-                          true, false);
-       if (err < 0)
-               return err;
-
-       spec->pcm_rec[pcm_idx].jack = jack;
-       jack->private_data = &spec->pcm_rec[pcm_idx];
-       jack->private_free = free_hdmi_jack_priv;
-       return 0;
-}
-
-static int generic_hdmi_build_controls(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int dev, err;
-       int pin_idx, pcm_idx;
-
-       for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
-               if (!get_pcm_rec(spec, pcm_idx)->pcm) {
-                       /* no PCM: mark this for skipping permanently */
-                       set_bit(pcm_idx, &spec->pcm_bitmap);
-                       continue;
-               }
-
-               err = generic_hdmi_build_jack(codec, pcm_idx);
-               if (err < 0)
-                       return err;
-
-               /* create the spdif for each pcm
-                * pin will be bound when monitor is connected
-                */
-               err = snd_hda_create_dig_out_ctls(codec,
-                                         0, spec->cvt_nids[0],
-                                         HDA_PCM_TYPE_HDMI);
-               if (err < 0)
-                       return err;
-               snd_hda_spdif_ctls_unassign(codec, pcm_idx);
-
-               dev = get_pcm_rec(spec, pcm_idx)->device;
-               if (dev != SNDRV_PCM_INVALID_DEVICE) {
-                       /* add control for ELD Bytes */
-                       err = hdmi_create_eld_ctl(codec, pcm_idx, dev);
-                       if (err < 0)
-                               return err;
-               }
-       }
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-               struct hdmi_eld *pin_eld = &per_pin->sink_eld;
-
-               if (spec->static_pcm_mapping) {
-                       hdmi_attach_hda_pcm(spec, per_pin);
-                       hdmi_pcm_setup_pin(spec, per_pin);
-               }
-
-               pin_eld->eld_valid = false;
-               hdmi_present_sense(per_pin, 0);
-       }
-
-       /* add channel maps */
-       for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
-               struct hda_pcm *pcm;
-
-               pcm = get_pcm_rec(spec, pcm_idx);
-               if (!pcm || !pcm->pcm)
-                       break;
-               err = snd_hdac_add_chmap_ctls(pcm->pcm, pcm_idx, &spec->chmap);
-               if (err < 0)
-                       return err;
-       }
-
-       return 0;
-}
-
-static int generic_hdmi_init_per_pins(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx;
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
-               per_pin->codec = codec;
-               mutex_init(&per_pin->lock);
-               INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld);
-               eld_proc_new(per_pin, pin_idx);
-       }
-       return 0;
-}
-
-static int generic_hdmi_init(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx;
-
-       mutex_lock(&spec->bind_lock);
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-               hda_nid_t pin_nid = per_pin->pin_nid;
-               int dev_id = per_pin->dev_id;
-
-               snd_hda_set_dev_select(codec, pin_nid, dev_id);
-               hdmi_init_pin(codec, pin_nid);
-               if (codec_has_acomp(codec))
-                       continue;
-               snd_hda_jack_detect_enable_callback_mst(codec, pin_nid, dev_id,
-                                                       jack_callback);
-       }
-       mutex_unlock(&spec->bind_lock);
-       return 0;
-}
-
-static void hdmi_array_init(struct hdmi_spec *spec, int nums)
-{
-       snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums);
-       snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums);
-}
-
-static void hdmi_array_free(struct hdmi_spec *spec)
-{
-       snd_array_free(&spec->pins);
-       snd_array_free(&spec->cvts);
-}
-
-static void generic_spec_free(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-
-       if (spec) {
-               hdmi_array_free(spec);
-               kfree(spec);
-               codec->spec = NULL;
-       }
-       codec->dp_mst = false;
-}
-
-static void generic_hdmi_free(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx, pcm_idx;
-
-       if (spec->acomp_registered) {
-               snd_hdac_acomp_exit(&codec->bus->core);
-       } else if (codec_has_acomp(codec)) {
-               snd_hdac_acomp_register_notifier(&codec->bus->core, NULL);
-       }
-       codec->relaxed_resume = 0;
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-               cancel_delayed_work_sync(&per_pin->work);
-               eld_proc_free(per_pin);
-       }
-
-       for (pcm_idx = 0; pcm_idx < spec->pcm_used; pcm_idx++) {
-               if (spec->pcm_rec[pcm_idx].jack == NULL)
-                       continue;
-               snd_device_free(codec->card, spec->pcm_rec[pcm_idx].jack);
-       }
-
-       generic_spec_free(codec);
-}
-
-static int generic_hdmi_suspend(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx;
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-               cancel_delayed_work_sync(&per_pin->work);
-       }
-       return 0;
-}
-
-static int generic_hdmi_resume(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx;
-
-       codec->patch_ops.init(codec);
-       snd_hda_regmap_sync(codec);
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-               hdmi_present_sense(per_pin, 1);
-       }
-       return 0;
-}
-
-static const struct hda_codec_ops generic_hdmi_patch_ops = {
-       .init                   = generic_hdmi_init,
-       .free                   = generic_hdmi_free,
-       .build_pcms             = generic_hdmi_build_pcms,
-       .build_controls         = generic_hdmi_build_controls,
-       .unsol_event            = hdmi_unsol_event,
-       .suspend                = generic_hdmi_suspend,
-       .resume                 = generic_hdmi_resume,
-};
-
-static const struct hdmi_ops generic_standard_hdmi_ops = {
-       .pin_get_eld                            = hdmi_pin_get_eld,
-       .pin_setup_infoframe                    = hdmi_pin_setup_infoframe,
-       .pin_hbr_setup                          = hdmi_pin_hbr_setup,
-       .setup_stream                           = hdmi_setup_stream,
-};
-
-/* allocate codec->spec and assign/initialize generic parser ops */
-static int alloc_generic_hdmi(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-
-       spec->codec = codec;
-       spec->ops = generic_standard_hdmi_ops;
-       spec->dev_num = 1;      /* initialize to 1 */
-       mutex_init(&spec->pcm_lock);
-       mutex_init(&spec->bind_lock);
-       snd_hdac_register_chmap_ops(&codec->core, &spec->chmap);
-
-       spec->chmap.ops.get_chmap = hdmi_get_chmap;
-       spec->chmap.ops.set_chmap = hdmi_set_chmap;
-       spec->chmap.ops.is_pcm_attached = is_hdmi_pcm_attached;
-       spec->chmap.ops.get_spk_alloc = hdmi_get_spk_alloc;
-
-       codec->spec = spec;
-       hdmi_array_init(spec, 4);
-
-       codec->patch_ops = generic_hdmi_patch_ops;
-
-       return 0;
-}
-
-/* generic HDMI parser */
-static int patch_generic_hdmi(struct hda_codec *codec)
-{
-       int err;
-
-       err = alloc_generic_hdmi(codec);
-       if (err < 0)
-               return err;
-
-       err = hdmi_parse_codec(codec);
-       if (err < 0) {
-               generic_spec_free(codec);
-               return err;
-       }
-
-       generic_hdmi_init_per_pins(codec);
-       return 0;
-}
-
-/*
- * generic audio component binding
- */
-
-/* turn on / off the unsol event jack detection dynamically */
-static void reprogram_jack_detect(struct hda_codec *codec, hda_nid_t nid,
-                                 int dev_id, bool use_acomp)
-{
-       struct hda_jack_tbl *tbl;
-
-       tbl = snd_hda_jack_tbl_get_mst(codec, nid, dev_id);
-       if (tbl) {
-               /* clear unsol even if component notifier is used, or re-enable
-                * if notifier is cleared
-                */
-               unsigned int val = use_acomp ? 0 : (AC_USRSP_EN | tbl->tag);
-               snd_hda_codec_write_cache(codec, nid, 0,
-                                         AC_VERB_SET_UNSOLICITED_ENABLE, val);
-       }
-}
-
-/* set up / clear component notifier dynamically */
-static void generic_acomp_notifier_set(struct drm_audio_component *acomp,
-                                      bool use_acomp)
-{
-       struct hdmi_spec *spec;
-       int i;
-
-       spec = container_of(acomp->audio_ops, struct hdmi_spec, drm_audio_ops);
-       mutex_lock(&spec->bind_lock);
-       spec->use_acomp_notifier = use_acomp;
-       spec->codec->relaxed_resume = use_acomp;
-       spec->codec->bus->keep_power = 0;
-       /* reprogram each jack detection logic depending on the notifier */
-       for (i = 0; i < spec->num_pins; i++)
-               reprogram_jack_detect(spec->codec,
-                                     get_pin(spec, i)->pin_nid,
-                                     get_pin(spec, i)->dev_id,
-                                     use_acomp);
-       mutex_unlock(&spec->bind_lock);
-}
-
-/* enable / disable the notifier via master bind / unbind */
-static int generic_acomp_master_bind(struct device *dev,
-                                    struct drm_audio_component *acomp)
-{
-       generic_acomp_notifier_set(acomp, true);
-       return 0;
-}
-
-static void generic_acomp_master_unbind(struct device *dev,
-                                       struct drm_audio_component *acomp)
-{
-       generic_acomp_notifier_set(acomp, false);
-}
-
-/* check whether both HD-audio and DRM PCI devices belong to the same bus */
-static int match_bound_vga(struct device *dev, int subtype, void *data)
-{
-       struct hdac_bus *bus = data;
-       struct pci_dev *pci, *master;
-
-       if (!dev_is_pci(dev) || !dev_is_pci(bus->dev))
-               return 0;
-       master = to_pci_dev(bus->dev);
-       pci = to_pci_dev(dev);
-       return master->bus == pci->bus;
-}
-
-/* audio component notifier for AMD/Nvidia HDMI codecs */
-static void generic_acomp_pin_eld_notify(void *audio_ptr, int port, int dev_id)
-{
-       struct hda_codec *codec = audio_ptr;
-       struct hdmi_spec *spec = codec->spec;
-       hda_nid_t pin_nid = spec->port2pin(codec, port);
-
-       if (!pin_nid)
-               return;
-       if (get_wcaps_type(get_wcaps(codec, pin_nid)) != AC_WID_PIN)
-               return;
-       /* skip notification during system suspend (but not in runtime PM);
-        * the state will be updated at resume
-        */
-       if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
-               return;
-
-       check_presence_and_report(codec, pin_nid, dev_id);
-}
-
-/* set up the private drm_audio_ops from the template */
-static void setup_drm_audio_ops(struct hda_codec *codec,
-                               const struct drm_audio_component_audio_ops *ops)
-{
-       struct hdmi_spec *spec = codec->spec;
-
-       spec->drm_audio_ops.audio_ptr = codec;
-       /* intel_audio_codec_enable() or intel_audio_codec_disable()
-        * will call pin_eld_notify with using audio_ptr pointer
-        * We need make sure audio_ptr is really setup
-        */
-       wmb();
-       spec->drm_audio_ops.pin2port = ops->pin2port;
-       spec->drm_audio_ops.pin_eld_notify = ops->pin_eld_notify;
-       spec->drm_audio_ops.master_bind = ops->master_bind;
-       spec->drm_audio_ops.master_unbind = ops->master_unbind;
-}
-
-/* initialize the generic HDMI audio component */
-static void generic_acomp_init(struct hda_codec *codec,
-                              const struct drm_audio_component_audio_ops *ops,
-                              int (*port2pin)(struct hda_codec *, int))
-{
-       struct hdmi_spec *spec = codec->spec;
-
-       if (!enable_acomp) {
-               codec_info(codec, "audio component disabled by module option\n");
-               return;
-       }
-
-       spec->port2pin = port2pin;
-       setup_drm_audio_ops(codec, ops);
-       if (!snd_hdac_acomp_init(&codec->bus->core, &spec->drm_audio_ops,
-                                match_bound_vga, 0)) {
-               spec->acomp_registered = true;
-       }
-}
-
-/*
- * Intel codec parsers and helpers
- */
-
-#define INTEL_GET_VENDOR_VERB  0xf81
-#define INTEL_SET_VENDOR_VERB  0x781
-#define INTEL_EN_DP12          0x02    /* enable DP 1.2 features */
-#define INTEL_EN_ALL_PIN_CVTS  0x01    /* enable 2nd & 3rd pins and convertors */
-
-static void intel_haswell_enable_all_pins(struct hda_codec *codec,
-                                         bool update_tree)
-{
-       unsigned int vendor_param;
-       struct hdmi_spec *spec = codec->spec;
-
-       vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
-                               INTEL_GET_VENDOR_VERB, 0);
-       if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS)
-               return;
-
-       vendor_param |= INTEL_EN_ALL_PIN_CVTS;
-       vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
-                               INTEL_SET_VENDOR_VERB, vendor_param);
-       if (vendor_param == -1)
-               return;
-
-       if (update_tree)
-               snd_hda_codec_update_widgets(codec);
-}
-
-static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec)
-{
-       unsigned int vendor_param;
-       struct hdmi_spec *spec = codec->spec;
-
-       vendor_param = snd_hda_codec_read(codec, spec->vendor_nid, 0,
-                               INTEL_GET_VENDOR_VERB, 0);
-       if (vendor_param == -1 || vendor_param & INTEL_EN_DP12)
-               return;
-
-       /* enable DP1.2 mode */
-       vendor_param |= INTEL_EN_DP12;
-       snd_hdac_regmap_add_vendor_verb(&codec->core, INTEL_SET_VENDOR_VERB);
-       snd_hda_codec_write_cache(codec, spec->vendor_nid, 0,
-                               INTEL_SET_VENDOR_VERB, vendor_param);
-}
-
-/* Haswell needs to re-issue the vendor-specific verbs before turning to D0.
- * Otherwise you may get severe h/w communication errors.
- */
-static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg,
-                               unsigned int power_state)
-{
-       if (power_state == AC_PWRST_D0) {
-               intel_haswell_enable_all_pins(codec, false);
-               intel_haswell_fixup_enable_dp12(codec);
-       }
-
-       snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state);
-       snd_hda_codec_set_power_to_all(codec, fg, power_state);
-}
-
-/* There is a fixed mapping between audio pin node and display port.
- * on SNB, IVY, HSW, BSW, SKL, BXT, KBL:
- * Pin Widget 5 - PORT B (port = 1 in i915 driver)
- * Pin Widget 6 - PORT C (port = 2 in i915 driver)
- * Pin Widget 7 - PORT D (port = 3 in i915 driver)
- *
- * on VLV, ILK:
- * Pin Widget 4 - PORT B (port = 1 in i915 driver)
- * Pin Widget 5 - PORT C (port = 2 in i915 driver)
- * Pin Widget 6 - PORT D (port = 3 in i915 driver)
- */
-static int intel_base_nid(struct hda_codec *codec)
-{
-       switch (codec->core.vendor_id) {
-       case 0x80860054: /* ILK */
-       case 0x80862804: /* ILK */
-       case 0x80862882: /* VLV */
-               return 4;
-       default:
-               return 5;
-       }
-}
-
-static int intel_pin2port(void *audio_ptr, int pin_nid)
-{
-       struct hda_codec *codec = audio_ptr;
-       struct hdmi_spec *spec = codec->spec;
-       int base_nid, i;
-
-       if (!spec->port_num) {
-               base_nid = intel_base_nid(codec);
-               if (WARN_ON(pin_nid < base_nid || pin_nid >= base_nid + 3))
-                       return -1;
-               return pin_nid - base_nid + 1;
-       }
-
-       /*
-        * looking for the pin number in the mapping table and return
-        * the index which indicate the port number
-        */
-       for (i = 0; i < spec->port_num; i++) {
-               if (pin_nid == spec->port_map[i])
-                       return i;
-       }
-
-       codec_info(codec, "Can't find the HDMI/DP port for pin NID 0x%x\n", pin_nid);
-       return -1;
-}
-
-static int intel_port2pin(struct hda_codec *codec, int port)
-{
-       struct hdmi_spec *spec = codec->spec;
-
-       if (!spec->port_num) {
-               /* we assume only from port-B to port-D */
-               if (port < 1 || port > 3)
-                       return 0;
-               return port + intel_base_nid(codec) - 1;
-       }
-
-       if (port < 0 || port >= spec->port_num)
-               return 0;
-       return spec->port_map[port];
-}
-
-static void intel_pin_eld_notify(void *audio_ptr, int port, int pipe)
-{
-       struct hda_codec *codec = audio_ptr;
-       int pin_nid;
-       int dev_id = pipe;
-
-       pin_nid = intel_port2pin(codec, port);
-       if (!pin_nid)
-               return;
-       /* skip notification during system suspend (but not in runtime PM);
-        * the state will be updated at resume
-        */
-       if (codec->core.dev.power.power_state.event == PM_EVENT_SUSPEND)
-               return;
-
-       snd_hdac_i915_set_bclk(&codec->bus->core);
-       check_presence_and_report(codec, pin_nid, dev_id);
-}
-
-static const struct drm_audio_component_audio_ops intel_audio_ops = {
-       .pin2port = intel_pin2port,
-       .pin_eld_notify = intel_pin_eld_notify,
-};
-
-/* register i915 component pin_eld_notify callback */
-static void register_i915_notifier(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-
-       spec->use_acomp_notifier = true;
-       spec->port2pin = intel_port2pin;
-       setup_drm_audio_ops(codec, &intel_audio_ops);
-       snd_hdac_acomp_register_notifier(&codec->bus->core,
-                                       &spec->drm_audio_ops);
-       /* no need for forcible resume for jack check thanks to notifier */
-       codec->relaxed_resume = 1;
-}
-
-/* setup_stream ops override for HSW+ */
-static int i915_hsw_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
-                                hda_nid_t pin_nid, int dev_id, u32 stream_tag,
-                                int format)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx = pin_id_to_pin_index(codec, pin_nid, dev_id);
-       struct hdmi_spec_per_pin *per_pin;
-       int res;
-
-       if (pin_idx < 0)
-               per_pin = NULL;
-       else
-               per_pin = get_pin(spec, pin_idx);
-
-       haswell_verify_D0(codec, cvt_nid, pin_nid);
-
-       if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
-               silent_stream_set_kae(codec, per_pin, false);
-               /* wait for pending transfers in codec to clear */
-               usleep_range(100, 200);
-       }
-
-       res = hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
-                               stream_tag, format);
-
-       if (spec->silent_stream_type == SILENT_STREAM_KAE && per_pin && per_pin->silent_stream) {
-               usleep_range(100, 200);
-               silent_stream_set_kae(codec, per_pin, true);
-       }
-
-       return res;
-}
-
-/* pin_cvt_fixup ops override for HSW+ and VLV+ */
-static void i915_pin_cvt_fixup(struct hda_codec *codec,
-                              struct hdmi_spec_per_pin *per_pin,
-                              hda_nid_t cvt_nid)
-{
-       if (per_pin) {
-               haswell_verify_D0(codec, per_pin->cvt_nid, per_pin->pin_nid);
-               snd_hda_set_dev_select(codec, per_pin->pin_nid,
-                              per_pin->dev_id);
-               intel_verify_pin_cvt_connect(codec, per_pin);
-               intel_not_share_assigned_cvt(codec, per_pin->pin_nid,
-                                    per_pin->dev_id, per_pin->mux_idx);
-       } else {
-               intel_not_share_assigned_cvt_nid(codec, 0, 0, cvt_nid);
-       }
-}
-
-static int i915_adlp_hdmi_suspend(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       bool silent_streams = false;
-       int pin_idx, res;
-
-       res = generic_hdmi_suspend(codec);
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
-               if (per_pin->silent_stream) {
-                       silent_streams = true;
-                       break;
-               }
-       }
-
-       if (silent_streams && spec->silent_stream_type == SILENT_STREAM_KAE) {
-               /*
-                * stream-id should remain programmed when codec goes
-                * to runtime suspend
-                */
-               codec->no_stream_clean_at_suspend = 1;
-
-               /*
-                * the system might go to S3, in which case keep-alive
-                * must be reprogrammed upon resume
-                */
-               codec->forced_resume = 1;
-
-               codec_dbg(codec, "HDMI: KAE active at suspend\n");
-       } else {
-               codec->no_stream_clean_at_suspend = 0;
-               codec->forced_resume = 0;
-       }
-
-       return res;
-}
-
-static int i915_adlp_hdmi_resume(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx, res;
-
-       res = generic_hdmi_resume(codec);
-
-       /* KAE not programmed at suspend, nothing to do here */
-       if (!codec->no_stream_clean_at_suspend)
-               return res;
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
-               /*
-                * If system was in suspend with monitor connected,
-                * the codec setting may have been lost. Re-enable
-                * keep-alive.
-                */
-               if (per_pin->silent_stream) {
-                       unsigned int param;
-
-                       param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
-                                                  AC_VERB_GET_CONV, 0);
-                       if (!param) {
-                               codec_dbg(codec, "HDMI: KAE: restore stream id\n");
-                               silent_stream_enable_i915(codec, per_pin);
-                       }
-
-                       param = snd_hda_codec_read(codec, per_pin->cvt_nid, 0,
-                                                  AC_VERB_GET_DIGI_CONVERT_1, 0);
-                       if (!(param & (AC_DIG3_KAE << 16))) {
-                               codec_dbg(codec, "HDMI: KAE: restore DIG3_KAE\n");
-                               silent_stream_set_kae(codec, per_pin, true);
-                       }
-               }
-       }
-
-       return res;
-}
-
-/* precondition and allocation for Intel codecs */
-static int alloc_intel_hdmi(struct hda_codec *codec)
-{
-       int err;
-
-       /* requires i915 binding */
-       if (!codec->bus->core.audio_component) {
-               codec_info(codec, "No i915 binding for Intel HDMI/DP codec\n");
-               /* set probe_id here to prevent generic fallback binding */
-               codec->probe_id = HDA_CODEC_ID_SKIP_PROBE;
-               return -ENODEV;
-       }
-
-       err = alloc_generic_hdmi(codec);
-       if (err < 0)
-               return err;
-       /* no need to handle unsol events */
-       codec->patch_ops.unsol_event = NULL;
-       return 0;
-}
-
-/* parse and post-process for Intel codecs */
-static int parse_intel_hdmi(struct hda_codec *codec)
-{
-       int err, retries = 3;
-
-       do {
-               err = hdmi_parse_codec(codec);
-       } while (err < 0 && retries--);
-
-       if (err < 0) {
-               generic_spec_free(codec);
-               return err;
-       }
-
-       generic_hdmi_init_per_pins(codec);
-       register_i915_notifier(codec);
-       return 0;
-}
-
-/* Intel Haswell and onwards; audio component with eld notifier */
-static int intel_hsw_common_init(struct hda_codec *codec, hda_nid_t vendor_nid,
-                                const int *port_map, int port_num, int dev_num,
-                                bool send_silent_stream)
-{
-       struct hdmi_spec *spec;
-       int err;
-
-       err = alloc_intel_hdmi(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-       codec->dp_mst = true;
-       spec->vendor_nid = vendor_nid;
-       spec->port_map = port_map;
-       spec->port_num = port_num;
-       spec->intel_hsw_fixup = true;
-       spec->dev_num = dev_num;
-
-       intel_haswell_enable_all_pins(codec, true);
-       intel_haswell_fixup_enable_dp12(codec);
-
-       codec->display_power_control = 1;
-
-       codec->patch_ops.set_power_state = haswell_set_power_state;
-       codec->depop_delay = 0;
-       codec->auto_runtime_pm = 1;
-
-       spec->ops.setup_stream = i915_hsw_setup_stream;
-       spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
-
-       /*
-        * Enable silent stream feature, if it is enabled via
-        * module param or Kconfig option
-        */
-       if (send_silent_stream)
-               spec->silent_stream_type = SILENT_STREAM_I915;
-
-       return parse_intel_hdmi(codec);
-}
-
-static int patch_i915_hsw_hdmi(struct hda_codec *codec)
-{
-       return intel_hsw_common_init(codec, 0x08, NULL, 0, 3,
-                                    enable_silent_stream);
-}
-
-static int patch_i915_glk_hdmi(struct hda_codec *codec)
-{
-       /*
-        * Silent stream calls audio component .get_power() from
-        * .pin_eld_notify(). On GLK this will deadlock in i915 due
-        * to the audio vs. CDCLK workaround.
-        */
-       return intel_hsw_common_init(codec, 0x0b, NULL, 0, 3, false);
-}
-
-static int patch_i915_icl_hdmi(struct hda_codec *codec)
-{
-       /*
-        * pin to port mapping table where the value indicate the pin number and
-        * the index indicate the port number.
-        */
-       static const int map[] = {0x0, 0x4, 0x6, 0x8, 0xa, 0xb};
-
-       return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 3,
-                                    enable_silent_stream);
-}
-
-static int patch_i915_tgl_hdmi(struct hda_codec *codec)
-{
-       /*
-        * pin to port mapping table where the value indicate the pin number and
-        * the index indicate the port number.
-        */
-       static const int map[] = {0x4, 0x6, 0x8, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
-
-       return intel_hsw_common_init(codec, 0x02, map, ARRAY_SIZE(map), 4,
-                                    enable_silent_stream);
-}
-
-static int patch_i915_adlp_hdmi(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int res;
-
-       res = patch_i915_tgl_hdmi(codec);
-       if (!res) {
-               spec = codec->spec;
-
-               if (spec->silent_stream_type) {
-                       spec->silent_stream_type = SILENT_STREAM_KAE;
-
-                       codec->patch_ops.resume = i915_adlp_hdmi_resume;
-                       codec->patch_ops.suspend = i915_adlp_hdmi_suspend;
-               }
-       }
-
-       return res;
-}
-
-/* Intel Baytrail and Braswell; with eld notifier */
-static int patch_i915_byt_hdmi(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int err;
-
-       err = alloc_intel_hdmi(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-
-       /* For Valleyview/Cherryview, only the display codec is in the display
-        * power well and can use link_power ops to request/release the power.
-        */
-       codec->display_power_control = 1;
-
-       codec->depop_delay = 0;
-       codec->auto_runtime_pm = 1;
-
-       spec->ops.pin_cvt_fixup = i915_pin_cvt_fixup;
-
-       return parse_intel_hdmi(codec);
-}
-
-/* Intel IronLake, SandyBridge and IvyBridge; with eld notifier */
-static int patch_i915_cpt_hdmi(struct hda_codec *codec)
-{
-       int err;
-
-       err = alloc_intel_hdmi(codec);
-       if (err < 0)
-               return err;
-       return parse_intel_hdmi(codec);
-}
-
-/*
- * Shared non-generic implementations
- */
-
-static int simple_playback_build_pcms(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info;
-       unsigned int chans;
-       struct hda_pcm_stream *pstr;
-       struct hdmi_spec_per_cvt *per_cvt;
-
-       per_cvt = get_cvt(spec, 0);
-       chans = get_wcaps(codec, per_cvt->cvt_nid);
-       chans = get_wcaps_channels(chans);
-
-       info = snd_hda_codec_pcm_new(codec, "HDMI 0");
-       if (!info)
-               return -ENOMEM;
-       spec->pcm_rec[0].pcm = info;
-       info->pcm_type = HDA_PCM_TYPE_HDMI;
-       pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK];
-       *pstr = spec->pcm_playback;
-       pstr->nid = per_cvt->cvt_nid;
-       if (pstr->channels_max <= 2 && chans && chans <= 16)
-               pstr->channels_max = chans;
-
-       return 0;
-}
-
-/* unsolicited event for jack sensing */
-static void simple_hdmi_unsol_event(struct hda_codec *codec,
-                                   unsigned int res)
-{
-       snd_hda_jack_set_dirty_all(codec);
-       snd_hda_jack_report_sync(codec);
-}
-
-/* generic_hdmi_build_jack can be used for simple_hdmi, too,
- * as long as spec->pins[] is set correctly
- */
-#define simple_hdmi_build_jack generic_hdmi_build_jack
-
-static int simple_playback_build_controls(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_cvt *per_cvt;
-       int err;
-
-       per_cvt = get_cvt(spec, 0);
-       err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid,
-                                         per_cvt->cvt_nid,
-                                         HDA_PCM_TYPE_HDMI);
-       if (err < 0)
-               return err;
-       return simple_hdmi_build_jack(codec, 0);
-}
-
-static int simple_playback_init(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0);
-       hda_nid_t pin = per_pin->pin_nid;
-
-       snd_hda_codec_write(codec, pin, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-       /* some codecs require to unmute the pin */
-       if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)
-               snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE,
-                                   AMP_OUT_UNMUTE);
-       snd_hda_jack_detect_enable(codec, pin, per_pin->dev_id);
-       return 0;
-}
-
-static void simple_playback_free(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-
-       hdmi_array_free(spec);
-       kfree(spec);
-}
-
-/*
- * Nvidia specific implementations
- */
-
-#define Nv_VERB_SET_Channel_Allocation          0xF79
-#define Nv_VERB_SET_Info_Frame_Checksum         0xF7A
-#define Nv_VERB_SET_Audio_Protection_On         0xF98
-#define Nv_VERB_SET_Audio_Protection_Off        0xF99
-
-#define nvhdmi_master_con_nid_7x       0x04
-#define nvhdmi_master_pin_nid_7x       0x05
-
-static const hda_nid_t nvhdmi_con_nids_7x[4] = {
-       /*front, rear, clfe, rear_surr */
-       0x6, 0x8, 0xa, 0xc,
-};
-
-static const struct hda_verb nvhdmi_basic_init_7x_2ch[] = {
-       /* set audio protect on */
-       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
-       /* enable digital output on pin widget */
-       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       {} /* terminator */
-};
-
-static const struct hda_verb nvhdmi_basic_init_7x_8ch[] = {
-       /* set audio protect on */
-       { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1},
-       /* enable digital output on pin widget */
-       { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 },
-       {} /* terminator */
-};
-
-#ifdef LIMITED_RATE_FMT_SUPPORT
-/* support only the safe format and rate */
-#define SUPPORTED_RATES                SNDRV_PCM_RATE_48000
-#define SUPPORTED_MAXBPS       16
-#define SUPPORTED_FORMATS      SNDRV_PCM_FMTBIT_S16_LE
-#else
-/* support all rates and formats */
-#define SUPPORTED_RATES \
-       (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\
-       SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\
-        SNDRV_PCM_RATE_192000)
-#define SUPPORTED_MAXBPS       24
-#define SUPPORTED_FORMATS \
-       (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S32_LE)
-#endif
-
-static int nvhdmi_7x_init_2ch(struct hda_codec *codec)
-{
-       snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_2ch);
-       return 0;
-}
-
-static int nvhdmi_7x_init_8ch(struct hda_codec *codec)
-{
-       snd_hda_sequence_write(codec, nvhdmi_basic_init_7x_8ch);
-       return 0;
-}
-
-static const unsigned int channels_2_6_8[] = {
-       2, 6, 8
-};
-
-static const unsigned int channels_2_8[] = {
-       2, 8
-};
-
-static const struct snd_pcm_hw_constraint_list hw_constraints_2_6_8_channels = {
-       .count = ARRAY_SIZE(channels_2_6_8),
-       .list = channels_2_6_8,
-       .mask = 0,
-};
-
-static const struct snd_pcm_hw_constraint_list hw_constraints_2_8_channels = {
-       .count = ARRAY_SIZE(channels_2_8),
-       .list = channels_2_8,
-       .mask = 0,
-};
-
-static int simple_playback_pcm_open(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       const struct snd_pcm_hw_constraint_list *hw_constraints_channels = NULL;
-
-       switch (codec->preset->vendor_id) {
-       case 0x10de0002:
-       case 0x10de0003:
-       case 0x10de0005:
-       case 0x10de0006:
-               hw_constraints_channels = &hw_constraints_2_8_channels;
-               break;
-       case 0x10de0007:
-               hw_constraints_channels = &hw_constraints_2_6_8_channels;
-               break;
-       default:
-               break;
-       }
-
-       if (hw_constraints_channels != NULL) {
-               snd_pcm_hw_constraint_list(substream->runtime, 0,
-                               SNDRV_PCM_HW_PARAM_CHANNELS,
-                               hw_constraints_channels);
-       } else {
-               snd_pcm_hw_constraint_step(substream->runtime, 0,
-                                          SNDRV_PCM_HW_PARAM_CHANNELS, 2);
-       }
-
-       return snd_hda_multi_out_dig_open(codec, &spec->multiout);
-}
-
-static int simple_playback_pcm_close(struct hda_pcm_stream *hinfo,
-                                    struct hda_codec *codec,
-                                    struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int simple_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                      struct hda_codec *codec,
-                                      unsigned int stream_tag,
-                                      unsigned int format,
-                                      struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       return snd_hda_multi_out_dig_prepare(codec, &spec->multiout,
-                                            stream_tag, format, substream);
-}
-
-static const struct hda_pcm_stream simple_pcm_playback = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 2,
-       .ops = {
-               .open = simple_playback_pcm_open,
-               .close = simple_playback_pcm_close,
-               .prepare = simple_playback_pcm_prepare
-       },
-};
-
-static const struct hda_codec_ops simple_hdmi_patch_ops = {
-       .build_controls = simple_playback_build_controls,
-       .build_pcms = simple_playback_build_pcms,
-       .init = simple_playback_init,
-       .free = simple_playback_free,
-       .unsol_event = simple_hdmi_unsol_event,
-};
-
-static int patch_simple_hdmi(struct hda_codec *codec,
-                            hda_nid_t cvt_nid, hda_nid_t pin_nid)
-{
-       struct hdmi_spec *spec;
-       struct hdmi_spec_per_cvt *per_cvt;
-       struct hdmi_spec_per_pin *per_pin;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-
-       spec->codec = codec;
-       codec->spec = spec;
-       hdmi_array_init(spec, 1);
-
-       spec->multiout.num_dacs = 0;  /* no analog */
-       spec->multiout.max_channels = 2;
-       spec->multiout.dig_out_nid = cvt_nid;
-       spec->num_cvts = 1;
-       spec->num_pins = 1;
-       per_pin = snd_array_new(&spec->pins);
-       per_cvt = snd_array_new(&spec->cvts);
-       if (!per_pin || !per_cvt) {
-               simple_playback_free(codec);
-               return -ENOMEM;
-       }
-       per_cvt->cvt_nid = cvt_nid;
-       per_pin->pin_nid = pin_nid;
-       spec->pcm_playback = simple_pcm_playback;
-
-       codec->patch_ops = simple_hdmi_patch_ops;
-
-       return 0;
-}
-
-static void nvhdmi_8ch_7x_set_info_frame_parameters(struct hda_codec *codec,
-                                                   int channels)
-{
-       unsigned int chanmask;
-       int chan = channels ? (channels - 1) : 1;
-
-       switch (channels) {
-       default:
-       case 0:
-       case 2:
-               chanmask = 0x00;
-               break;
-       case 4:
-               chanmask = 0x08;
-               break;
-       case 6:
-               chanmask = 0x0b;
-               break;
-       case 8:
-               chanmask = 0x13;
-               break;
-       }
-
-       /* Set the audio infoframe channel allocation and checksum fields.  The
-        * channel count is computed implicitly by the hardware. */
-       snd_hda_codec_write(codec, 0x1, 0,
-                       Nv_VERB_SET_Channel_Allocation, chanmask);
-
-       snd_hda_codec_write(codec, 0x1, 0,
-                       Nv_VERB_SET_Info_Frame_Checksum,
-                       (0x71 - chan - chanmask));
-}
-
-static int nvhdmi_8ch_7x_pcm_close(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i;
-
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x,
-                       0, AC_VERB_SET_CHANNEL_STREAMID, 0);
-       for (i = 0; i < 4; i++) {
-               /* set the stream id */
-               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
-                               AC_VERB_SET_CHANNEL_STREAMID, 0);
-               /* set the stream format */
-               snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0,
-                               AC_VERB_SET_STREAM_FORMAT, 0);
-       }
-
-       /* The audio hardware sends a channel count of 0x7 (8ch) when all the
-        * streams are disabled. */
-       nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
-
-       return snd_hda_multi_out_dig_close(codec, &spec->multiout);
-}
-
-static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                    struct hda_codec *codec,
-                                    unsigned int stream_tag,
-                                    unsigned int format,
-                                    struct snd_pcm_substream *substream)
-{
-       int chs;
-       unsigned int dataDCC2, channel_id;
-       int i;
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_spdif_out *spdif;
-       struct hdmi_spec_per_cvt *per_cvt;
-
-       mutex_lock(&codec->spdif_mutex);
-       per_cvt = get_cvt(spec, 0);
-       spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid);
-
-       chs = substream->runtime->channels;
-
-       dataDCC2 = 0x2;
-
-       /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */
-       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE))
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
-
-       /* set the stream id */
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
-                       AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0);
-
-       /* set the stream format */
-       snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0,
-                       AC_VERB_SET_STREAM_FORMAT, format);
-
-       /* turn on again (if needed) */
-       /* enable and set the channel status audio/data flag */
-       if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) {
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               spdif->ctls & 0xff);
-               snd_hda_codec_write(codec,
-                               nvhdmi_master_con_nid_7x,
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
-       }
-
-       for (i = 0; i < 4; i++) {
-               if (chs == 2)
-                       channel_id = 0;
-               else
-                       channel_id = i * 2;
-
-               /* turn off SPDIF once;
-                *otherwise the IEC958 bits won't be updated
-                */
-               if (codec->spdif_status_reset &&
-               (spdif->ctls & AC_DIG1_ENABLE))
-                       snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_DIGI_CONVERT_1,
-                               spdif->ctls & ~AC_DIG1_ENABLE & 0xff);
-               /* set the stream id */
-               snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_CHANNEL_STREAMID,
-                               (stream_tag << 4) | channel_id);
-               /* set the stream format */
-               snd_hda_codec_write(codec,
-                               nvhdmi_con_nids_7x[i],
-                               0,
-                               AC_VERB_SET_STREAM_FORMAT,
-                               format);
-               /* turn on again (if needed) */
-               /* enable and set the channel status audio/data flag */
-               if (codec->spdif_status_reset &&
-               (spdif->ctls & AC_DIG1_ENABLE)) {
-                       snd_hda_codec_write(codec,
-                                       nvhdmi_con_nids_7x[i],
-                                       0,
-                                       AC_VERB_SET_DIGI_CONVERT_1,
-                                       spdif->ctls & 0xff);
-                       snd_hda_codec_write(codec,
-                                       nvhdmi_con_nids_7x[i],
-                                       0,
-                                       AC_VERB_SET_DIGI_CONVERT_2, dataDCC2);
-               }
-       }
-
-       nvhdmi_8ch_7x_set_info_frame_parameters(codec, chs);
-
-       mutex_unlock(&codec->spdif_mutex);
-       return 0;
-}
-
-static const struct hda_pcm_stream nvhdmi_pcm_playback_8ch_7x = {
-       .substreams = 1,
-       .channels_min = 2,
-       .channels_max = 8,
-       .nid = nvhdmi_master_con_nid_7x,
-       .rates = SUPPORTED_RATES,
-       .maxbps = SUPPORTED_MAXBPS,
-       .formats = SUPPORTED_FORMATS,
-       .ops = {
-               .open = simple_playback_pcm_open,
-               .close = nvhdmi_8ch_7x_pcm_close,
-               .prepare = nvhdmi_8ch_7x_pcm_prepare
-       },
-};
-
-static int patch_nvhdmi_2ch(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int err = patch_simple_hdmi(codec, nvhdmi_master_con_nid_7x,
-                                   nvhdmi_master_pin_nid_7x);
-       if (err < 0)
-               return err;
-
-       codec->patch_ops.init = nvhdmi_7x_init_2ch;
-       /* override the PCM rates, etc, as the codec doesn't give full list */
-       spec = codec->spec;
-       spec->pcm_playback.rates = SUPPORTED_RATES;
-       spec->pcm_playback.maxbps = SUPPORTED_MAXBPS;
-       spec->pcm_playback.formats = SUPPORTED_FORMATS;
-       spec->nv_dp_workaround = true;
-       return 0;
-}
-
-static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int err = simple_playback_build_pcms(codec);
-       if (!err) {
-               struct hda_pcm *info = get_pcm_rec(spec, 0);
-               info->own_chmap = true;
-       }
-       return err;
-}
-
-static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       struct hda_pcm *info;
-       struct snd_pcm_chmap *chmap;
-       int err;
-
-       err = simple_playback_build_controls(codec);
-       if (err < 0)
-               return err;
-
-       /* add channel maps */
-       info = get_pcm_rec(spec, 0);
-       err = snd_pcm_add_chmap_ctls(info->pcm,
-                                    SNDRV_PCM_STREAM_PLAYBACK,
-                                    snd_pcm_alt_chmaps, 8, 0, &chmap);
-       if (err < 0)
-               return err;
-       switch (codec->preset->vendor_id) {
-       case 0x10de0002:
-       case 0x10de0003:
-       case 0x10de0005:
-       case 0x10de0006:
-               chmap->channel_mask = (1U << 2) | (1U << 8);
-               break;
-       case 0x10de0007:
-               chmap->channel_mask = (1U << 2) | (1U << 6) | (1U << 8);
-       }
-       return 0;
-}
-
-static int patch_nvhdmi_8ch_7x(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int err = patch_nvhdmi_2ch(codec);
-       if (err < 0)
-               return err;
-       spec = codec->spec;
-       spec->multiout.max_channels = 8;
-       spec->pcm_playback = nvhdmi_pcm_playback_8ch_7x;
-       codec->patch_ops.init = nvhdmi_7x_init_8ch;
-       codec->patch_ops.build_pcms = nvhdmi_7x_8ch_build_pcms;
-       codec->patch_ops.build_controls = nvhdmi_7x_8ch_build_controls;
-
-       /* Initialize the audio infoframe channel mask and checksum to something
-        * valid */
-       nvhdmi_8ch_7x_set_info_frame_parameters(codec, 8);
-
-       return 0;
-}
-
-/*
- * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on:
- * - 0x10de0015
- * - 0x10de0040
- */
-static int nvhdmi_chmap_cea_alloc_validate_get_type(struct hdac_chmap *chmap,
-               struct hdac_cea_channel_speaker_allocation *cap, int channels)
-{
-       if (cap->ca_index == 0x00 && channels == 2)
-               return SNDRV_CTL_TLVT_CHMAP_FIXED;
-
-       /* If the speaker allocation matches the channel count, it is OK. */
-       if (cap->channels != channels)
-               return -1;
-
-       /* all channels are remappable freely */
-       return SNDRV_CTL_TLVT_CHMAP_VAR;
-}
-
-static int nvhdmi_chmap_validate(struct hdac_chmap *chmap,
-               int ca, int chs, unsigned char *map)
-{
-       if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR))
-               return -EINVAL;
-
-       return 0;
-}
-
-/* map from pin NID to port; port is 0-based */
-/* for Nvidia: assume widget NID starting from 4, with step 1 (4, 5, 6, ...) */
-static int nvhdmi_pin2port(void *audio_ptr, int pin_nid)
-{
-       return pin_nid - 4;
-}
-
-/* reverse-map from port to pin NID: see above */
-static int nvhdmi_port2pin(struct hda_codec *codec, int port)
-{
-       return port + 4;
-}
-
-static const struct drm_audio_component_audio_ops nvhdmi_audio_ops = {
-       .pin2port = nvhdmi_pin2port,
-       .pin_eld_notify = generic_acomp_pin_eld_notify,
-       .master_bind = generic_acomp_master_bind,
-       .master_unbind = generic_acomp_master_unbind,
-};
-
-static int patch_nvhdmi(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int err;
-
-       err = alloc_generic_hdmi(codec);
-       if (err < 0)
-               return err;
-       codec->dp_mst = true;
-
-       spec = codec->spec;
-
-       err = hdmi_parse_codec(codec);
-       if (err < 0) {
-               generic_spec_free(codec);
-               return err;
-       }
-
-       generic_hdmi_init_per_pins(codec);
-
-       spec->dyn_pin_out = true;
-
-       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-               nvhdmi_chmap_cea_alloc_validate_get_type;
-       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-       spec->nv_dp_workaround = true;
-
-       codec->link_down_at_suspend = 1;
-
-       generic_acomp_init(codec, &nvhdmi_audio_ops, nvhdmi_port2pin);
-
-       return 0;
-}
-
-static int patch_nvhdmi_legacy(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int err;
-
-       err = patch_generic_hdmi(codec);
-       if (err)
-               return err;
-
-       spec = codec->spec;
-       spec->dyn_pin_out = true;
-
-       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-               nvhdmi_chmap_cea_alloc_validate_get_type;
-       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-       spec->nv_dp_workaround = true;
-
-       codec->link_down_at_suspend = 1;
-
-       return 0;
-}
-
-/*
- * The HDA codec on NVIDIA Tegra contains two scratch registers that are
- * accessed using vendor-defined verbs. These registers can be used for
- * interoperability between the HDA and HDMI drivers.
- */
-
-/* Audio Function Group node */
-#define NVIDIA_AFG_NID 0x01
-
-/*
- * The SCRATCH0 register is used to notify the HDMI codec of changes in audio
- * format. On Tegra, bit 31 is used as a trigger that causes an interrupt to
- * be raised in the HDMI codec. The remainder of the bits is arbitrary. This
- * implementation stores the HDA format (see AC_FMT_*) in bits [15:0] and an
- * additional bit (at position 30) to signal the validity of the format.
- *
- * | 31      | 30    | 29  16 | 15   0 |
- * +---------+-------+--------+--------+
- * | TRIGGER | VALID | UNUSED | FORMAT |
- * +-----------------------------------|
- *
- * Note that for the trigger bit to take effect it needs to change value
- * (i.e. it needs to be toggled). The trigger bit is not applicable from
- * TEGRA234 chip onwards, as new verb id 0xf80 will be used for interrupt
- * trigger to hdmi.
- */
-#define NVIDIA_SET_HOST_INTR           0xf80
-#define NVIDIA_GET_SCRATCH0            0xfa6
-#define NVIDIA_SET_SCRATCH0_BYTE0      0xfa7
-#define NVIDIA_SET_SCRATCH0_BYTE1      0xfa8
-#define NVIDIA_SET_SCRATCH0_BYTE2      0xfa9
-#define NVIDIA_SET_SCRATCH0_BYTE3      0xfaa
-#define NVIDIA_SCRATCH_TRIGGER (1 << 7)
-#define NVIDIA_SCRATCH_VALID   (1 << 6)
-
-#define NVIDIA_GET_SCRATCH1            0xfab
-#define NVIDIA_SET_SCRATCH1_BYTE0      0xfac
-#define NVIDIA_SET_SCRATCH1_BYTE1      0xfad
-#define NVIDIA_SET_SCRATCH1_BYTE2      0xfae
-#define NVIDIA_SET_SCRATCH1_BYTE3      0xfaf
-
-/*
- * The format parameter is the HDA audio format (see AC_FMT_*). If set to 0,
- * the format is invalidated so that the HDMI codec can be disabled.
- */
-static void tegra_hdmi_set_format(struct hda_codec *codec,
-                                 hda_nid_t cvt_nid,
-                                 unsigned int format)
-{
-       unsigned int value;
-       unsigned int nid = NVIDIA_AFG_NID;
-       struct hdmi_spec *spec = codec->spec;
-
-       /*
-        * Tegra HDA codec design from TEGRA234 chip onwards support DP MST.
-        * This resulted in moving scratch registers from audio function
-        * group to converter widget context. So CVT NID should be used for
-        * scratch register read/write for DP MST supported Tegra HDA codec.
-        */
-       if (codec->dp_mst)
-               nid = cvt_nid;
-
-       /* bits [31:30] contain the trigger and valid bits */
-       value = snd_hda_codec_read(codec, nid, 0,
-                                  NVIDIA_GET_SCRATCH0, 0);
-       value = (value >> 24) & 0xff;
-
-       /* bits [15:0] are used to store the HDA format */
-       snd_hda_codec_write(codec, nid, 0,
-                           NVIDIA_SET_SCRATCH0_BYTE0,
-                           (format >> 0) & 0xff);
-       snd_hda_codec_write(codec, nid, 0,
-                           NVIDIA_SET_SCRATCH0_BYTE1,
-                           (format >> 8) & 0xff);
-
-       /* bits [16:24] are unused */
-       snd_hda_codec_write(codec, nid, 0,
-                           NVIDIA_SET_SCRATCH0_BYTE2, 0);
-
-       /*
-        * Bit 30 signals that the data is valid and hence that HDMI audio can
-        * be enabled.
-        */
-       if (format == 0)
-               value &= ~NVIDIA_SCRATCH_VALID;
-       else
-               value |= NVIDIA_SCRATCH_VALID;
-
-       if (spec->hdmi_intr_trig_ctrl) {
-               /*
-                * For Tegra HDA Codec design from TEGRA234 onwards, the
-                * Interrupt to hdmi driver is triggered by writing
-                * non-zero values to verb 0xF80 instead of 31st bit of
-                * scratch register.
-                */
-               snd_hda_codec_write(codec, nid, 0,
-                               NVIDIA_SET_SCRATCH0_BYTE3, value);
-               snd_hda_codec_write(codec, nid, 0,
-                               NVIDIA_SET_HOST_INTR, 0x1);
-       } else {
-               /*
-                * Whenever the 31st trigger bit is toggled, an interrupt is raised
-                * in the HDMI codec. The HDMI driver will use that as trigger
-                * to update its configuration.
-                */
-               value ^= NVIDIA_SCRATCH_TRIGGER;
-
-               snd_hda_codec_write(codec, nid, 0,
-                               NVIDIA_SET_SCRATCH0_BYTE3, value);
-       }
-}
-
-static int tegra_hdmi_pcm_prepare(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 unsigned int stream_tag,
-                                 unsigned int format,
-                                 struct snd_pcm_substream *substream)
-{
-       int err;
-
-       err = generic_hdmi_playback_pcm_prepare(hinfo, codec, stream_tag,
-                                               format, substream);
-       if (err < 0)
-               return err;
-
-       /* notify the HDMI codec of the format change */
-       tegra_hdmi_set_format(codec, hinfo->nid, format);
-
-       return 0;
-}
-
-static int tegra_hdmi_pcm_cleanup(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 struct snd_pcm_substream *substream)
-{
-       /* invalidate the format in the HDMI codec */
-       tegra_hdmi_set_format(codec, hinfo->nid, 0);
-
-       return generic_hdmi_playback_pcm_cleanup(hinfo, codec, substream);
-}
-
-static struct hda_pcm *hda_find_pcm_by_type(struct hda_codec *codec, int type)
-{
-       struct hdmi_spec *spec = codec->spec;
-       unsigned int i;
-
-       for (i = 0; i < spec->num_pins; i++) {
-               struct hda_pcm *pcm = get_pcm_rec(spec, i);
-
-               if (pcm->pcm_type == type)
-                       return pcm;
-       }
-
-       return NULL;
-}
-
-static int tegra_hdmi_build_pcms(struct hda_codec *codec)
-{
-       struct hda_pcm_stream *stream;
-       struct hda_pcm *pcm;
-       int err;
-
-       err = generic_hdmi_build_pcms(codec);
-       if (err < 0)
-               return err;
-
-       pcm = hda_find_pcm_by_type(codec, HDA_PCM_TYPE_HDMI);
-       if (!pcm)
-               return -ENODEV;
-
-       /*
-        * Override ->prepare() and ->cleanup() operations to notify the HDMI
-        * codec about format changes.
-        */
-       stream = &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK];
-       stream->ops.prepare = tegra_hdmi_pcm_prepare;
-       stream->ops.cleanup = tegra_hdmi_pcm_cleanup;
-
-       return 0;
-}
-
-static int tegra_hdmi_init(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int i, err;
-
-       err = hdmi_parse_codec(codec);
-       if (err < 0) {
-               generic_spec_free(codec);
-               return err;
-       }
-
-       for (i = 0; i < spec->num_cvts; i++)
-               snd_hda_codec_write(codec, spec->cvt_nids[i], 0,
-                                       AC_VERB_SET_DIGI_CONVERT_1,
-                                       AC_DIG1_ENABLE);
-
-       generic_hdmi_init_per_pins(codec);
-
-       codec->depop_delay = 10;
-       codec->patch_ops.build_pcms = tegra_hdmi_build_pcms;
-       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-               nvhdmi_chmap_cea_alloc_validate_get_type;
-       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-
-       spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-               nvhdmi_chmap_cea_alloc_validate_get_type;
-       spec->chmap.ops.chmap_validate = nvhdmi_chmap_validate;
-       spec->nv_dp_workaround = true;
-
-       return 0;
-}
-
-static int patch_tegra_hdmi(struct hda_codec *codec)
-{
-       int err;
-
-       err = alloc_generic_hdmi(codec);
-       if (err < 0)
-               return err;
-
-       return tegra_hdmi_init(codec);
-}
-
-static int patch_tegra234_hdmi(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       int err;
-
-       err = alloc_generic_hdmi(codec);
-       if (err < 0)
-               return err;
-
-       codec->dp_mst = true;
-       spec = codec->spec;
-       spec->dyn_pin_out = true;
-       spec->hdmi_intr_trig_ctrl = true;
-
-       return tegra_hdmi_init(codec);
-}
-
-/*
- * ATI/AMD-specific implementations
- */
-
-#define is_amdhdmi_rev3_or_later(codec) \
-       ((codec)->core.vendor_id == 0x1002aa01 && \
-        ((codec)->core.revision_id & 0xff00) >= 0x0300)
-#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec)
-
-/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */
-#define ATI_VERB_SET_CHANNEL_ALLOCATION        0x771
-#define ATI_VERB_SET_DOWNMIX_INFO      0x772
-#define ATI_VERB_SET_MULTICHANNEL_01   0x777
-#define ATI_VERB_SET_MULTICHANNEL_23   0x778
-#define ATI_VERB_SET_MULTICHANNEL_45   0x779
-#define ATI_VERB_SET_MULTICHANNEL_67   0x77a
-#define ATI_VERB_SET_HBR_CONTROL       0x77c
-#define ATI_VERB_SET_MULTICHANNEL_1    0x785
-#define ATI_VERB_SET_MULTICHANNEL_3    0x786
-#define ATI_VERB_SET_MULTICHANNEL_5    0x787
-#define ATI_VERB_SET_MULTICHANNEL_7    0x788
-#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789
-#define ATI_VERB_GET_CHANNEL_ALLOCATION        0xf71
-#define ATI_VERB_GET_DOWNMIX_INFO      0xf72
-#define ATI_VERB_GET_MULTICHANNEL_01   0xf77
-#define ATI_VERB_GET_MULTICHANNEL_23   0xf78
-#define ATI_VERB_GET_MULTICHANNEL_45   0xf79
-#define ATI_VERB_GET_MULTICHANNEL_67   0xf7a
-#define ATI_VERB_GET_HBR_CONTROL       0xf7c
-#define ATI_VERB_GET_MULTICHANNEL_1    0xf85
-#define ATI_VERB_GET_MULTICHANNEL_3    0xf86
-#define ATI_VERB_GET_MULTICHANNEL_5    0xf87
-#define ATI_VERB_GET_MULTICHANNEL_7    0xf88
-#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89
-
-/* AMD specific HDA cvt verbs */
-#define ATI_VERB_SET_RAMP_RATE         0x770
-#define ATI_VERB_GET_RAMP_RATE         0xf70
-
-#define ATI_OUT_ENABLE 0x1
-
-#define ATI_MULTICHANNEL_MODE_PAIRED   0
-#define ATI_MULTICHANNEL_MODE_SINGLE   1
-
-#define ATI_HBR_CAPABLE 0x01
-#define ATI_HBR_ENABLE 0x10
-
-static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid,
-                              int dev_id, unsigned char *buf, int *eld_size)
-{
-       WARN_ON(dev_id != 0);
-       /* call hda_eld.c ATI/AMD-specific function */
-       return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size,
-                                   is_amdhdmi_rev3_or_later(codec));
-}
-
-static void atihdmi_pin_setup_infoframe(struct hda_codec *codec,
-                                       hda_nid_t pin_nid, int dev_id, int ca,
-                                       int active_channels, int conn_type)
-{
-       WARN_ON(dev_id != 0);
-       snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca);
-}
-
-static int atihdmi_paired_swap_fc_lfe(int pos)
-{
-       /*
-        * ATI/AMD have automatic FC/LFE swap built-in
-        * when in pairwise mapping mode.
-        */
-
-       switch (pos) {
-               /* see channel_allocations[].speakers[] */
-               case 2: return 3;
-               case 3: return 2;
-               default: break;
-       }
-
-       return pos;
-}
-
-static int atihdmi_paired_chmap_validate(struct hdac_chmap *chmap,
-                       int ca, int chs, unsigned char *map)
-{
-       struct hdac_cea_channel_speaker_allocation *cap;
-       int i, j;
-
-       /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */
-
-       cap = snd_hdac_get_ch_alloc_from_ca(ca);
-       for (i = 0; i < chs; ++i) {
-               int mask = snd_hdac_chmap_to_spk_mask(map[i]);
-               bool ok = false;
-               bool companion_ok = false;
-
-               if (!mask)
-                       continue;
-
-               for (j = 0 + i % 2; j < 8; j += 2) {
-                       int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j);
-                       if (cap->speakers[chan_idx] == mask) {
-                               /* channel is in a supported position */
-                               ok = true;
-
-                               if (i % 2 == 0 && i + 1 < chs) {
-                                       /* even channel, check the odd companion */
-                                       int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1);
-                                       int comp_mask_req = snd_hdac_chmap_to_spk_mask(map[i+1]);
-                                       int comp_mask_act = cap->speakers[comp_chan_idx];
-
-                                       if (comp_mask_req == comp_mask_act)
-                                               companion_ok = true;
-                                       else
-                                               return -EINVAL;
-                               }
-                               break;
-                       }
-               }
-
-               if (!ok)
-                       return -EINVAL;
-
-               if (companion_ok)
-                       i++; /* companion channel already checked */
-       }
-
-       return 0;
-}
-
-static int atihdmi_pin_set_slot_channel(struct hdac_device *hdac,
-               hda_nid_t pin_nid, int hdmi_slot, int stream_channel)
-{
-       struct hda_codec *codec = hdac_to_hda_codec(hdac);
-       int verb;
-       int ati_channel_setup = 0;
-
-       if (hdmi_slot > 7)
-               return -EINVAL;
-
-       if (!has_amd_full_remap_support(codec)) {
-               hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot);
-
-               /* In case this is an odd slot but without stream channel, do not
-                * disable the slot since the corresponding even slot could have a
-                * channel. In case neither have a channel, the slot pair will be
-                * disabled when this function is called for the even slot. */
-               if (hdmi_slot % 2 != 0 && stream_channel == 0xf)
-                       return 0;
-
-               hdmi_slot -= hdmi_slot % 2;
-
-               if (stream_channel != 0xf)
-                       stream_channel -= stream_channel % 2;
-       }
-
-       verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e;
-
-       /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */
-
-       if (stream_channel != 0xf)
-               ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE;
-
-       return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup);
-}
-
-static int atihdmi_pin_get_slot_channel(struct hdac_device *hdac,
-                               hda_nid_t pin_nid, int asp_slot)
-{
-       struct hda_codec *codec = hdac_to_hda_codec(hdac);
-       bool was_odd = false;
-       int ati_asp_slot = asp_slot;
-       int verb;
-       int ati_channel_setup;
-
-       if (asp_slot > 7)
-               return -EINVAL;
-
-       if (!has_amd_full_remap_support(codec)) {
-               ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot);
-               if (ati_asp_slot % 2 != 0) {
-                       ati_asp_slot -= 1;
-                       was_odd = true;
-               }
-       }
-
-       verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e;
-
-       ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0);
-
-       if (!(ati_channel_setup & ATI_OUT_ENABLE))
-               return 0xf;
-
-       return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd;
-}
-
-static int atihdmi_paired_chmap_cea_alloc_validate_get_type(
-               struct hdac_chmap *chmap,
-               struct hdac_cea_channel_speaker_allocation *cap,
-               int channels)
-{
-       int c;
-
-       /*
-        * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so
-        * we need to take that into account (a single channel may take 2
-        * channel slots if we need to carry a silent channel next to it).
-        * On Rev3+ AMD codecs this function is not used.
-        */
-       int chanpairs = 0;
-
-       /* We only produce even-numbered channel count TLVs */
-       if ((channels % 2) != 0)
-               return -1;
-
-       for (c = 0; c < 7; c += 2) {
-               if (cap->speakers[c] || cap->speakers[c+1])
-                       chanpairs++;
-       }
-
-       if (chanpairs * 2 != channels)
-               return -1;
-
-       return SNDRV_CTL_TLVT_CHMAP_PAIRED;
-}
-
-static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct hdac_chmap *hchmap,
-               struct hdac_cea_channel_speaker_allocation *cap,
-               unsigned int *chmap, int channels)
-{
-       /* produce paired maps for pre-rev3 ATI/AMD codecs */
-       int count = 0;
-       int c;
-
-       for (c = 7; c >= 0; c--) {
-               int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c);
-               int spk = cap->speakers[chan];
-               if (!spk) {
-                       /* add N/A channel if the companion channel is occupied */
-                       if (cap->speakers[chan + (chan % 2 ? -1 : 1)])
-                               chmap[count++] = SNDRV_CHMAP_NA;
-
-                       continue;
-               }
-
-               chmap[count++] = snd_hdac_spk_to_chmap(spk);
-       }
-
-       WARN_ON(count != channels);
-}
-
-static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid,
-                                int dev_id, bool hbr)
-{
-       int hbr_ctl, hbr_ctl_new;
-
-       WARN_ON(dev_id != 0);
-
-       hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0);
-       if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) {
-               if (hbr)
-                       hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE;
-               else
-                       hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE;
-
-               codec_dbg(codec,
-                         "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n",
-                               pin_nid,
-                               hbr_ctl == hbr_ctl_new ? "" : "new-",
-                               hbr_ctl_new);
-
-               if (hbr_ctl != hbr_ctl_new)
-                       snd_hda_codec_write(codec, pin_nid, 0,
-                                               ATI_VERB_SET_HBR_CONTROL,
-                                               hbr_ctl_new);
-
-       } else if (hbr)
-               return -EINVAL;
-
-       return 0;
-}
-
-static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid,
-                               hda_nid_t pin_nid, int dev_id,
-                               u32 stream_tag, int format)
-{
-       if (is_amdhdmi_rev3_or_later(codec)) {
-               int ramp_rate = 180; /* default as per AMD spec */
-               /* disable ramp-up/down for non-pcm as per AMD spec */
-               if (format & AC_FMT_TYPE_NON_PCM)
-                       ramp_rate = 0;
-
-               snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate);
-       }
-
-       return hdmi_setup_stream(codec, cvt_nid, pin_nid, dev_id,
-                                stream_tag, format);
-}
-
-
-static int atihdmi_init(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec = codec->spec;
-       int pin_idx, err;
-
-       err = generic_hdmi_init(codec);
-
-       if (err)
-               return err;
-
-       for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
-               struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
-
-               /* make sure downmix information in infoframe is zero */
-               snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0);
-
-               /* enable channel-wise remap mode if supported */
-               if (has_amd_full_remap_support(codec))
-                       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
-                                           ATI_VERB_SET_MULTICHANNEL_MODE,
-                                           ATI_MULTICHANNEL_MODE_SINGLE);
-       }
-       codec->auto_runtime_pm = 1;
-
-       return 0;
-}
-
-/* map from pin NID to port; port is 0-based */
-/* for AMD: assume widget NID starting from 3, with step 2 (3, 5, 7, ...) */
-static int atihdmi_pin2port(void *audio_ptr, int pin_nid)
-{
-       return pin_nid / 2 - 1;
-}
-
-/* reverse-map from port to pin NID: see above */
-static int atihdmi_port2pin(struct hda_codec *codec, int port)
-{
-       return port * 2 + 3;
-}
-
-static const struct drm_audio_component_audio_ops atihdmi_audio_ops = {
-       .pin2port = atihdmi_pin2port,
-       .pin_eld_notify = generic_acomp_pin_eld_notify,
-       .master_bind = generic_acomp_master_bind,
-       .master_unbind = generic_acomp_master_unbind,
-};
-
-static int patch_atihdmi(struct hda_codec *codec)
-{
-       struct hdmi_spec *spec;
-       struct hdmi_spec_per_cvt *per_cvt;
-       int err, cvt_idx;
-
-       err = patch_generic_hdmi(codec);
-
-       if (err)
-               return err;
-
-       codec->patch_ops.init = atihdmi_init;
-
-       spec = codec->spec;
-
-       spec->static_pcm_mapping = true;
-
-       spec->ops.pin_get_eld = atihdmi_pin_get_eld;
-       spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe;
-       spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup;
-       spec->ops.setup_stream = atihdmi_setup_stream;
-
-       spec->chmap.ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel;
-       spec->chmap.ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel;
-
-       if (!has_amd_full_remap_support(codec)) {
-               /* override to ATI/AMD-specific versions with pairwise mapping */
-               spec->chmap.ops.chmap_cea_alloc_validate_get_type =
-                       atihdmi_paired_chmap_cea_alloc_validate_get_type;
-               spec->chmap.ops.cea_alloc_to_tlv_chmap =
-                               atihdmi_paired_cea_alloc_to_tlv_chmap;
-               spec->chmap.ops.chmap_validate = atihdmi_paired_chmap_validate;
-       }
-
-       /* ATI/AMD converters do not advertise all of their capabilities */
-       for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
-               per_cvt = get_cvt(spec, cvt_idx);
-               per_cvt->channels_max = max(per_cvt->channels_max, 8u);
-               per_cvt->rates |= SUPPORTED_RATES;
-               per_cvt->formats |= SUPPORTED_FORMATS;
-               per_cvt->maxbps = max(per_cvt->maxbps, 24u);
-       }
-
-       spec->chmap.channels_max = max(spec->chmap.channels_max, 8u);
-
-       /* AMD GPUs have neither EPSS nor CLKSTOP bits, hence preventing
-        * the link-down as is.  Tell the core to allow it.
-        */
-       codec->link_down_at_suspend = 1;
-
-       generic_acomp_init(codec, &atihdmi_audio_ops, atihdmi_port2pin);
-
-       return 0;
-}
-
-/* VIA HDMI Implementation */
-#define VIAHDMI_CVT_NID        0x02    /* audio converter1 */
-#define VIAHDMI_PIN_NID        0x03    /* HDMI output pin1 */
-
-static int patch_via_hdmi(struct hda_codec *codec)
-{
-       return patch_simple_hdmi(codec, VIAHDMI_CVT_NID, VIAHDMI_PIN_NID);
-}
-
-static int patch_gf_hdmi(struct hda_codec *codec)
-{
-       int err;
-
-       err = patch_generic_hdmi(codec);
-       if (err)
-               return err;
-
-       /*
-        * Glenfly GPUs have two codecs, stream switches from one codec to
-        * another, need to do actual clean-ups in codec_cleanup_stream
-        */
-       codec->no_sticky_stream = 1;
-       return 0;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_hdmi[] = {
-HDA_CODEC_ENTRY(0x00147a47, "Loongson HDMI",   patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x1002793c, "RS600 HDMI",      patch_atihdmi),
-HDA_CODEC_ENTRY(0x10027919, "RS600 HDMI",      patch_atihdmi),
-HDA_CODEC_ENTRY(0x1002791a, "RS690/780 HDMI",  patch_atihdmi),
-HDA_CODEC_ENTRY(0x1002aa01, "R6xx HDMI",       patch_atihdmi),
-HDA_CODEC_ENTRY(0x10951390, "SiI1390 HDMI",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x10951392, "SiI1392 HDMI",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x17e80047, "Chrontel HDMI",   patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x10de0001, "MCP73 HDMI",      patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de0002, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0003, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0004, "GPU 04 HDMI",     patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0005, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0006, "MCP77/78 HDMI",   patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0007, "MCP79/7A HDMI",   patch_nvhdmi_8ch_7x),
-HDA_CODEC_ENTRY(0x10de0008, "GPU 08 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0009, "GPU 09 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000a, "GPU 0a HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000b, "GPU 0b HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000c, "MCP89 HDMI",      patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de000d, "GPU 0d HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0010, "GPU 10 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0011, "GPU 11 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0012, "GPU 12 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0013, "GPU 13 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0014, "GPU 14 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0015, "GPU 15 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0016, "GPU 16 HDMI/DP",  patch_nvhdmi_legacy),
-/* 17 is known to be absent */
-HDA_CODEC_ENTRY(0x10de0018, "GPU 18 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0019, "GPU 19 HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001a, "GPU 1a HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001b, "GPU 1b HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de001c, "GPU 1c HDMI/DP",  patch_nvhdmi_legacy),
-HDA_CODEC_ENTRY(0x10de0020, "Tegra30 HDMI",    patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0022, "Tegra114 HDMI",   patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0028, "Tegra124 HDMI",   patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0029, "Tegra210 HDMI/DP",        patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002d, "Tegra186 HDMI/DP0", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002e, "Tegra186 HDMI/DP1", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de002f, "Tegra194 HDMI/DP2", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0030, "Tegra194 HDMI/DP3", patch_tegra_hdmi),
-HDA_CODEC_ENTRY(0x10de0031, "Tegra234 HDMI/DP", patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0033, "SoC 33 HDMI/DP",  patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0034, "Tegra264 HDMI/DP",        patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0035, "SoC 35 HDMI/DP",  patch_tegra234_hdmi),
-HDA_CODEC_ENTRY(0x10de0040, "GPU 40 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0041, "GPU 41 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0042, "GPU 42 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0043, "GPU 43 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0044, "GPU 44 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0045, "GPU 45 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0050, "GPU 50 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0051, "GPU 51 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0052, "GPU 52 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0060, "GPU 60 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0061, "GPU 61 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0062, "GPU 62 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0067, "MCP67 HDMI",      patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de0070, "GPU 70 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0071, "GPU 71 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0072, "GPU 72 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0073, "GPU 73 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0074, "GPU 74 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0076, "GPU 76 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007b, "GPU 7b HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007c, "GPU 7c HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007d, "GPU 7d HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de007e, "GPU 7e HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0080, "GPU 80 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0081, "GPU 81 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0082, "GPU 82 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0083, "GPU 83 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0084, "GPU 84 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0090, "GPU 90 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0091, "GPU 91 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0092, "GPU 92 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0093, "GPU 93 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0094, "GPU 94 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0095, "GPU 95 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0097, "GPU 97 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0098, "GPU 98 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de0099, "GPU 99 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009a, "GPU 9a HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009b, "GPU 9b HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009c, "GPU 9c HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009d, "GPU 9d HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009e, "GPU 9e HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de009f, "GPU 9f HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a0, "GPU a0 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a1, "GPU a1 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a3, "GPU a3 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a4, "GPU a4 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a5, "GPU a5 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a6, "GPU a6 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a7, "GPU a7 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a8, "GPU a8 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00a9, "GPU a9 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00aa, "GPU aa HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ab, "GPU ab HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ad, "GPU ad HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00ae, "GPU ae HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00af, "GPU af HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00b0, "GPU b0 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00b1, "GPU b1 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c0, "GPU c0 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c1, "GPU c1 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c3, "GPU c3 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c4, "GPU c4 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de00c5, "GPU c5 HDMI/DP",  patch_nvhdmi),
-HDA_CODEC_ENTRY(0x10de8001, "MCP73 HDMI",      patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x10de8067, "MCP67/68 HDMI",   patch_nvhdmi_2ch),
-HDA_CODEC_ENTRY(0x67663d82, "Arise 82 HDMI/DP",        patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d83, "Arise 83 HDMI/DP",        patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d84, "Arise 84 HDMI/DP",        patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d85, "Arise 85 HDMI/DP",        patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d86, "Arise 86 HDMI/DP",        patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x67663d87, "Arise 87 HDMI/DP",        patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x11069f80, "VX900 HDMI/DP",   patch_via_hdmi),
-HDA_CODEC_ENTRY(0x11069f81, "VX900 HDMI/DP",   patch_via_hdmi),
-HDA_CODEC_ENTRY(0x11069f84, "VX11 HDMI/DP",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x11069f85, "VX11 HDMI/DP",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x1d179f86, "ZX-100S HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f87, "ZX-100S HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f88, "KX-5000 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f89, "KX-5000 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8a, "KX-6000 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8b, "KX-6000 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8c, "KX-6000G HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8d, "KX-6000G HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8e, "KX-7000 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f8f, "KX-7000 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x1d179f90, "KX-7000 HDMI/DP", patch_gf_hdmi),
-HDA_CODEC_ENTRY(0x80860054, "IbexPeak HDMI",   patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862800, "Geminilake HDMI", patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x80862801, "Bearlake HDMI",   patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862802, "Cantiga HDMI",    patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862803, "Eaglelake HDMI",  patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862804, "IbexPeak HDMI",   patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862805, "CougarPoint HDMI",        patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862806, "PantherPoint HDMI", patch_i915_cpt_hdmi),
-HDA_CODEC_ENTRY(0x80862807, "Haswell HDMI",    patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x80862808, "Broadwell HDMI",  patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x80862809, "Skylake HDMI",    patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280a, "Broxton HDMI",    patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280b, "Kabylake HDMI",   patch_i915_hsw_hdmi),
-HDA_CODEC_ENTRY(0x8086280c, "Cannonlake HDMI", patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x8086280d, "Geminilake HDMI", patch_i915_glk_hdmi),
-HDA_CODEC_ENTRY(0x8086280f, "Icelake HDMI",    patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x80862812, "Tigerlake HDMI",  patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862814, "DG1 HDMI",        patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862815, "Alderlake HDMI",  patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862816, "Rocketlake HDMI", patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862818, "Raptorlake HDMI", patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x80862819, "DG2 HDMI",        patch_i915_tgl_hdmi),
-HDA_CODEC_ENTRY(0x8086281a, "Jasperlake HDMI", patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x8086281b, "Elkhartlake HDMI",        patch_i915_icl_hdmi),
-HDA_CODEC_ENTRY(0x8086281c, "Alderlake-P HDMI", patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281d, "Meteor Lake HDMI",        patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281e, "Battlemage HDMI", patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x8086281f, "Raptor Lake P HDMI",      patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862820, "Lunar Lake HDMI", patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862822, "Panther Lake HDMI",       patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862823, "Wildcat Lake HDMI",       patch_i915_adlp_hdmi),
-HDA_CODEC_ENTRY(0x80862880, "CedarTrail HDMI", patch_generic_hdmi),
-HDA_CODEC_ENTRY(0x80862882, "Valleyview2 HDMI",        patch_i915_byt_hdmi),
-HDA_CODEC_ENTRY(0x80862883, "Braswell HDMI",   patch_i915_byt_hdmi),
-HDA_CODEC_ENTRY(0x808629fb, "Crestline HDMI",  patch_generic_hdmi),
-/* special ID for generic HDMI */
-HDA_CODEC_ENTRY(HDA_CODEC_ID_GENERIC_HDMI, "Generic HDMI", patch_generic_hdmi),
-{} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_hdmi);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("HDMI HD-audio codec");
-MODULE_ALIAS("snd-hda-codec-intelhdmi");
-MODULE_ALIAS("snd-hda-codec-nvhdmi");
-MODULE_ALIAS("snd-hda-codec-atihdmi");
-
-static struct hda_codec_driver hdmi_driver = {
-       .id = snd_hda_id_hdmi,
-};
-
-module_hda_codec_driver(hdmi_driver);
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
deleted file mode 100644 (file)
index 936c347..0000000
+++ /dev/null
@@ -1,13795 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for Realtek ALC codecs
- *
- * Copyright (c) 2004 Kailang Yang <kailang@realtek.com.tw>
- *                    PeiSen Hou <pshou@realtek.com.tw>
- *                    Takashi Iwai <tiwai@suse.de>
- *                    Jonathan Woithe <jwoithe@just42.net>
- */
-
-#include <linux/acpi.h>
-#include <linux/cleanup.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/dmi.h>
-#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/input.h>
-#include <linux/leds.h>
-#include <linux/ctype.h>
-#include <linux/spi/spi.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_beep.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-#include "hda_component.h"
-
-/* keep halting ALC5505 DSP, for power saving */
-#define HALT_REALTEK_ALC5505
-
-/* extra amp-initialization sequence types */
-enum {
-       ALC_INIT_UNDEFINED,
-       ALC_INIT_NONE,
-       ALC_INIT_DEFAULT,
-};
-
-enum {
-       ALC_HEADSET_MODE_UNKNOWN,
-       ALC_HEADSET_MODE_UNPLUGGED,
-       ALC_HEADSET_MODE_HEADSET,
-       ALC_HEADSET_MODE_MIC,
-       ALC_HEADSET_MODE_HEADPHONE,
-};
-
-enum {
-       ALC_HEADSET_TYPE_UNKNOWN,
-       ALC_HEADSET_TYPE_CTIA,
-       ALC_HEADSET_TYPE_OMTP,
-};
-
-enum {
-       ALC_KEY_MICMUTE_INDEX,
-};
-
-struct alc_customize_define {
-       unsigned int  sku_cfg;
-       unsigned char port_connectivity;
-       unsigned char check_sum;
-       unsigned char customization;
-       unsigned char external_amp;
-       unsigned int  enable_pcbeep:1;
-       unsigned int  platform_type:1;
-       unsigned int  swap:1;
-       unsigned int  override:1;
-       unsigned int  fixup:1; /* Means that this sku is set by driver, not read from hw */
-};
-
-struct alc_coef_led {
-       unsigned int idx;
-       unsigned int mask;
-       unsigned int on;
-       unsigned int off;
-};
-
-struct alc_spec {
-       struct hda_gen_spec gen; /* must be at head */
-
-       /* codec parameterization */
-       struct alc_customize_define cdefine;
-       unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
-
-       /* GPIO bits */
-       unsigned int gpio_mask;
-       unsigned int gpio_dir;
-       unsigned int gpio_data;
-       bool gpio_write_delay;  /* add a delay before writing gpio_data */
-
-       /* mute LED for HP laptops, see vref_mute_led_set() */
-       int mute_led_polarity;
-       int micmute_led_polarity;
-       hda_nid_t mute_led_nid;
-       hda_nid_t cap_mute_led_nid;
-
-       unsigned int gpio_mute_led_mask;
-       unsigned int gpio_mic_led_mask;
-       struct alc_coef_led mute_led_coef;
-       struct alc_coef_led mic_led_coef;
-       struct mutex coef_mutex;
-
-       hda_nid_t headset_mic_pin;
-       hda_nid_t headphone_mic_pin;
-       int current_headset_mode;
-       int current_headset_type;
-
-       /* hooks */
-       void (*init_hook)(struct hda_codec *codec);
-       void (*power_hook)(struct hda_codec *codec);
-       void (*shutup)(struct hda_codec *codec);
-
-       int init_amp;
-       int codec_variant;      /* flag for other variants */
-       unsigned int has_alc5505_dsp:1;
-       unsigned int no_depop_delay:1;
-       unsigned int done_hp_init:1;
-       unsigned int no_shutup_pins:1;
-       unsigned int ultra_low_power:1;
-       unsigned int has_hs_key:1;
-       unsigned int no_internal_mic_pin:1;
-       unsigned int en_3kpull_low:1;
-       int num_speaker_amps;
-
-       /* for PLL fix */
-       hda_nid_t pll_nid;
-       unsigned int pll_coef_idx, pll_coef_bit;
-       unsigned int coef0;
-       struct input_dev *kb_dev;
-       u8 alc_mute_keycode_map[1];
-
-       /* component binding */
-       struct hda_component_parent comps;
-};
-
-/*
- * COEF access helper functions
- */
-
-static void coef_mutex_lock(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       snd_hda_power_up_pm(codec);
-       mutex_lock(&spec->coef_mutex);
-}
-
-static void coef_mutex_unlock(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       mutex_unlock(&spec->coef_mutex);
-       snd_hda_power_down_pm(codec);
-}
-
-static int __alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                unsigned int coef_idx)
-{
-       unsigned int val;
-
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
-       val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0);
-       return val;
-}
-
-static int alc_read_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                              unsigned int coef_idx)
-{
-       unsigned int val;
-
-       coef_mutex_lock(codec);
-       val = __alc_read_coefex_idx(codec, nid, coef_idx);
-       coef_mutex_unlock(codec);
-       return val;
-}
-
-#define alc_read_coef_idx(codec, coef_idx) \
-       alc_read_coefex_idx(codec, 0x20, coef_idx)
-
-static void __alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                  unsigned int coef_idx, unsigned int coef_val)
-{
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx);
-       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val);
-}
-
-static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                unsigned int coef_idx, unsigned int coef_val)
-{
-       coef_mutex_lock(codec);
-       __alc_write_coefex_idx(codec, nid, coef_idx, coef_val);
-       coef_mutex_unlock(codec);
-}
-
-#define alc_write_coef_idx(codec, coef_idx, coef_val) \
-       alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val)
-
-static void __alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                   unsigned int coef_idx, unsigned int mask,
-                                   unsigned int bits_set)
-{
-       unsigned int val = __alc_read_coefex_idx(codec, nid, coef_idx);
-
-       if (val != -1)
-               __alc_write_coefex_idx(codec, nid, coef_idx,
-                                      (val & ~mask) | bits_set);
-}
-
-static void alc_update_coefex_idx(struct hda_codec *codec, hda_nid_t nid,
-                                 unsigned int coef_idx, unsigned int mask,
-                                 unsigned int bits_set)
-{
-       coef_mutex_lock(codec);
-       __alc_update_coefex_idx(codec, nid, coef_idx, mask, bits_set);
-       coef_mutex_unlock(codec);
-}
-
-#define alc_update_coef_idx(codec, coef_idx, mask, bits_set)   \
-       alc_update_coefex_idx(codec, 0x20, coef_idx, mask, bits_set)
-
-/* a special bypass for COEF 0; read the cached value at the second time */
-static unsigned int alc_get_coef0(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (!spec->coef0)
-               spec->coef0 = alc_read_coef_idx(codec, 0);
-       return spec->coef0;
-}
-
-/* coef writes/updates batch */
-struct coef_fw {
-       unsigned char nid;
-       unsigned char idx;
-       unsigned short mask;
-       unsigned short val;
-};
-
-#define UPDATE_COEFEX(_nid, _idx, _mask, _val) \
-       { .nid = (_nid), .idx = (_idx), .mask = (_mask), .val = (_val) }
-#define WRITE_COEFEX(_nid, _idx, _val) UPDATE_COEFEX(_nid, _idx, -1, _val)
-#define WRITE_COEF(_idx, _val) WRITE_COEFEX(0x20, _idx, _val)
-#define UPDATE_COEF(_idx, _mask, _val) UPDATE_COEFEX(0x20, _idx, _mask, _val)
-
-static void alc_process_coef_fw(struct hda_codec *codec,
-                               const struct coef_fw *fw)
-{
-       coef_mutex_lock(codec);
-       for (; fw->nid; fw++) {
-               if (fw->mask == (unsigned short)-1)
-                       __alc_write_coefex_idx(codec, fw->nid, fw->idx, fw->val);
-               else
-                       __alc_update_coefex_idx(codec, fw->nid, fw->idx,
-                                               fw->mask, fw->val);
-       }
-       coef_mutex_unlock(codec);
-}
-
-/*
- * GPIO setup tables, used in initialization
- */
-
-/* Enable GPIO mask and set output */
-static void alc_setup_gpio(struct hda_codec *codec, unsigned int mask)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->gpio_mask |= mask;
-       spec->gpio_dir |= mask;
-       spec->gpio_data |= mask;
-}
-
-static void alc_write_gpio_data(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                           spec->gpio_data);
-}
-
-static void alc_update_gpio_data(struct hda_codec *codec, unsigned int mask,
-                                bool on)
-{
-       struct alc_spec *spec = codec->spec;
-       unsigned int oldval = spec->gpio_data;
-
-       if (on)
-               spec->gpio_data |= mask;
-       else
-               spec->gpio_data &= ~mask;
-       if (oldval != spec->gpio_data)
-               alc_write_gpio_data(codec);
-}
-
-static void alc_write_gpio(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (!spec->gpio_mask)
-               return;
-
-       snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_GPIO_MASK, spec->gpio_mask);
-       snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_SET_GPIO_DIRECTION, spec->gpio_dir);
-       if (spec->gpio_write_delay)
-               msleep(1);
-       alc_write_gpio_data(codec);
-}
-
-static void alc_fixup_gpio(struct hda_codec *codec, int action,
-                          unsigned int mask)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               alc_setup_gpio(codec, mask);
-}
-
-static void alc_fixup_gpio1(struct hda_codec *codec,
-                           const struct hda_fixup *fix, int action)
-{
-       alc_fixup_gpio(codec, action, 0x01);
-}
-
-static void alc_fixup_gpio2(struct hda_codec *codec,
-                           const struct hda_fixup *fix, int action)
-{
-       alc_fixup_gpio(codec, action, 0x02);
-}
-
-static void alc_fixup_gpio3(struct hda_codec *codec,
-                           const struct hda_fixup *fix, int action)
-{
-       alc_fixup_gpio(codec, action, 0x03);
-}
-
-static void alc_fixup_gpio4(struct hda_codec *codec,
-                           const struct hda_fixup *fix, int action)
-{
-       alc_fixup_gpio(codec, action, 0x04);
-}
-
-static void alc_fixup_micmute_led(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               snd_hda_gen_add_micmute_led_cdev(codec, NULL);
-}
-
-/*
- * Fix hardware PLL issue
- * On some codecs, the analog PLL gating control must be off while
- * the default value is 1.
- */
-static void alc_fix_pll(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->pll_nid)
-               alc_update_coefex_idx(codec, spec->pll_nid, spec->pll_coef_idx,
-                                     1 << spec->pll_coef_bit, 0);
-}
-
-static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid,
-                            unsigned int coef_idx, unsigned int coef_bit)
-{
-       struct alc_spec *spec = codec->spec;
-       spec->pll_nid = nid;
-       spec->pll_coef_idx = coef_idx;
-       spec->pll_coef_bit = coef_bit;
-       alc_fix_pll(codec);
-}
-
-/* update the master volume per volume-knob's unsol event */
-static void alc_update_knob_master(struct hda_codec *codec,
-                                  struct hda_jack_callback *jack)
-{
-       unsigned int val;
-       struct snd_kcontrol *kctl;
-       struct snd_ctl_elem_value *uctl;
-
-       kctl = snd_hda_find_mixer_ctl(codec, "Master Playback Volume");
-       if (!kctl)
-               return;
-       uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
-       if (!uctl)
-               return;
-       val = snd_hda_codec_read(codec, jack->nid, 0,
-                                AC_VERB_GET_VOLUME_KNOB_CONTROL, 0);
-       val &= HDA_AMP_VOLMASK;
-       uctl->value.integer.value[0] = val;
-       uctl->value.integer.value[1] = val;
-       kctl->put(kctl, uctl);
-       kfree(uctl);
-}
-
-static void alc880_unsol_event(struct hda_codec *codec, unsigned int res)
-{
-       /* For some reason, the res given from ALC880 is broken.
-          Here we adjust it properly. */
-       snd_hda_jack_unsol_event(codec, res >> 2);
-}
-
-/* Change EAPD to verb control */
-static void alc_fill_eapd_coef(struct hda_codec *codec)
-{
-       int coef;
-
-       coef = alc_get_coef0(codec);
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0262:
-               alc_update_coef_idx(codec, 0x7, 0, 1<<5);
-               break;
-       case 0x10ec0267:
-       case 0x10ec0268:
-               alc_update_coef_idx(codec, 0x7, 0, 1<<13);
-               break;
-       case 0x10ec0269:
-               if ((coef & 0x00f0) == 0x0010)
-                       alc_update_coef_idx(codec, 0xd, 0, 1<<14);
-               if ((coef & 0x00f0) == 0x0020)
-                       alc_update_coef_idx(codec, 0x4, 1<<15, 0);
-               if ((coef & 0x00f0) == 0x0030)
-                       alc_update_coef_idx(codec, 0x10, 1<<9, 0);
-               break;
-       case 0x10ec0280:
-       case 0x10ec0284:
-       case 0x10ec0290:
-       case 0x10ec0292:
-               alc_update_coef_idx(codec, 0x4, 1<<15, 0);
-               break;
-       case 0x10ec0225:
-       case 0x10ec0295:
-       case 0x10ec0299:
-               alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
-               fallthrough;
-       case 0x10ec0215:
-       case 0x10ec0236:
-       case 0x10ec0245:
-       case 0x10ec0256:
-       case 0x10ec0257:
-       case 0x10ec0285:
-       case 0x10ec0289:
-               alc_update_coef_idx(codec, 0x36, 1<<13, 0);
-               fallthrough;
-       case 0x10ec0230:
-       case 0x10ec0233:
-       case 0x10ec0235:
-       case 0x10ec0255:
-       case 0x19e58326:
-       case 0x10ec0282:
-       case 0x10ec0283:
-       case 0x10ec0286:
-       case 0x10ec0288:
-       case 0x10ec0298:
-       case 0x10ec0300:
-               alc_update_coef_idx(codec, 0x10, 1<<9, 0);
-               break;
-       case 0x10ec0275:
-               alc_update_coef_idx(codec, 0xe, 0, 1<<0);
-               break;
-       case 0x10ec0287:
-               alc_update_coef_idx(codec, 0x10, 1<<9, 0);
-               alc_write_coef_idx(codec, 0x8, 0x4ab7);
-               break;
-       case 0x10ec0293:
-               alc_update_coef_idx(codec, 0xa, 1<<13, 0);
-               break;
-       case 0x10ec0234:
-       case 0x10ec0274:
-               alc_write_coef_idx(codec, 0x6e, 0x0c25);
-               fallthrough;
-       case 0x10ec0294:
-       case 0x10ec0700:
-       case 0x10ec0701:
-       case 0x10ec0703:
-       case 0x10ec0711:
-               alc_update_coef_idx(codec, 0x10, 1<<15, 0);
-               break;
-       case 0x10ec0662:
-               if ((coef & 0x00f0) == 0x0030)
-                       alc_update_coef_idx(codec, 0x4, 1<<10, 0); /* EAPD Ctrl */
-               break;
-       case 0x10ec0272:
-       case 0x10ec0273:
-       case 0x10ec0663:
-       case 0x10ec0665:
-       case 0x10ec0670:
-       case 0x10ec0671:
-       case 0x10ec0672:
-               alc_update_coef_idx(codec, 0xd, 0, 1<<14); /* EAPD Ctrl */
-               break;
-       case 0x10ec0222:
-       case 0x10ec0623:
-               alc_update_coef_idx(codec, 0x19, 1<<13, 0);
-               break;
-       case 0x10ec0668:
-               alc_update_coef_idx(codec, 0x7, 3<<13, 0);
-               break;
-       case 0x10ec0867:
-               alc_update_coef_idx(codec, 0x4, 1<<10, 0);
-               break;
-       case 0x10ec0888:
-               if ((coef & 0x00f0) == 0x0020 || (coef & 0x00f0) == 0x0030)
-                       alc_update_coef_idx(codec, 0x7, 1<<5, 0);
-               break;
-       case 0x10ec0892:
-       case 0x10ec0897:
-               alc_update_coef_idx(codec, 0x7, 1<<5, 0);
-               break;
-       case 0x10ec0899:
-       case 0x10ec0900:
-       case 0x10ec0b00:
-       case 0x10ec1168:
-       case 0x10ec1220:
-               alc_update_coef_idx(codec, 0x7, 1<<1, 0);
-               break;
-       }
-}
-
-/* additional initialization for ALC888 variants */
-static void alc888_coef_init(struct hda_codec *codec)
-{
-       switch (alc_get_coef0(codec) & 0x00f0) {
-       /* alc888-VA */
-       case 0x00:
-       /* alc888-VB */
-       case 0x10:
-               alc_update_coef_idx(codec, 7, 0, 0x2030); /* Turn EAPD to High */
-               break;
-       }
-}
-
-/* turn on/off EAPD control (only if available) */
-static void set_eapd(struct hda_codec *codec, hda_nid_t nid, int on)
-{
-       if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
-               return;
-       if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)
-               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE,
-                                   on ? 2 : 0);
-}
-
-/* turn on/off EAPD controls of the codec */
-static void alc_auto_setup_eapd(struct hda_codec *codec, bool on)
-{
-       /* We currently only handle front, HP */
-       static const hda_nid_t pins[] = {
-               0x0f, 0x10, 0x14, 0x15, 0x17, 0
-       };
-       const hda_nid_t *p;
-       for (p = pins; *p; p++)
-               set_eapd(codec, *p, on);
-}
-
-static int find_ext_mic_pin(struct hda_codec *codec);
-
-static void alc_headset_mic_no_shutup(struct hda_codec *codec)
-{
-       const struct hda_pincfg *pin;
-       int mic_pin = find_ext_mic_pin(codec);
-       int i;
-
-       /* don't shut up pins when unloading the driver; otherwise it breaks
-        * the default pin setup at the next load of the driver
-        */
-       if (codec->bus->shutdown)
-               return;
-
-       snd_array_for_each(&codec->init_pins, i, pin) {
-               /* use read here for syncing after issuing each verb */
-               if (pin->nid != mic_pin)
-                       snd_hda_codec_read(codec, pin->nid, 0,
-                                       AC_VERB_SET_PIN_WIDGET_CONTROL, 0);
-       }
-
-       codec->pins_shutup = 1;
-}
-
-static void alc_shutup_pins(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->no_shutup_pins)
-               return;
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x10ec0257:
-       case 0x19e58326:
-       case 0x10ec0283:
-       case 0x10ec0285:
-       case 0x10ec0286:
-       case 0x10ec0287:
-       case 0x10ec0288:
-       case 0x10ec0295:
-       case 0x10ec0298:
-               alc_headset_mic_no_shutup(codec);
-               break;
-       default:
-               snd_hda_shutup_pins(codec);
-               break;
-       }
-}
-
-/* generic shutup callback;
- * just turning off EAPD and a little pause for avoiding pop-noise
- */
-static void alc_eapd_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_auto_setup_eapd(codec, false);
-       if (!spec->no_depop_delay)
-               msleep(200);
-       alc_shutup_pins(codec);
-}
-
-/* generic EAPD initialization */
-static void alc_auto_init_amp(struct hda_codec *codec, int type)
-{
-       alc_auto_setup_eapd(codec, true);
-       alc_write_gpio(codec);
-       switch (type) {
-       case ALC_INIT_DEFAULT:
-               switch (codec->core.vendor_id) {
-               case 0x10ec0260:
-                       alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x2010);
-                       break;
-               case 0x10ec0880:
-               case 0x10ec0882:
-               case 0x10ec0883:
-               case 0x10ec0885:
-                       alc_update_coef_idx(codec, 7, 0, 0x2030);
-                       break;
-               case 0x10ec0888:
-                       alc888_coef_init(codec);
-                       break;
-               }
-               break;
-       }
-}
-
-/* get a primary headphone pin if available */
-static hda_nid_t alc_get_hp_pin(struct alc_spec *spec)
-{
-       if (spec->gen.autocfg.hp_pins[0])
-               return spec->gen.autocfg.hp_pins[0];
-       if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
-               return spec->gen.autocfg.line_out_pins[0];
-       return 0;
-}
-
-/*
- * Realtek SSID verification
- */
-
-/* Could be any non-zero and even value. When used as fixup, tells
- * the driver to ignore any present sku defines.
- */
-#define ALC_FIXUP_SKU_IGNORE (2)
-
-static void alc_fixup_sku_ignore(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->cdefine.fixup = 1;
-               spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE;
-       }
-}
-
-static void alc_fixup_no_depop_delay(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               spec->no_depop_delay = 1;
-               codec->depop_delay = 0;
-       }
-}
-
-static int alc_auto_parse_customize_define(struct hda_codec *codec)
-{
-       unsigned int ass, tmp, i;
-       unsigned nid = 0;
-       struct alc_spec *spec = codec->spec;
-
-       spec->cdefine.enable_pcbeep = 1; /* assume always enabled */
-
-       if (spec->cdefine.fixup) {
-               ass = spec->cdefine.sku_cfg;
-               if (ass == ALC_FIXUP_SKU_IGNORE)
-                       return -1;
-               goto do_sku;
-       }
-
-       if (!codec->bus->pci)
-               return -1;
-       ass = codec->core.subsystem_id & 0xffff;
-       if (ass != codec->bus->pci->subsystem_device && (ass & 1))
-               goto do_sku;
-
-       nid = 0x1d;
-       if (codec->core.vendor_id == 0x10ec0260)
-               nid = 0x17;
-       ass = snd_hda_codec_get_pincfg(codec, nid);
-
-       if (!(ass & 1)) {
-               codec_info(codec, "%s: SKU not ready 0x%08x\n",
-                          codec->core.chip_name, ass);
-               return -1;
-       }
-
-       /* check sum */
-       tmp = 0;
-       for (i = 1; i < 16; i++) {
-               if ((ass >> i) & 1)
-                       tmp++;
-       }
-       if (((ass >> 16) & 0xf) != tmp)
-               return -1;
-
-       spec->cdefine.port_connectivity = ass >> 30;
-       spec->cdefine.enable_pcbeep = (ass & 0x100000) >> 20;
-       spec->cdefine.check_sum = (ass >> 16) & 0xf;
-       spec->cdefine.customization = ass >> 8;
-do_sku:
-       spec->cdefine.sku_cfg = ass;
-       spec->cdefine.external_amp = (ass & 0x38) >> 3;
-       spec->cdefine.platform_type = (ass & 0x4) >> 2;
-       spec->cdefine.swap = (ass & 0x2) >> 1;
-       spec->cdefine.override = ass & 0x1;
-
-       codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n",
-                  nid, spec->cdefine.sku_cfg);
-       codec_dbg(codec, "SKU: port_connectivity=0x%x\n",
-                  spec->cdefine.port_connectivity);
-       codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep);
-       codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum);
-       codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization);
-       codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp);
-       codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type);
-       codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap);
-       codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override);
-
-       return 0;
-}
-
-/* return the position of NID in the list, or -1 if not found */
-static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-       int i;
-       for (i = 0; i < nums; i++)
-               if (list[i] == nid)
-                       return i;
-       return -1;
-}
-/* return true if the given NID is found in the list */
-static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums)
-{
-       return find_idx_in_nid_list(nid, list, nums) >= 0;
-}
-
-/* check subsystem ID and set up device-specific initialization;
- * return 1 if initialized, 0 if invalid SSID
- */
-/* 32-bit subsystem ID for BIOS loading in HD Audio codec.
- *     31 ~ 16 :       Manufacture ID
- *     15 ~ 8  :       SKU ID
- *     7  ~ 0  :       Assembly ID
- *     port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36
- */
-static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports)
-{
-       unsigned int ass, tmp, i;
-       unsigned nid;
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->cdefine.fixup) {
-               ass = spec->cdefine.sku_cfg;
-               if (ass == ALC_FIXUP_SKU_IGNORE)
-                       return 0;
-               goto do_sku;
-       }
-
-       ass = codec->core.subsystem_id & 0xffff;
-       if (codec->bus->pci &&
-           ass != codec->bus->pci->subsystem_device && (ass & 1))
-               goto do_sku;
-
-       /* invalid SSID, check the special NID pin defcfg instead */
-       /*
-        * 31~30        : port connectivity
-        * 29~21        : reserve
-        * 20           : PCBEEP input
-        * 19~16        : Check sum (15:1)
-        * 15~1         : Custom
-        * 0            : override
-       */
-       nid = 0x1d;
-       if (codec->core.vendor_id == 0x10ec0260)
-               nid = 0x17;
-       ass = snd_hda_codec_get_pincfg(codec, nid);
-       codec_dbg(codec,
-                 "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n",
-                  ass, nid);
-       if (!(ass & 1))
-               return 0;
-       if ((ass >> 30) != 1)   /* no physical connection */
-               return 0;
-
-       /* check sum */
-       tmp = 0;
-       for (i = 1; i < 16; i++) {
-               if ((ass >> i) & 1)
-                       tmp++;
-       }
-       if (((ass >> 16) & 0xf) != tmp)
-               return 0;
-do_sku:
-       codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n",
-                  ass & 0xffff, codec->core.vendor_id);
-       /*
-        * 0 : override
-        * 1 :  Swap Jack
-        * 2 : 0 --> Desktop, 1 --> Laptop
-        * 3~5 : External Amplifier control
-        * 7~6 : Reserved
-       */
-       tmp = (ass & 0x38) >> 3;        /* external Amp control */
-       if (spec->init_amp == ALC_INIT_UNDEFINED) {
-               switch (tmp) {
-               case 1:
-                       alc_setup_gpio(codec, 0x01);
-                       break;
-               case 3:
-                       alc_setup_gpio(codec, 0x02);
-                       break;
-               case 7:
-                       alc_setup_gpio(codec, 0x04);
-                       break;
-               case 5:
-               default:
-                       spec->init_amp = ALC_INIT_DEFAULT;
-                       break;
-               }
-       }
-
-       /* is laptop or Desktop and enable the function "Mute internal speaker
-        * when the external headphone out jack is plugged"
-        */
-       if (!(ass & 0x8000))
-               return 1;
-       /*
-        * 10~8 : Jack location
-        * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered
-        * 14~13: Resvered
-        * 15   : 1 --> enable the function "Mute internal speaker
-        *              when the external headphone out jack is plugged"
-        */
-       if (!alc_get_hp_pin(spec)) {
-               hda_nid_t nid;
-               tmp = (ass >> 11) & 0x3;        /* HP to chassis */
-               nid = ports[tmp];
-               if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins,
-                                     spec->gen.autocfg.line_outs))
-                       return 1;
-               spec->gen.autocfg.hp_pins[0] = nid;
-       }
-       return 1;
-}
-
-/* Check the validity of ALC subsystem-id
- * ports contains an array of 4 pin NIDs for port-A, E, D and I */
-static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports)
-{
-       if (!alc_subsystem_id(codec, ports)) {
-               struct alc_spec *spec = codec->spec;
-               if (spec->init_amp == ALC_INIT_UNDEFINED) {
-                       codec_dbg(codec,
-                                 "realtek: Enable default setup for auto mode as fallback\n");
-                       spec->init_amp = ALC_INIT_DEFAULT;
-               }
-       }
-}
-
-/* inverted digital-mic */
-static void alc_fixup_inv_dmic(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->gen.inv_dmic_split = 1;
-}
-
-
-static int alc_build_controls(struct hda_codec *codec)
-{
-       int err;
-
-       err = snd_hda_gen_build_controls(codec);
-       if (err < 0)
-               return err;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD);
-       return 0;
-}
-
-
-/*
- * Common callbacks
- */
-
-static void alc_pre_init(struct hda_codec *codec)
-{
-       alc_fill_eapd_coef(codec);
-}
-
-#define is_s3_resume(codec) \
-       ((codec)->core.dev.power.power_state.event == PM_EVENT_RESUME)
-#define is_s4_resume(codec) \
-       ((codec)->core.dev.power.power_state.event == PM_EVENT_RESTORE)
-#define is_s4_suspend(codec) \
-       ((codec)->core.dev.power.power_state.event == PM_EVENT_FREEZE)
-
-static int alc_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       /* hibernation resume needs the full chip initialization */
-       if (is_s4_resume(codec))
-               alc_pre_init(codec);
-
-       if (spec->init_hook)
-               spec->init_hook(codec);
-
-       spec->gen.skip_verbs = 1; /* applied in below */
-       snd_hda_gen_init(codec);
-       alc_fix_pll(codec);
-       alc_auto_init_amp(codec, spec->init_amp);
-       snd_hda_apply_verbs(codec); /* apply verbs here after own init */
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
-
-       return 0;
-}
-
-/* forward declaration */
-static const struct component_master_ops comp_master_ops;
-
-static void alc_free(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec)
-               hda_component_manager_free(&spec->comps, &comp_master_ops);
-
-       snd_hda_gen_free(codec);
-}
-
-static inline void alc_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (!snd_hda_get_bool_hint(codec, "shutup"))
-               return; /* disabled explicitly by hints */
-
-       if (spec && spec->shutup)
-               spec->shutup(codec);
-       else
-               alc_shutup_pins(codec);
-}
-
-static void alc_power_eapd(struct hda_codec *codec)
-{
-       alc_auto_setup_eapd(codec, false);
-}
-
-static int alc_suspend(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       alc_shutup(codec);
-       if (spec && spec->power_hook)
-               spec->power_hook(codec);
-       return 0;
-}
-
-static int alc_resume(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (!spec->no_depop_delay)
-               msleep(150); /* to avoid pop noise */
-       codec->patch_ops.init(codec);
-       snd_hda_regmap_sync(codec);
-       hda_call_check_power_status(codec, 0x01);
-       return 0;
-}
-
-/*
- */
-static const struct hda_codec_ops alc_patch_ops = {
-       .build_controls = alc_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = alc_init,
-       .free = alc_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .resume = alc_resume,
-       .suspend = alc_suspend,
-       .check_power_status = snd_hda_gen_check_power_status,
-};
-
-
-#define alc_codec_rename(codec, name) snd_hda_codec_set_name(codec, name)
-
-/*
- * Rename codecs appropriately from COEF value or subvendor id
- */
-struct alc_codec_rename_table {
-       unsigned int vendor_id;
-       unsigned short coef_mask;
-       unsigned short coef_bits;
-       const char *name;
-};
-
-struct alc_codec_rename_pci_table {
-       unsigned int codec_vendor_id;
-       unsigned short pci_subvendor;
-       unsigned short pci_subdevice;
-       const char *name;
-};
-
-static const struct alc_codec_rename_table rename_tbl[] = {
-       { 0x10ec0221, 0xf00f, 0x1003, "ALC231" },
-       { 0x10ec0269, 0xfff0, 0x3010, "ALC277" },
-       { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" },
-       { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" },
-       { 0x10ec0269, 0x00f0, 0x0010, "ALC269VB" },
-       { 0x10ec0269, 0xffff, 0xa023, "ALC259" },
-       { 0x10ec0269, 0xffff, 0x6023, "ALC281X" },
-       { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" },
-       { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" },
-       { 0x10ec0662, 0xffff, 0x4020, "ALC656" },
-       { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" },
-       { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" },
-       { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" },
-       { 0x10ec0899, 0x2000, 0x2000, "ALC899" },
-       { 0x10ec0892, 0xffff, 0x8020, "ALC661" },
-       { 0x10ec0892, 0xffff, 0x8011, "ALC661" },
-       { 0x10ec0892, 0xffff, 0x4011, "ALC656" },
-       { } /* terminator */
-};
-
-static const struct alc_codec_rename_pci_table rename_pci_tbl[] = {
-       { 0x10ec0280, 0x1028, 0, "ALC3220" },
-       { 0x10ec0282, 0x1028, 0, "ALC3221" },
-       { 0x10ec0283, 0x1028, 0, "ALC3223" },
-       { 0x10ec0288, 0x1028, 0, "ALC3263" },
-       { 0x10ec0292, 0x1028, 0, "ALC3226" },
-       { 0x10ec0293, 0x1028, 0, "ALC3235" },
-       { 0x10ec0255, 0x1028, 0, "ALC3234" },
-       { 0x10ec0668, 0x1028, 0, "ALC3661" },
-       { 0x10ec0275, 0x1028, 0, "ALC3260" },
-       { 0x10ec0899, 0x1028, 0, "ALC3861" },
-       { 0x10ec0298, 0x1028, 0, "ALC3266" },
-       { 0x10ec0236, 0x1028, 0, "ALC3204" },
-       { 0x10ec0256, 0x1028, 0, "ALC3246" },
-       { 0x10ec0225, 0x1028, 0, "ALC3253" },
-       { 0x10ec0295, 0x1028, 0, "ALC3254" },
-       { 0x10ec0299, 0x1028, 0, "ALC3271" },
-       { 0x10ec0670, 0x1025, 0, "ALC669X" },
-       { 0x10ec0676, 0x1025, 0, "ALC679X" },
-       { 0x10ec0282, 0x1043, 0, "ALC3229" },
-       { 0x10ec0233, 0x1043, 0, "ALC3236" },
-       { 0x10ec0280, 0x103c, 0, "ALC3228" },
-       { 0x10ec0282, 0x103c, 0, "ALC3227" },
-       { 0x10ec0286, 0x103c, 0, "ALC3242" },
-       { 0x10ec0290, 0x103c, 0, "ALC3241" },
-       { 0x10ec0668, 0x103c, 0, "ALC3662" },
-       { 0x10ec0283, 0x17aa, 0, "ALC3239" },
-       { 0x10ec0292, 0x17aa, 0, "ALC3232" },
-       { 0x10ec0257, 0x12f0, 0, "ALC3328" },
-       { } /* terminator */
-};
-
-static int alc_codec_rename_from_preset(struct hda_codec *codec)
-{
-       const struct alc_codec_rename_table *p;
-       const struct alc_codec_rename_pci_table *q;
-
-       for (p = rename_tbl; p->vendor_id; p++) {
-               if (p->vendor_id != codec->core.vendor_id)
-                       continue;
-               if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits)
-                       return alc_codec_rename(codec, p->name);
-       }
-
-       if (!codec->bus->pci)
-               return 0;
-       for (q = rename_pci_tbl; q->codec_vendor_id; q++) {
-               if (q->codec_vendor_id != codec->core.vendor_id)
-                       continue;
-               if (q->pci_subvendor != codec->bus->pci->subsystem_vendor)
-                       continue;
-               if (!q->pci_subdevice ||
-                   q->pci_subdevice == codec->bus->pci->subsystem_device)
-                       return alc_codec_rename(codec, q->name);
-       }
-
-       return 0;
-}
-
-
-/*
- * Digital-beep handlers
- */
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-
-/* additional beep mixers; private_value will be overwritten */
-static const struct snd_kcontrol_new alc_beep_mixer[] = {
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT),
-       HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT),
-};
-
-/* set up and create beep controls */
-static int set_beep_amp(struct alc_spec *spec, hda_nid_t nid,
-                       int idx, int dir)
-{
-       struct snd_kcontrol_new *knew;
-       unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir);
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(alc_beep_mixer); i++) {
-               knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
-                                           &alc_beep_mixer[i]);
-               if (!knew)
-                       return -ENOMEM;
-               knew->private_value = beep_amp;
-       }
-       return 0;
-}
-
-static const struct snd_pci_quirk beep_allow_list[] = {
-       SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1),
-       SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1),
-       SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1),
-       SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1),
-       SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1),
-       SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1),
-       SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1),
-       SND_PCI_QUIRK(0x1458, 0xa002, "GA-MA790X", 1),
-       SND_PCI_QUIRK(0x8086, 0xd613, "Intel", 1),
-       /* denylist -- no beep available */
-       SND_PCI_QUIRK(0x17aa, 0x309e, "Lenovo ThinkCentre M73", 0),
-       SND_PCI_QUIRK(0x17aa, 0x30a3, "Lenovo ThinkCentre M93", 0),
-       {}
-};
-
-static inline int has_cdefine_beep(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       const struct snd_pci_quirk *q;
-       q = snd_pci_quirk_lookup(codec->bus->pci, beep_allow_list);
-       if (q)
-               return q->value;
-       return spec->cdefine.enable_pcbeep;
-}
-#else
-#define set_beep_amp(spec, nid, idx, dir)      0
-#define has_cdefine_beep(codec)                0
-#endif
-
-/* parse the BIOS configuration and set up the alc_spec */
-/* return 1 if successful, 0 if the proper config is not found,
- * or a negative error code
- */
-static int alc_parse_auto_config(struct hda_codec *codec,
-                                const hda_nid_t *ignore_nids,
-                                const hda_nid_t *ssid_nids)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-       int err;
-
-       err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids,
-                                      spec->parse_flags);
-       if (err < 0)
-               return err;
-
-       if (ssid_nids)
-               alc_ssid_check(codec, ssid_nids);
-
-       err = snd_hda_gen_parse_auto_config(codec, cfg);
-       if (err < 0)
-               return err;
-
-       return 1;
-}
-
-/* common preparation job for alc_spec */
-static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid)
-{
-       struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       int err;
-
-       if (!spec)
-               return -ENOMEM;
-       codec->spec = spec;
-       snd_hda_gen_spec_init(&spec->gen);
-       spec->gen.mixer_nid = mixer_nid;
-       spec->gen.own_eapd_ctl = 1;
-       codec->single_adc_amp = 1;
-       /* FIXME: do we need this for all Realtek codec models? */
-       codec->spdif_status_reset = 1;
-       codec->forced_resume = 1;
-       codec->patch_ops = alc_patch_ops;
-       mutex_init(&spec->coef_mutex);
-
-       err = alc_codec_rename_from_preset(codec);
-       if (err < 0) {
-               kfree(spec);
-               return err;
-       }
-       return 0;
-}
-
-static int alc880_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc880_ignore[] = { 0x1d, 0 };
-       static const hda_nid_t alc880_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-       return alc_parse_auto_config(codec, alc880_ignore, alc880_ssids);
-}
-
-/*
- * ALC880 fix-ups
- */
-enum {
-       ALC880_FIXUP_GPIO1,
-       ALC880_FIXUP_GPIO2,
-       ALC880_FIXUP_MEDION_RIM,
-       ALC880_FIXUP_LG,
-       ALC880_FIXUP_LG_LW25,
-       ALC880_FIXUP_W810,
-       ALC880_FIXUP_EAPD_COEF,
-       ALC880_FIXUP_TCL_S700,
-       ALC880_FIXUP_VOL_KNOB,
-       ALC880_FIXUP_FUJITSU,
-       ALC880_FIXUP_F1734,
-       ALC880_FIXUP_UNIWILL,
-       ALC880_FIXUP_UNIWILL_DIG,
-       ALC880_FIXUP_Z71V,
-       ALC880_FIXUP_ASUS_W5A,
-       ALC880_FIXUP_3ST_BASE,
-       ALC880_FIXUP_3ST,
-       ALC880_FIXUP_3ST_DIG,
-       ALC880_FIXUP_5ST_BASE,
-       ALC880_FIXUP_5ST,
-       ALC880_FIXUP_5ST_DIG,
-       ALC880_FIXUP_6ST_BASE,
-       ALC880_FIXUP_6ST,
-       ALC880_FIXUP_6ST_DIG,
-       ALC880_FIXUP_6ST_AUTOMUTE,
-};
-
-/* enable the volume-knob widget support on NID 0x21 */
-static void alc880_fixup_vol_knob(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PROBE)
-               snd_hda_jack_detect_enable_callback(codec, 0x21,
-                                                   alc_update_knob_master);
-}
-
-static const struct hda_fixup alc880_fixups[] = {
-       [ALC880_FIXUP_GPIO1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_gpio1,
-       },
-       [ALC880_FIXUP_GPIO2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_gpio2,
-       },
-       [ALC880_FIXUP_MEDION_RIM] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_GPIO2,
-       },
-       [ALC880_FIXUP_LG] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* disable bogus unused pins */
-                       { 0x16, 0x411111f0 },
-                       { 0x18, 0x411111f0 },
-                       { 0x1a, 0x411111f0 },
-                       { }
-               }
-       },
-       [ALC880_FIXUP_LG_LW25] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x0181344f }, /* line-in */
-                       { 0x1b, 0x0321403f }, /* headphone */
-                       { }
-               }
-       },
-       [ALC880_FIXUP_W810] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* disable bogus unused pins */
-                       { 0x17, 0x411111f0 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_GPIO2,
-       },
-       [ALC880_FIXUP_EAPD_COEF] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* change to EAPD mode */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3060 },
-                       {}
-               },
-       },
-       [ALC880_FIXUP_TCL_S700] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* change to EAPD mode */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF,  0x3070 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_GPIO2,
-       },
-       [ALC880_FIXUP_VOL_KNOB] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc880_fixup_vol_knob,
-       },
-       [ALC880_FIXUP_FUJITSU] = {
-               /* override all pins as BIOS on old Amilo is broken */
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x0121401f }, /* HP */
-                       { 0x15, 0x99030120 }, /* speaker */
-                       { 0x16, 0x99030130 }, /* bass speaker */
-                       { 0x17, 0x411111f0 }, /* N/A */
-                       { 0x18, 0x411111f0 }, /* N/A */
-                       { 0x19, 0x01a19950 }, /* mic-in */
-                       { 0x1a, 0x411111f0 }, /* N/A */
-                       { 0x1b, 0x411111f0 }, /* N/A */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x411111f0 }, /* N/A */
-                       { 0x1e, 0x01454140 }, /* SPDIF out */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_VOL_KNOB,
-       },
-       [ALC880_FIXUP_F1734] = {
-               /* almost compatible with FUJITSU, but no bass and SPDIF */
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x0121401f }, /* HP */
-                       { 0x15, 0x99030120 }, /* speaker */
-                       { 0x16, 0x411111f0 }, /* N/A */
-                       { 0x17, 0x411111f0 }, /* N/A */
-                       { 0x18, 0x411111f0 }, /* N/A */
-                       { 0x19, 0x01a19950 }, /* mic-in */
-                       { 0x1a, 0x411111f0 }, /* N/A */
-                       { 0x1b, 0x411111f0 }, /* N/A */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x411111f0 }, /* N/A */
-                       { 0x1e, 0x411111f0 }, /* N/A */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_VOL_KNOB,
-       },
-       [ALC880_FIXUP_UNIWILL] = {
-               /* need to fix HP and speaker pins to be parsed correctly */
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x0121411f }, /* HP */
-                       { 0x15, 0x99030120 }, /* speaker */
-                       { 0x16, 0x99030130 }, /* bass speaker */
-                       { }
-               },
-       },
-       [ALC880_FIXUP_UNIWILL_DIG] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* disable bogus unused pins */
-                       { 0x17, 0x411111f0 },
-                       { 0x19, 0x411111f0 },
-                       { 0x1b, 0x411111f0 },
-                       { 0x1f, 0x411111f0 },
-                       { }
-               }
-       },
-       [ALC880_FIXUP_Z71V] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* set up the whole pins as BIOS is utterly broken */
-                       { 0x14, 0x99030120 }, /* speaker */
-                       { 0x15, 0x0121411f }, /* HP */
-                       { 0x16, 0x411111f0 }, /* N/A */
-                       { 0x17, 0x411111f0 }, /* N/A */
-                       { 0x18, 0x01a19950 }, /* mic-in */
-                       { 0x19, 0x411111f0 }, /* N/A */
-                       { 0x1a, 0x01813031 }, /* line-in */
-                       { 0x1b, 0x411111f0 }, /* N/A */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x411111f0 }, /* N/A */
-                       { 0x1e, 0x0144111e }, /* SPDIF */
-                       { }
-               }
-       },
-       [ALC880_FIXUP_ASUS_W5A] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* set up the whole pins as BIOS is utterly broken */
-                       { 0x14, 0x0121411f }, /* HP */
-                       { 0x15, 0x411111f0 }, /* N/A */
-                       { 0x16, 0x411111f0 }, /* N/A */
-                       { 0x17, 0x411111f0 }, /* N/A */
-                       { 0x18, 0x90a60160 }, /* mic */
-                       { 0x19, 0x411111f0 }, /* N/A */
-                       { 0x1a, 0x411111f0 }, /* N/A */
-                       { 0x1b, 0x411111f0 }, /* N/A */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x411111f0 }, /* N/A */
-                       { 0x1e, 0xb743111e }, /* SPDIF out */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_GPIO1,
-       },
-       [ALC880_FIXUP_3ST_BASE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x01014010 }, /* line-out */
-                       { 0x15, 0x411111f0 }, /* N/A */
-                       { 0x16, 0x411111f0 }, /* N/A */
-                       { 0x17, 0x411111f0 }, /* N/A */
-                       { 0x18, 0x01a19c30 }, /* mic-in */
-                       { 0x19, 0x0121411f }, /* HP */
-                       { 0x1a, 0x01813031 }, /* line-in */
-                       { 0x1b, 0x02a19c40 }, /* front-mic */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x411111f0 }, /* N/A */
-                       /* 0x1e is filled in below */
-                       { 0x1f, 0x411111f0 }, /* N/A */
-                       { }
-               }
-       },
-       [ALC880_FIXUP_3ST] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1e, 0x411111f0 }, /* N/A */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_3ST_BASE,
-       },
-       [ALC880_FIXUP_3ST_DIG] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1e, 0x0144111e }, /* SPDIF */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_3ST_BASE,
-       },
-       [ALC880_FIXUP_5ST_BASE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x01014010 }, /* front */
-                       { 0x15, 0x411111f0 }, /* N/A */
-                       { 0x16, 0x01011411 }, /* CLFE */
-                       { 0x17, 0x01016412 }, /* surr */
-                       { 0x18, 0x01a19c30 }, /* mic-in */
-                       { 0x19, 0x0121411f }, /* HP */
-                       { 0x1a, 0x01813031 }, /* line-in */
-                       { 0x1b, 0x02a19c40 }, /* front-mic */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x411111f0 }, /* N/A */
-                       /* 0x1e is filled in below */
-                       { 0x1f, 0x411111f0 }, /* N/A */
-                       { }
-               }
-       },
-       [ALC880_FIXUP_5ST] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1e, 0x411111f0 }, /* N/A */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_5ST_BASE,
-       },
-       [ALC880_FIXUP_5ST_DIG] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1e, 0x0144111e }, /* SPDIF */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_5ST_BASE,
-       },
-       [ALC880_FIXUP_6ST_BASE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x01014010 }, /* front */
-                       { 0x15, 0x01016412 }, /* surr */
-                       { 0x16, 0x01011411 }, /* CLFE */
-                       { 0x17, 0x01012414 }, /* side */
-                       { 0x18, 0x01a19c30 }, /* mic-in */
-                       { 0x19, 0x02a19c40 }, /* front-mic */
-                       { 0x1a, 0x01813031 }, /* line-in */
-                       { 0x1b, 0x0121411f }, /* HP */
-                       { 0x1c, 0x411111f0 }, /* N/A */
-                       { 0x1d, 0x411111f0 }, /* N/A */
-                       /* 0x1e is filled in below */
-                       { 0x1f, 0x411111f0 }, /* N/A */
-                       { }
-               }
-       },
-       [ALC880_FIXUP_6ST] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1e, 0x411111f0 }, /* N/A */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_6ST_BASE,
-       },
-       [ALC880_FIXUP_6ST_DIG] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1e, 0x0144111e }, /* SPDIF */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC880_FIXUP_6ST_BASE,
-       },
-       [ALC880_FIXUP_6ST_AUTOMUTE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x0121401f }, /* HP with jack detect */
-                       { }
-               },
-               .chained_before = true,
-               .chain_id = ALC880_FIXUP_6ST_BASE,
-       },
-};
-
-static const struct hda_quirk alc880_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810),
-       SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A),
-       SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V),
-       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1),
-       SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE),
-       SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2),
-       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF),
-       SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG),
-       SND_PCI_QUIRK(0x1584, 0x9054, "Uniwill", ALC880_FIXUP_F1734),
-       SND_PCI_QUIRK(0x1584, 0x9070, "Uniwill", ALC880_FIXUP_UNIWILL),
-       SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB),
-       SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810),
-       SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM),
-       SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE),
-       SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU),
-       SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU),
-       SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734),
-       SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU),
-       SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG),
-       SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG),
-       SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG),
-       SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25),
-       SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700),
-
-       /* Below is the copied entries from alc880_quirks.c.
-        * It's not quite sure whether BIOS sets the correct pin-config table
-        * on these machines, thus they are kept to be compatible with
-        * the old static quirks.  Once when it's confirmed to work without
-        * these overrides, it'd be better to remove.
-        */
-       SND_PCI_QUIRK(0x1019, 0xa880, "ECS", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x1019, 0xa884, "Acer APFV", ALC880_FIXUP_6ST),
-       SND_PCI_QUIRK(0x1025, 0x0070, "ULI", ALC880_FIXUP_3ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0x0077, "ULI", ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0x0078, "ULI", ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0x0087, "ULI", ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0xe309, "ULI", ALC880_FIXUP_3ST_DIG),
-       SND_PCI_QUIRK(0x1025, 0xe310, "ULI", ALC880_FIXUP_3ST),
-       SND_PCI_QUIRK(0x1039, 0x1234, NULL, ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x104d, 0x81a0, "Sony", ALC880_FIXUP_3ST),
-       SND_PCI_QUIRK(0x104d, 0x81d6, "Sony", ALC880_FIXUP_3ST),
-       SND_PCI_QUIRK(0x107b, 0x3032, "Gateway", ALC880_FIXUP_5ST),
-       SND_PCI_QUIRK(0x107b, 0x3033, "Gateway", ALC880_FIXUP_5ST),
-       SND_PCI_QUIRK(0x107b, 0x4039, "Gateway", ALC880_FIXUP_5ST),
-       SND_PCI_QUIRK(0x1297, 0xc790, "Shuttle ST20G5", ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x1458, 0xa102, "Gigabyte K8", ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x1462, 0x1150, "MSI", ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x1509, 0x925d, "FIC P4M", ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x1565, 0x8202, "Biostar", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x1695, 0x400d, "EPoX", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x1695, 0x4012, "EPox EP-5LDA", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x2668, 0x8086, NULL, ALC880_FIXUP_6ST_DIG), /* broken BIOS */
-       SND_PCI_QUIRK(0x8086, 0x2668, NULL, ALC880_FIXUP_6ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xa100, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xd400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xd401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xd402, "Intel mobo", ALC880_FIXUP_3ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe224, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe305, "Intel mobo", ALC880_FIXUP_3ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe308, "Intel mobo", ALC880_FIXUP_3ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe400, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe401, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0x8086, 0xe402, "Intel mobo", ALC880_FIXUP_5ST_DIG),
-       /* default Intel */
-       SND_PCI_QUIRK_VENDOR(0x8086, "Intel mobo", ALC880_FIXUP_3ST),
-       SND_PCI_QUIRK(0xa0a0, 0x0560, "AOpen i915GMm-HFS", ALC880_FIXUP_5ST_DIG),
-       SND_PCI_QUIRK(0xe803, 0x1019, NULL, ALC880_FIXUP_6ST_DIG),
-       {}
-};
-
-static const struct hda_model_fixup alc880_fixup_models[] = {
-       {.id = ALC880_FIXUP_3ST, .name = "3stack"},
-       {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"},
-       {.id = ALC880_FIXUP_5ST, .name = "5stack"},
-       {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"},
-       {.id = ALC880_FIXUP_6ST, .name = "6stack"},
-       {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"},
-       {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"},
-       {}
-};
-
-
-/*
- * OK, here we have finally the patch for ALC880
- */
-static int patch_alc880(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err;
-
-       err = alc_alloc_spec(codec, 0x0b);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->gen.need_dac_fix = 1;
-       spec->gen.beep_nid = 0x01;
-
-       codec->patch_ops.unsol_event = alc880_unsol_event;
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl,
-                      alc880_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       /* automatic parse from the BIOS config */
-       err = alc880_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!spec->gen.no_analog) {
-               err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-               if (err < 0)
-                       goto error;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-
-/*
- * ALC260 support
- */
-static int alc260_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc260_ignore[] = { 0x17, 0 };
-       static const hda_nid_t alc260_ssids[] = { 0x10, 0x15, 0x0f, 0 };
-       return alc_parse_auto_config(codec, alc260_ignore, alc260_ssids);
-}
-
-/*
- * Pin config fixes
- */
-enum {
-       ALC260_FIXUP_HP_DC5750,
-       ALC260_FIXUP_HP_PIN_0F,
-       ALC260_FIXUP_COEF,
-       ALC260_FIXUP_GPIO1,
-       ALC260_FIXUP_GPIO1_TOGGLE,
-       ALC260_FIXUP_REPLACER,
-       ALC260_FIXUP_HP_B1900,
-       ALC260_FIXUP_KN1,
-       ALC260_FIXUP_FSC_S7020,
-       ALC260_FIXUP_FSC_S7020_JWSE,
-       ALC260_FIXUP_VAIO_PINS,
-};
-
-static void alc260_gpio1_automute(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_update_gpio_data(codec, 0x01, spec->gen.hp_jack_present);
-}
-
-static void alc260_fixup_gpio1_toggle(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               /* although the machine has only one output pin, we need to
-                * toggle GPIO1 according to the jack state
-                */
-               spec->gen.automute_hook = alc260_gpio1_automute;
-               spec->gen.detect_hp = 1;
-               spec->gen.automute_speaker = 1;
-               spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */
-               snd_hda_jack_detect_enable_callback(codec, 0x0f,
-                                                   snd_hda_gen_hp_automute);
-               alc_setup_gpio(codec, 0x01);
-       }
-}
-
-static void alc260_fixup_kn1(struct hda_codec *codec,
-                            const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x0f, 0x02214000 }, /* HP/speaker */
-               { 0x12, 0x90a60160 }, /* int mic */
-               { 0x13, 0x02a19000 }, /* ext mic */
-               { 0x18, 0x01446000 }, /* SPDIF out */
-               /* disable bogus I/O pins */
-               { 0x10, 0x411111f0 },
-               { 0x11, 0x411111f0 },
-               { 0x14, 0x411111f0 },
-               { 0x15, 0x411111f0 },
-               { 0x16, 0x411111f0 },
-               { 0x17, 0x411111f0 },
-               { 0x19, 0x411111f0 },
-               { }
-       };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               spec->init_amp = ALC_INIT_NONE;
-               break;
-       }
-}
-
-static void alc260_fixup_fsc_s7020(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->init_amp = ALC_INIT_NONE;
-}
-
-static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.add_jack_modes = 1;
-               spec->gen.hp_mic = 1;
-       }
-}
-
-static const struct hda_fixup alc260_fixups[] = {
-       [ALC260_FIXUP_HP_DC5750] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x11, 0x90130110 }, /* speaker */
-                       { }
-               }
-       },
-       [ALC260_FIXUP_HP_PIN_0F] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x0f, 0x01214000 }, /* HP */
-                       { }
-               }
-       },
-       [ALC260_FIXUP_COEF] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x1a, AC_VERB_SET_PROC_COEF,  0x3040 },
-                       { }
-               },
-       },
-       [ALC260_FIXUP_GPIO1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_gpio1,
-       },
-       [ALC260_FIXUP_GPIO1_TOGGLE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc260_fixup_gpio1_toggle,
-               .chained = true,
-               .chain_id = ALC260_FIXUP_HP_PIN_0F,
-       },
-       [ALC260_FIXUP_REPLACER] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x1a, AC_VERB_SET_PROC_COEF,  0x3050 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC260_FIXUP_GPIO1_TOGGLE,
-       },
-       [ALC260_FIXUP_HP_B1900] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc260_fixup_gpio1_toggle,
-               .chained = true,
-               .chain_id = ALC260_FIXUP_COEF,
-       },
-       [ALC260_FIXUP_KN1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc260_fixup_kn1,
-       },
-       [ALC260_FIXUP_FSC_S7020] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc260_fixup_fsc_s7020,
-       },
-       [ALC260_FIXUP_FSC_S7020_JWSE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc260_fixup_fsc_s7020_jwse,
-               .chained = true,
-               .chain_id = ALC260_FIXUP_FSC_S7020,
-       },
-       [ALC260_FIXUP_VAIO_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* Pin configs are missing completely on some VAIOs */
-                       { 0x0f, 0x01211020 },
-                       { 0x10, 0x0001003f },
-                       { 0x11, 0x411111f0 },
-                       { 0x12, 0x01a15930 },
-                       { 0x13, 0x411111f0 },
-                       { 0x14, 0x411111f0 },
-                       { 0x15, 0x411111f0 },
-                       { 0x16, 0x411111f0 },
-                       { 0x17, 0x411111f0 },
-                       { 0x18, 0x411111f0 },
-                       { 0x19, 0x411111f0 },
-                       { }
-               }
-       },
-};
-
-static const struct hda_quirk alc260_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_FIXUP_GPIO1),
-       SND_PCI_QUIRK(0x1025, 0x007f, "Acer Aspire 9500", ALC260_FIXUP_COEF),
-       SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1),
-       SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750),
-       SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900),
-       SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS),
-       SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F),
-       SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020),
-       SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1),
-       SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1),
-       SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER),
-       SND_PCI_QUIRK(0x1631, 0xc017, "PB V7900", ALC260_FIXUP_COEF),
-       {}
-};
-
-static const struct hda_model_fixup alc260_fixup_models[] = {
-       {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"},
-       {.id = ALC260_FIXUP_COEF, .name = "coef"},
-       {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"},
-       {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"},
-       {}
-};
-
-/*
- */
-static int patch_alc260(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err;
-
-       err = alc_alloc_spec(codec, 0x07);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       /* as quite a few machines require HP amp for speaker outputs,
-        * it's easier to enable it unconditionally; even if it's unneeded,
-        * it's almost harmless.
-        */
-       spec->gen.prefer_hp_amp = 1;
-       spec->gen.beep_nid = 0x01;
-
-       spec->shutup = alc_eapd_shutup;
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl,
-                          alc260_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       /* automatic parse from the BIOS config */
-       err = alc260_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!spec->gen.no_analog) {
-               err = set_beep_amp(spec, 0x07, 0x05, HDA_INPUT);
-               if (err < 0)
-                       goto error;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-
-/*
- * ALC882/883/885/888/889 support
- *
- * ALC882 is almost identical with ALC880 but has cleaner and more flexible
- * configuration.  Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs.  This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-
-/*
- * Pin config fixes
- */
-enum {
-       ALC882_FIXUP_ABIT_AW9D_MAX,
-       ALC882_FIXUP_LENOVO_Y530,
-       ALC882_FIXUP_PB_M5210,
-       ALC882_FIXUP_ACER_ASPIRE_7736,
-       ALC882_FIXUP_ASUS_W90V,
-       ALC889_FIXUP_CD,
-       ALC889_FIXUP_FRONT_HP_NO_PRESENCE,
-       ALC889_FIXUP_VAIO_TT,
-       ALC888_FIXUP_EEE1601,
-       ALC886_FIXUP_EAPD,
-       ALC882_FIXUP_EAPD,
-       ALC883_FIXUP_EAPD,
-       ALC883_FIXUP_ACER_EAPD,
-       ALC882_FIXUP_GPIO1,
-       ALC882_FIXUP_GPIO2,
-       ALC882_FIXUP_GPIO3,
-       ALC889_FIXUP_COEF,
-       ALC882_FIXUP_ASUS_W2JC,
-       ALC882_FIXUP_ACER_ASPIRE_4930G,
-       ALC882_FIXUP_ACER_ASPIRE_8930G,
-       ALC882_FIXUP_ASPIRE_8930G_VERBS,
-       ALC885_FIXUP_MACPRO_GPIO,
-       ALC889_FIXUP_DAC_ROUTE,
-       ALC889_FIXUP_MBP_VREF,
-       ALC889_FIXUP_IMAC91_VREF,
-       ALC889_FIXUP_MBA11_VREF,
-       ALC889_FIXUP_MBA21_VREF,
-       ALC889_FIXUP_MP11_VREF,
-       ALC889_FIXUP_MP41_VREF,
-       ALC882_FIXUP_INV_DMIC,
-       ALC882_FIXUP_NO_PRIMARY_HP,
-       ALC887_FIXUP_ASUS_BASS,
-       ALC887_FIXUP_BASS_CHMAP,
-       ALC1220_FIXUP_GB_DUAL_CODECS,
-       ALC1220_FIXUP_GB_X570,
-       ALC1220_FIXUP_CLEVO_P950,
-       ALC1220_FIXUP_CLEVO_PB51ED,
-       ALC1220_FIXUP_CLEVO_PB51ED_PINS,
-       ALC887_FIXUP_ASUS_AUDIO,
-       ALC887_FIXUP_ASUS_HMIC,
-       ALCS1200A_FIXUP_MIC_VREF,
-       ALC888VD_FIXUP_MIC_100VREF,
-};
-
-static void alc889_fixup_coef(struct hda_codec *codec,
-                             const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_INIT)
-               return;
-       alc_update_coef_idx(codec, 7, 0, 0x2030);
-}
-
-/* set up GPIO at initialization */
-static void alc885_fixup_macpro_gpio(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       spec->gpio_write_delay = true;
-       alc_fixup_gpio3(codec, fix, action);
-}
-
-/* Fix the connection of some pins for ALC889:
- * At least, Acer Aspire 5935 shows the connections to DAC3/4 don't
- * work correctly (bko#42740)
- */
-static void alc889_fixup_dac_route(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               /* fake the connections during parsing the tree */
-               static const hda_nid_t conn1[] = { 0x0c, 0x0d };
-               static const hda_nid_t conn2[] = { 0x0e, 0x0f };
-               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
-               snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
-               snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn2), conn2);
-               snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn2), conn2);
-       } else if (action == HDA_FIXUP_ACT_PROBE) {
-               /* restore the connections */
-               static const hda_nid_t conn[] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 };
-               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
-               snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
-               snd_hda_override_conn_list(codec, 0x18, ARRAY_SIZE(conn), conn);
-               snd_hda_override_conn_list(codec, 0x1a, ARRAY_SIZE(conn), conn);
-       }
-}
-
-/* Set VREF on HP pin */
-static void alc889_fixup_mbp_vref(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t nids[] = { 0x14, 0x15, 0x19 };
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       if (action != HDA_FIXUP_ACT_INIT)
-               return;
-       for (i = 0; i < ARRAY_SIZE(nids); i++) {
-               unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]);
-               if (get_defcfg_device(val) != AC_JACK_HP_OUT)
-                       continue;
-               val = snd_hda_codec_get_pin_target(codec, nids[i]);
-               val |= AC_PINCTL_VREF_80;
-               snd_hda_set_pin_ctl(codec, nids[i], val);
-               spec->gen.keep_vref_in_automute = 1;
-               break;
-       }
-}
-
-static void alc889_fixup_mac_pins(struct hda_codec *codec,
-                                 const hda_nid_t *nids, int num_nids)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < num_nids; i++) {
-               unsigned int val;
-               val = snd_hda_codec_get_pin_target(codec, nids[i]);
-               val |= AC_PINCTL_VREF_50;
-               snd_hda_set_pin_ctl(codec, nids[i], val);
-       }
-       spec->gen.keep_vref_in_automute = 1;
-}
-
-/* Set VREF on speaker pins on imac91 */
-static void alc889_fixup_imac91_vref(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t nids[] = { 0x18, 0x1a };
-
-       if (action == HDA_FIXUP_ACT_INIT)
-               alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Set VREF on speaker pins on mba11 */
-static void alc889_fixup_mba11_vref(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t nids[] = { 0x18 };
-
-       if (action == HDA_FIXUP_ACT_INIT)
-               alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Set VREF on speaker pins on mba21 */
-static void alc889_fixup_mba21_vref(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t nids[] = { 0x18, 0x19 };
-
-       if (action == HDA_FIXUP_ACT_INIT)
-               alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
-}
-
-/* Don't take HP output as primary
- * Strangely, the speaker output doesn't work on Vaio Z and some Vaio
- * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05
- */
-static void alc882_fixup_no_primary_hp(struct hda_codec *codec,
-                                      const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.no_primary_hp = 1;
-               spec->gen.no_multi_io = 1;
-       }
-}
-
-static void alc_fixup_bass_chmap(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action);
-
-/* For dual-codec configuration, we need to disable some features to avoid
- * conflicts of kctls and PCM streams
- */
-static void alc_fixup_dual_codecs(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-       /* disable vmaster */
-       spec->gen.suppress_vmaster = 1;
-       /* auto-mute and auto-mic switch don't work with multiple codecs */
-       spec->gen.suppress_auto_mute = 1;
-       spec->gen.suppress_auto_mic = 1;
-       /* disable aamix as well */
-       spec->gen.mixer_nid = 0;
-       /* add location prefix to avoid conflicts */
-       codec->force_pin_prefix = 1;
-}
-
-static void rename_ctl(struct hda_codec *codec, const char *oldname,
-                      const char *newname)
-{
-       struct snd_kcontrol *kctl;
-
-       kctl = snd_hda_find_mixer_ctl(codec, oldname);
-       if (kctl)
-               snd_ctl_rename(codec->card, kctl, newname);
-}
-
-static void alc1220_fixup_gb_dual_codecs(struct hda_codec *codec,
-                                        const struct hda_fixup *fix,
-                                        int action)
-{
-       alc_fixup_dual_codecs(codec, fix, action);
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               /* override card longname to provide a unique UCM profile */
-               strcpy(codec->card->longname, "HDAudio-Gigabyte-ALC1220DualCodecs");
-               break;
-       case HDA_FIXUP_ACT_BUILD:
-               /* rename Capture controls depending on the codec */
-               rename_ctl(codec, "Capture Volume",
-                          codec->addr == 0 ?
-                          "Rear-Panel Capture Volume" :
-                          "Front-Panel Capture Volume");
-               rename_ctl(codec, "Capture Switch",
-                          codec->addr == 0 ?
-                          "Rear-Panel Capture Switch" :
-                          "Front-Panel Capture Switch");
-               break;
-       }
-}
-
-static void alc1220_fixup_gb_x570(struct hda_codec *codec,
-                                    const struct hda_fixup *fix,
-                                    int action)
-{
-       static const hda_nid_t conn1[] = { 0x0c };
-       static const struct coef_fw gb_x570_coefs[] = {
-               WRITE_COEF(0x07, 0x03c0),
-               WRITE_COEF(0x1a, 0x01c1),
-               WRITE_COEF(0x1b, 0x0202),
-               WRITE_COEF(0x43, 0x3005),
-               {}
-       };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
-               snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               alc_process_coef_fw(codec, gb_x570_coefs);
-               break;
-       }
-}
-
-static void alc1220_fixup_clevo_p950(struct hda_codec *codec,
-                                    const struct hda_fixup *fix,
-                                    int action)
-{
-       static const hda_nid_t conn1[] = { 0x0c };
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       alc_update_coef_idx(codec, 0x7, 0, 0x3c3);
-       /* We therefore want to make sure 0x14 (front headphone) and
-        * 0x1b (speakers) use the stereo DAC 0x02
-        */
-       snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
-       snd_hda_override_conn_list(codec, 0x1b, ARRAY_SIZE(conn1), conn1);
-}
-
-static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action);
-
-static void alc1220_fixup_clevo_pb51ed(struct hda_codec *codec,
-                                    const struct hda_fixup *fix,
-                                    int action)
-{
-       alc1220_fixup_clevo_p950(codec, fix, action);
-       alc_fixup_headset_mode_no_hp_mic(codec, fix, action);
-}
-
-static void alc887_asus_hp_automute_hook(struct hda_codec *codec,
-                                        struct hda_jack_callback *jack)
-{
-       struct alc_spec *spec = codec->spec;
-       unsigned int vref;
-
-       snd_hda_gen_hp_automute(codec, jack);
-
-       if (spec->gen.hp_jack_present)
-               vref = AC_PINCTL_VREF_80;
-       else
-               vref = AC_PINCTL_VREF_HIZ;
-       snd_hda_set_pin_ctl(codec, 0x19, PIN_HP | vref);
-}
-
-static void alc887_fixup_asus_jack(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action != HDA_FIXUP_ACT_PROBE)
-               return;
-       snd_hda_set_pin_ctl_cache(codec, 0x1b, PIN_HP);
-       spec->gen.hp_automute_hook = alc887_asus_hp_automute_hook;
-}
-
-static const struct hda_fixup alc882_fixups[] = {
-       [ALC882_FIXUP_ABIT_AW9D_MAX] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x15, 0x01080104 }, /* side */
-                       { 0x16, 0x01011012 }, /* rear */
-                       { 0x17, 0x01016011 }, /* clfe */
-                       { }
-               }
-       },
-       [ALC882_FIXUP_LENOVO_Y530] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x15, 0x99130112 }, /* rear int speakers */
-                       { 0x16, 0x99130111 }, /* subwoofer */
-                       { }
-               }
-       },
-       [ALC882_FIXUP_PB_M5210] = {
-               .type = HDA_FIXUP_PINCTLS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, PIN_VREF50 },
-                       {}
-               }
-       },
-       [ALC882_FIXUP_ACER_ASPIRE_7736] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_sku_ignore,
-       },
-       [ALC882_FIXUP_ASUS_W90V] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x99130110 }, /* fix sequence for CLFE */
-                       { }
-               }
-       },
-       [ALC889_FIXUP_CD] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1c, 0x993301f0 }, /* CD */
-                       { }
-               }
-       },
-       [ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC889_FIXUP_CD,
-       },
-       [ALC889_FIXUP_VAIO_TT] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x17, 0x90170111 }, /* hidden surround speaker */
-                       { }
-               }
-       },
-       [ALC888_FIXUP_EEE1601] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
-                       { 0x20, AC_VERB_SET_PROC_COEF,  0x0838 },
-                       { }
-               }
-       },
-       [ALC886_FIXUP_EAPD] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* change to EAPD mode */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0068 },
-                       { }
-               }
-       },
-       [ALC882_FIXUP_EAPD] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* change to EAPD mode */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 },
-                       { }
-               }
-       },
-       [ALC883_FIXUP_EAPD] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* change to EAPD mode */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
-                       { }
-               }
-       },
-       [ALC883_FIXUP_ACER_EAPD] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* eanable EAPD on Acer laptops */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
-                       { }
-               }
-       },
-       [ALC882_FIXUP_GPIO1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_gpio1,
-       },
-       [ALC882_FIXUP_GPIO2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_gpio2,
-       },
-       [ALC882_FIXUP_GPIO3] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_gpio3,
-       },
-       [ALC882_FIXUP_ASUS_W2JC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_gpio1,
-               .chained = true,
-               .chain_id = ALC882_FIXUP_EAPD,
-       },
-       [ALC889_FIXUP_COEF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc889_fixup_coef,
-       },
-       [ALC882_FIXUP_ACER_ASPIRE_4930G] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x99130111 }, /* CLFE speaker */
-                       { 0x17, 0x99130112 }, /* surround speaker */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC882_FIXUP_GPIO1,
-       },
-       [ALC882_FIXUP_ACER_ASPIRE_8930G] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x99130111 }, /* CLFE speaker */
-                       { 0x1b, 0x99130112 }, /* surround speaker */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC882_FIXUP_ASPIRE_8930G_VERBS,
-       },
-       [ALC882_FIXUP_ASPIRE_8930G_VERBS] = {
-               /* additional init verbs for Acer Aspire 8930G */
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Enable all DACs */
-                       /* DAC DISABLE/MUTE 1? */
-                       /*  setting bits 1-5 disables DAC nids 0x02-0x06
-                        *  apparently. Init=0x38 */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x03 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-                       /* DAC DISABLE/MUTE 2? */
-                       /*  some bit here disables the other DACs.
-                        *  Init=0x4900 */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x08 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0000 },
-                       /* DMIC fix
-                        * This laptop has a stereo digital microphone.
-                        * The mics are only 1cm apart which makes the stereo
-                        * useless. However, either the mic or the ALC889
-                        * makes the signal become a difference/sum signal
-                        * instead of standard stereo, which is annoying.
-                        * So instead we flip this bit which makes the
-                        * codec replicate the sum signal to both channels,
-                        * turning it into a normal mono mic.
-                        */
-                       /* DMIC_CONTROL? Init value = 0x0001 */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0003 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC882_FIXUP_GPIO1,
-       },
-       [ALC885_FIXUP_MACPRO_GPIO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc885_fixup_macpro_gpio,
-       },
-       [ALC889_FIXUP_DAC_ROUTE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc889_fixup_dac_route,
-       },
-       [ALC889_FIXUP_MBP_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc889_fixup_mbp_vref,
-               .chained = true,
-               .chain_id = ALC882_FIXUP_GPIO1,
-       },
-       [ALC889_FIXUP_IMAC91_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc889_fixup_imac91_vref,
-               .chained = true,
-               .chain_id = ALC882_FIXUP_GPIO1,
-       },
-       [ALC889_FIXUP_MBA11_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc889_fixup_mba11_vref,
-               .chained = true,
-               .chain_id = ALC889_FIXUP_MBP_VREF,
-       },
-       [ALC889_FIXUP_MBA21_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc889_fixup_mba21_vref,
-               .chained = true,
-               .chain_id = ALC889_FIXUP_MBP_VREF,
-       },
-       [ALC889_FIXUP_MP11_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc889_fixup_mba11_vref,
-               .chained = true,
-               .chain_id = ALC885_FIXUP_MACPRO_GPIO,
-       },
-       [ALC889_FIXUP_MP41_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc889_fixup_mbp_vref,
-               .chained = true,
-               .chain_id = ALC885_FIXUP_MACPRO_GPIO,
-       },
-       [ALC882_FIXUP_INV_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic,
-       },
-       [ALC882_FIXUP_NO_PRIMARY_HP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc882_fixup_no_primary_hp,
-       },
-       [ALC887_FIXUP_ASUS_BASS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       {0x16, 0x99130130}, /* bass speaker */
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC887_FIXUP_BASS_CHMAP,
-       },
-       [ALC887_FIXUP_BASS_CHMAP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_bass_chmap,
-       },
-       [ALC1220_FIXUP_GB_DUAL_CODECS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc1220_fixup_gb_dual_codecs,
-       },
-       [ALC1220_FIXUP_GB_X570] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc1220_fixup_gb_x570,
-       },
-       [ALC1220_FIXUP_CLEVO_P950] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc1220_fixup_clevo_p950,
-       },
-       [ALC1220_FIXUP_CLEVO_PB51ED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc1220_fixup_clevo_pb51ed,
-       },
-       [ALC1220_FIXUP_CLEVO_PB51ED_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC1220_FIXUP_CLEVO_PB51ED,
-       },
-       [ALC887_FIXUP_ASUS_AUDIO] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x15, 0x02a14150 }, /* use as headset mic, without its own jack detect */
-                       { 0x19, 0x22219420 },
-                       {}
-               },
-       },
-       [ALC887_FIXUP_ASUS_HMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc887_fixup_asus_jack,
-               .chained = true,
-               .chain_id = ALC887_FIXUP_ASUS_AUDIO,
-       },
-       [ALCS1200A_FIXUP_MIC_VREF] = {
-               .type = HDA_FIXUP_PINCTLS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, PIN_VREF50 }, /* rear mic */
-                       { 0x19, PIN_VREF50 }, /* front mic */
-                       {}
-               }
-       },
-       [ALC888VD_FIXUP_MIC_100VREF] = {
-               .type = HDA_FIXUP_PINCTLS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, PIN_VREF100 }, /* headset mic */
-                       {}
-               }
-       },
-};
-
-static const struct hda_quirk alc882_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x006c, "Acer Aspire 9810", ALC883_FIXUP_ACER_EAPD),
-       SND_PCI_QUIRK(0x1025, 0x0090, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
-       SND_PCI_QUIRK(0x1025, 0x0107, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
-       SND_PCI_QUIRK(0x1025, 0x010a, "Acer Ferrari 5000", ALC883_FIXUP_ACER_EAPD),
-       SND_PCI_QUIRK(0x1025, 0x0110, "Acer Aspire", ALC883_FIXUP_ACER_EAPD),
-       SND_PCI_QUIRK(0x1025, 0x0112, "Acer Aspire 9303", ALC883_FIXUP_ACER_EAPD),
-       SND_PCI_QUIRK(0x1025, 0x0121, "Acer Aspire 5920G", ALC883_FIXUP_ACER_EAPD),
-       SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G",
-                     ALC882_FIXUP_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G",
-                     ALC882_FIXUP_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G",
-                     ALC882_FIXUP_ACER_ASPIRE_8930G),
-       SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G",
-                     ALC882_FIXUP_ACER_ASPIRE_8930G),
-       SND_PCI_QUIRK(0x1025, 0x0142, "Acer Aspire 7730G",
-                     ALC882_FIXUP_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x0155, "Packard-Bell M5120", ALC882_FIXUP_PB_M5210),
-       SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
-                     ALC882_FIXUP_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
-                     ALC882_FIXUP_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x021e, "Acer Aspire 5739G",
-                     ALC882_FIXUP_ACER_ASPIRE_4930G),
-       SND_PCI_QUIRK(0x1025, 0x0259, "Acer Aspire 5935", ALC889_FIXUP_DAC_ROUTE),
-       SND_PCI_QUIRK(0x1025, 0x026b, "Acer Aspire 8940G", ALC882_FIXUP_ACER_ASPIRE_8930G),
-       SND_PCI_QUIRK(0x1025, 0x0296, "Acer Aspire 7736z", ALC882_FIXUP_ACER_ASPIRE_7736),
-       SND_PCI_QUIRK(0x1043, 0x13c2, "Asus A7M", ALC882_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V),
-       SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC),
-       SND_PCI_QUIRK(0x1043, 0x2390, "Asus D700SA", ALC887_FIXUP_ASUS_HMIC),
-       SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601),
-       SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS),
-       SND_PCI_QUIRK(0x1043, 0x8691, "ASUS ROG Ranger VIII", ALC882_FIXUP_GPIO3),
-       SND_PCI_QUIRK(0x1043, 0x8797, "ASUS TUF B550M-PLUS", ALCS1200A_FIXUP_MIC_VREF),
-       SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
-       SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
-       SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
-       SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
-       SND_PCI_QUIRK(0x104d, 0x9060, "Sony Vaio VPCL14M1R", ALC882_FIXUP_NO_PRIMARY_HP),
-
-       /* All Apple entries are in codec SSIDs */
-       SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
-       SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF),
-       SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
-       SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF),
-       SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO),
-       SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO),
-       SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
-       SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
-       SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
-       SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
-       SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
-       SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
-       SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO),
-       SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 4,1/5,1", ALC889_FIXUP_MP41_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF),
-       SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_MBA11_VREF),
-
-       SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x10ec, 0x12d8, "iBase Elo Touch", ALC888VD_FIXUP_MIC_100VREF),
-       SND_PCI_QUIRK(0x13fe, 0x1009, "Advantech MIT-W101", ALC886_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1458, 0xa0b8, "Gigabyte AZ370-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
-       SND_PCI_QUIRK(0x1458, 0xa0cd, "Gigabyte X570 Aorus Master", ALC1220_FIXUP_GB_X570),
-       SND_PCI_QUIRK(0x1458, 0xa0ce, "Gigabyte X570 Aorus Xtreme", ALC1220_FIXUP_GB_X570),
-       SND_PCI_QUIRK(0x1458, 0xa0d5, "Gigabyte X570S Aorus Master", ALC1220_FIXUP_GB_X570),
-       SND_PCI_QUIRK(0x1462, 0x11f7, "MSI-GE63", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1462, 0x1228, "MSI-GP63", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1462, 0x1229, "MSI-GP73", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1462, 0x1275, "MSI-GL63", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1462, 0x1276, "MSI-GL73", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1462, 0x1293, "MSI-GP65", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD),
-       SND_PCI_QUIRK(0x1462, 0xcc34, "MSI Godlike X570", ALC1220_FIXUP_GB_DUAL_CODECS),
-       SND_PCI_QUIRK(0x1462, 0xda57, "MSI Z270-Gaming", ALC1220_FIXUP_GB_DUAL_CODECS),
-       SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3),
-       SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX),
-       SND_PCI_QUIRK(0x1558, 0x3702, "Clevo X370SN[VW]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x50d3, "Clevo PC50[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x5802, "Clevo X58[05]WN[RST]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x65d1, "Clevo PB51[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x65d2, "Clevo PB51R[CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x65e1, "Clevo PB51[ED][DF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x65e5, "Clevo PC50D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x65f1, "Clevo PC50HS", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x65f5, "Clevo PD50PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x66a2, "Clevo PE60RNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x66a6, "Clevo PE60SN[CDE]-[GS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x67d1, "Clevo PB71[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x67e1, "Clevo PB71[DE][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x67e5, "Clevo PC70D[PRS](?:-D|-G)?", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x67f1, "Clevo PC70H[PRS]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x67f5, "Clevo PD70PN[NRT]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x70d1, "Clevo PC70[ER][CDF]", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x7714, "Clevo X170SM", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK(0x1558, 0x7715, "Clevo X170KM-G", ALC1220_FIXUP_CLEVO_PB51ED),
-       SND_PCI_QUIRK(0x1558, 0x9501, "Clevo P950HR", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x9506, "Clevo P955HQ", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x950a, "Clevo P955H[PR]", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x95e1, "Clevo P95xER", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x95e2, "Clevo P950ER", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x95e3, "Clevo P955[ER]T", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x95e4, "Clevo P955ER", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x95e5, "Clevo P955EE6", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x95e6, "Clevo P950R[CDF]", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x96e1, "Clevo P960[ER][CDFN]-K", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x97e1, "Clevo P970[ER][CDFN]", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0x97e2, "Clevo P970RC-M", ALC1220_FIXUP_CLEVO_P950),
-       SND_PCI_QUIRK(0x1558, 0xd502, "Clevo PD50SNE", ALC1220_FIXUP_CLEVO_PB51ED_PINS),
-       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Y530", ALC882_FIXUP_LENOVO_Y530),
-       SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_FIXUP_COEF),
-       {}
-};
-
-static const struct hda_model_fixup alc882_fixup_models[] = {
-       {.id = ALC882_FIXUP_ABIT_AW9D_MAX, .name = "abit-aw9d"},
-       {.id = ALC882_FIXUP_LENOVO_Y530, .name = "lenovo-y530"},
-       {.id = ALC882_FIXUP_ACER_ASPIRE_7736, .name = "acer-aspire-7736"},
-       {.id = ALC882_FIXUP_ASUS_W90V, .name = "asus-w90v"},
-       {.id = ALC889_FIXUP_CD, .name = "cd"},
-       {.id = ALC889_FIXUP_FRONT_HP_NO_PRESENCE, .name = "no-front-hp"},
-       {.id = ALC889_FIXUP_VAIO_TT, .name = "vaio-tt"},
-       {.id = ALC888_FIXUP_EEE1601, .name = "eee1601"},
-       {.id = ALC882_FIXUP_EAPD, .name = "alc882-eapd"},
-       {.id = ALC883_FIXUP_EAPD, .name = "alc883-eapd"},
-       {.id = ALC882_FIXUP_GPIO1, .name = "gpio1"},
-       {.id = ALC882_FIXUP_GPIO2, .name = "gpio2"},
-       {.id = ALC882_FIXUP_GPIO3, .name = "gpio3"},
-       {.id = ALC889_FIXUP_COEF, .name = "alc889-coef"},
-       {.id = ALC882_FIXUP_ASUS_W2JC, .name = "asus-w2jc"},
-       {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"},
-       {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"},
-       {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"},
-       {.id = ALC885_FIXUP_MACPRO_GPIO, .name = "macpro-gpio"},
-       {.id = ALC889_FIXUP_DAC_ROUTE, .name = "dac-route"},
-       {.id = ALC889_FIXUP_MBP_VREF, .name = "mbp-vref"},
-       {.id = ALC889_FIXUP_IMAC91_VREF, .name = "imac91-vref"},
-       {.id = ALC889_FIXUP_MBA11_VREF, .name = "mba11-vref"},
-       {.id = ALC889_FIXUP_MBA21_VREF, .name = "mba21-vref"},
-       {.id = ALC889_FIXUP_MP11_VREF, .name = "mp11-vref"},
-       {.id = ALC889_FIXUP_MP41_VREF, .name = "mp41-vref"},
-       {.id = ALC882_FIXUP_INV_DMIC, .name = "inv-dmic"},
-       {.id = ALC882_FIXUP_NO_PRIMARY_HP, .name = "no-primary-hp"},
-       {.id = ALC887_FIXUP_ASUS_BASS, .name = "asus-bass"},
-       {.id = ALC1220_FIXUP_GB_DUAL_CODECS, .name = "dual-codecs"},
-       {.id = ALC1220_FIXUP_GB_X570, .name = "gb-x570"},
-       {.id = ALC1220_FIXUP_CLEVO_P950, .name = "clevo-p950"},
-       {}
-};
-
-static const struct snd_hda_pin_quirk alc882_pin_fixup_tbl[] = {
-       SND_HDA_PIN_QUIRK(0x10ec1220, 0x1043, "ASUS", ALC1220_FIXUP_CLEVO_P950,
-               {0x14, 0x01014010},
-               {0x15, 0x01011012},
-               {0x16, 0x01016011},
-               {0x18, 0x01a19040},
-               {0x19, 0x02a19050},
-               {0x1a, 0x0181304f},
-               {0x1b, 0x0221401f},
-               {0x1e, 0x01456130}),
-       SND_HDA_PIN_QUIRK(0x10ec1220, 0x1462, "MS-7C35", ALC1220_FIXUP_CLEVO_P950,
-               {0x14, 0x01015010},
-               {0x15, 0x01011012},
-               {0x16, 0x01011011},
-               {0x18, 0x01a11040},
-               {0x19, 0x02a19050},
-               {0x1a, 0x0181104f},
-               {0x1b, 0x0221401f},
-               {0x1e, 0x01451130}),
-       {}
-};
-
-/*
- * BIOS auto configuration
- */
-/* almost identical with ALC880 parser... */
-static int alc882_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc882_ignore[] = { 0x1d, 0 };
-       static const hda_nid_t alc882_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-       return alc_parse_auto_config(codec, alc882_ignore, alc882_ssids);
-}
-
-/*
- */
-static int patch_alc882(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err;
-
-       err = alc_alloc_spec(codec, 0x0b);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0882:
-       case 0x10ec0885:
-       case 0x10ec0900:
-       case 0x10ec0b00:
-       case 0x10ec1220:
-               break;
-       default:
-               /* ALC883 and variants */
-               alc_fix_pll_init(codec, 0x20, 0x0a, 10);
-               break;
-       }
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl,
-                      alc882_fixups);
-       snd_hda_pick_pin_fixup(codec, alc882_pin_fixup_tbl, alc882_fixups, true);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       alc_auto_parse_customize_define(codec);
-
-       if (has_cdefine_beep(codec))
-               spec->gen.beep_nid = 0x01;
-
-       /* automatic parse from the BIOS config */
-       err = alc882_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!spec->gen.no_analog && spec->gen.beep_nid) {
-               err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-               if (err < 0)
-                       goto error;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-
-/*
- * ALC262 support
- */
-static int alc262_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc262_ignore[] = { 0x1d, 0 };
-       static const hda_nid_t alc262_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-       return alc_parse_auto_config(codec, alc262_ignore, alc262_ssids);
-}
-
-/*
- * Pin config fixes
- */
-enum {
-       ALC262_FIXUP_FSC_H270,
-       ALC262_FIXUP_FSC_S7110,
-       ALC262_FIXUP_HP_Z200,
-       ALC262_FIXUP_TYAN,
-       ALC262_FIXUP_LENOVO_3000,
-       ALC262_FIXUP_BENQ,
-       ALC262_FIXUP_BENQ_T31,
-       ALC262_FIXUP_INV_DMIC,
-       ALC262_FIXUP_INTEL_BAYLEYBAY,
-};
-
-static const struct hda_fixup alc262_fixups[] = {
-       [ALC262_FIXUP_FSC_H270] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x0221142f }, /* front HP */
-                       { 0x1b, 0x0121141f }, /* rear HP */
-                       { }
-               }
-       },
-       [ALC262_FIXUP_FSC_S7110] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x15, 0x90170110 }, /* speaker */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC262_FIXUP_BENQ,
-       },
-       [ALC262_FIXUP_HP_Z200] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x99130120 }, /* internal speaker */
-                       { }
-               }
-       },
-       [ALC262_FIXUP_TYAN] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x1993e1f0 }, /* int AUX */
-                       { }
-               }
-       },
-       [ALC262_FIXUP_LENOVO_3000] = {
-               .type = HDA_FIXUP_PINCTLS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, PIN_VREF50 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC262_FIXUP_BENQ,
-       },
-       [ALC262_FIXUP_BENQ] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 },
-                       {}
-               }
-       },
-       [ALC262_FIXUP_BENQ_T31] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 },
-                       {}
-               }
-       },
-       [ALC262_FIXUP_INV_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic,
-       },
-       [ALC262_FIXUP_INTEL_BAYLEYBAY] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_no_depop_delay,
-       },
-};
-
-static const struct hda_quirk alc262_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200),
-       SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110),
-       SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ),
-       SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN),
-       SND_PCI_QUIRK(0x1734, 0x1141, "FSC ESPRIMO U9210", ALC262_FIXUP_FSC_H270),
-       SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270),
-       SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000),
-       SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ),
-       SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31),
-       SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY),
-       {}
-};
-
-static const struct hda_model_fixup alc262_fixup_models[] = {
-       {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"},
-       {.id = ALC262_FIXUP_FSC_H270, .name = "fsc-h270"},
-       {.id = ALC262_FIXUP_FSC_S7110, .name = "fsc-s7110"},
-       {.id = ALC262_FIXUP_HP_Z200, .name = "hp-z200"},
-       {.id = ALC262_FIXUP_TYAN, .name = "tyan"},
-       {.id = ALC262_FIXUP_LENOVO_3000, .name = "lenovo-3000"},
-       {.id = ALC262_FIXUP_BENQ, .name = "benq"},
-       {.id = ALC262_FIXUP_BENQ_T31, .name = "benq-t31"},
-       {.id = ALC262_FIXUP_INTEL_BAYLEYBAY, .name = "bayleybay"},
-       {}
-};
-
-/*
- */
-static int patch_alc262(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err;
-
-       err = alc_alloc_spec(codec, 0x0b);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->gen.shared_mic_vref_pin = 0x18;
-
-       spec->shutup = alc_eapd_shutup;
-
-#if 0
-       /* pshou 07/11/05  set a zero PCM sample to DAC when FIFO is
-        * under-run
-        */
-       alc_update_coefex_idx(codec, 0x1a, 7, 0, 0x80);
-#endif
-       alc_fix_pll_init(codec, 0x20, 0x0a, 10);
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl,
-                      alc262_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       alc_auto_parse_customize_define(codec);
-
-       if (has_cdefine_beep(codec))
-               spec->gen.beep_nid = 0x01;
-
-       /* automatic parse from the BIOS config */
-       err = alc262_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!spec->gen.no_analog && spec->gen.beep_nid) {
-               err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-               if (err < 0)
-                       goto error;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-/*
- *  ALC268
- */
-/* bind Beep switches of both NID 0x0f and 0x10 */
-static int alc268_beep_switch_put(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned long pval;
-       int err;
-
-       mutex_lock(&codec->control_mutex);
-       pval = kcontrol->private_value;
-       kcontrol->private_value = (pval & ~0xff) | 0x0f;
-       err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-       if (err >= 0) {
-               kcontrol->private_value = (pval & ~0xff) | 0x10;
-               err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol);
-       }
-       kcontrol->private_value = pval;
-       mutex_unlock(&codec->control_mutex);
-       return err;
-}
-
-static const struct snd_kcontrol_new alc268_beep_mixer[] = {
-       HDA_CODEC_VOLUME("Beep Playback Volume", 0x1d, 0x0, HDA_INPUT),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Beep Playback Switch",
-               .subdevice = HDA_SUBDEV_AMP_FLAG,
-               .info = snd_hda_mixer_amp_switch_info,
-               .get = snd_hda_mixer_amp_switch_get,
-               .put = alc268_beep_switch_put,
-               .private_value = HDA_COMPOSE_AMP_VAL(0x0f, 3, 1, HDA_INPUT)
-       },
-};
-
-/* set PCBEEP vol = 0, mute connections */
-static const struct hda_verb alc268_beep_init_verbs[] = {
-       {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)},
-       {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)},
-       { }
-};
-
-enum {
-       ALC268_FIXUP_INV_DMIC,
-       ALC268_FIXUP_HP_EAPD,
-       ALC268_FIXUP_SPDIF,
-};
-
-static const struct hda_fixup alc268_fixups[] = {
-       [ALC268_FIXUP_INV_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic,
-       },
-       [ALC268_FIXUP_HP_EAPD] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0},
-                       {}
-               }
-       },
-       [ALC268_FIXUP_SPDIF] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1e, 0x014b1180 }, /* enable SPDIF out */
-                       {}
-               }
-       },
-};
-
-static const struct hda_model_fixup alc268_fixup_models[] = {
-       {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"},
-       {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"},
-       {.id = ALC268_FIXUP_SPDIF, .name = "spdif"},
-       {}
-};
-
-static const struct hda_quirk alc268_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF),
-       SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC),
-       /* below is codec SSID since multiple Toshiba laptops have the
-        * same PCI SSID 1179:ff00
-        */
-       SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD),
-       {}
-};
-
-/*
- * BIOS auto configuration
- */
-static int alc268_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-       return alc_parse_auto_config(codec, NULL, alc268_ssids);
-}
-
-/*
- */
-static int patch_alc268(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int i, err;
-
-       /* ALC268 has no aa-loopback mixer */
-       err = alc_alloc_spec(codec, 0);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       if (has_cdefine_beep(codec))
-               spec->gen.beep_nid = 0x01;
-
-       spec->shutup = alc_eapd_shutup;
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       /* automatic parse from the BIOS config */
-       err = alc268_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (err > 0 && !spec->gen.no_analog &&
-           spec->gen.autocfg.speaker_pins[0] != 0x1d) {
-               for (i = 0; i < ARRAY_SIZE(alc268_beep_mixer); i++) {
-                       if (!snd_hda_gen_add_kctl(&spec->gen, NULL,
-                                                 &alc268_beep_mixer[i])) {
-                               err = -ENOMEM;
-                               goto error;
-                       }
-               }
-               snd_hda_add_verbs(codec, alc268_beep_init_verbs);
-               if (!query_amp_caps(codec, 0x1d, HDA_INPUT))
-                       /* override the amp caps for beep generator */
-                       snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT,
-                                         (0x0c << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x0c << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x07 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (0 << AC_AMPCAP_MUTE_SHIFT));
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-/*
- * ALC269
- */
-
-static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = {
-       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
-};
-
-static const struct hda_pcm_stream alc269_44k_pcm_analog_capture = {
-       .rates = SNDRV_PCM_RATE_44100, /* fixed rate */
-};
-
-/* different alc269-variants */
-enum {
-       ALC269_TYPE_ALC269VA,
-       ALC269_TYPE_ALC269VB,
-       ALC269_TYPE_ALC269VC,
-       ALC269_TYPE_ALC269VD,
-       ALC269_TYPE_ALC280,
-       ALC269_TYPE_ALC282,
-       ALC269_TYPE_ALC283,
-       ALC269_TYPE_ALC284,
-       ALC269_TYPE_ALC293,
-       ALC269_TYPE_ALC286,
-       ALC269_TYPE_ALC298,
-       ALC269_TYPE_ALC255,
-       ALC269_TYPE_ALC256,
-       ALC269_TYPE_ALC257,
-       ALC269_TYPE_ALC215,
-       ALC269_TYPE_ALC225,
-       ALC269_TYPE_ALC245,
-       ALC269_TYPE_ALC287,
-       ALC269_TYPE_ALC294,
-       ALC269_TYPE_ALC300,
-       ALC269_TYPE_ALC623,
-       ALC269_TYPE_ALC700,
-};
-
-/*
- * BIOS auto configuration
- */
-static int alc269_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc269_ignore[] = { 0x1d, 0 };
-       static const hda_nid_t alc269_ssids[] = { 0, 0x1b, 0x14, 0x21 };
-       static const hda_nid_t alc269va_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-       struct alc_spec *spec = codec->spec;
-       const hda_nid_t *ssids;
-
-       switch (spec->codec_variant) {
-       case ALC269_TYPE_ALC269VA:
-       case ALC269_TYPE_ALC269VC:
-       case ALC269_TYPE_ALC280:
-       case ALC269_TYPE_ALC284:
-       case ALC269_TYPE_ALC293:
-               ssids = alc269va_ssids;
-               break;
-       case ALC269_TYPE_ALC269VB:
-       case ALC269_TYPE_ALC269VD:
-       case ALC269_TYPE_ALC282:
-       case ALC269_TYPE_ALC283:
-       case ALC269_TYPE_ALC286:
-       case ALC269_TYPE_ALC298:
-       case ALC269_TYPE_ALC255:
-       case ALC269_TYPE_ALC256:
-       case ALC269_TYPE_ALC257:
-       case ALC269_TYPE_ALC215:
-       case ALC269_TYPE_ALC225:
-       case ALC269_TYPE_ALC245:
-       case ALC269_TYPE_ALC287:
-       case ALC269_TYPE_ALC294:
-       case ALC269_TYPE_ALC300:
-       case ALC269_TYPE_ALC623:
-       case ALC269_TYPE_ALC700:
-               ssids = alc269_ssids;
-               break;
-       default:
-               ssids = alc269_ssids;
-               break;
-       }
-
-       return alc_parse_auto_config(codec, alc269_ignore, ssids);
-}
-
-static const struct hda_jack_keymap alc_headset_btn_keymap[] = {
-       { SND_JACK_BTN_0, KEY_PLAYPAUSE },
-       { SND_JACK_BTN_1, KEY_VOICECOMMAND },
-       { SND_JACK_BTN_2, KEY_VOLUMEUP },
-       { SND_JACK_BTN_3, KEY_VOLUMEDOWN },
-       {}
-};
-
-static void alc_headset_btn_callback(struct hda_codec *codec,
-                                    struct hda_jack_callback *jack)
-{
-       int report = 0;
-
-       if (jack->unsol_res & (7 << 13))
-               report |= SND_JACK_BTN_0;
-
-       if (jack->unsol_res  & (1 << 16 | 3 << 8))
-               report |= SND_JACK_BTN_1;
-
-       /* Volume up key */
-       if (jack->unsol_res & (7 << 23))
-               report |= SND_JACK_BTN_2;
-
-       /* Volume down key */
-       if (jack->unsol_res & (7 << 10))
-               report |= SND_JACK_BTN_3;
-
-       snd_hda_jack_set_button_state(codec, jack->nid, report);
-}
-
-static void alc_disable_headset_jack_key(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (!spec->has_hs_key)
-               return;
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0215:
-       case 0x10ec0225:
-       case 0x10ec0285:
-       case 0x10ec0287:
-       case 0x10ec0295:
-       case 0x10ec0289:
-       case 0x10ec0299:
-               alc_write_coef_idx(codec, 0x48, 0x0);
-               alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
-               alc_update_coef_idx(codec, 0x44, 0x0045 << 8, 0x0);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x10ec0257:
-       case 0x19e58326:
-               alc_write_coef_idx(codec, 0x48, 0x0);
-               alc_update_coef_idx(codec, 0x49, 0x0045, 0x0);
-               break;
-       }
-}
-
-static void alc_enable_headset_jack_key(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (!spec->has_hs_key)
-               return;
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0215:
-       case 0x10ec0225:
-       case 0x10ec0285:
-       case 0x10ec0287:
-       case 0x10ec0295:
-       case 0x10ec0289:
-       case 0x10ec0299:
-               alc_write_coef_idx(codec, 0x48, 0xd011);
-               alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
-               alc_update_coef_idx(codec, 0x44, 0x007f << 8, 0x0045 << 8);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x10ec0257:
-       case 0x19e58326:
-               alc_write_coef_idx(codec, 0x48, 0xd011);
-               alc_update_coef_idx(codec, 0x49, 0x007f, 0x0045);
-               break;
-       }
-}
-
-static void alc_fixup_headset_jack(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->has_hs_key = 1;
-               snd_hda_jack_detect_enable_callback(codec, 0x55,
-                                                   alc_headset_btn_callback);
-               break;
-       case HDA_FIXUP_ACT_BUILD:
-               hp_pin = alc_get_hp_pin(spec);
-               if (!hp_pin || snd_hda_jack_bind_keymap(codec, 0x55,
-                                                       alc_headset_btn_keymap,
-                                                       hp_pin))
-                       snd_hda_jack_add_kctl(codec, 0x55, "Headset Jack",
-                                             false, SND_JACK_HEADSET,
-                                             alc_headset_btn_keymap);
-
-               alc_enable_headset_jack_key(codec);
-               break;
-       }
-}
-
-static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up)
-{
-       alc_update_coef_idx(codec, 0x04, 1 << 11, power_up ? (1 << 11) : 0);
-}
-
-static void alc269_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
-               alc269vb_toggle_power_output(codec, 0);
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
-                       (alc_get_coef0(codec) & 0x00ff) == 0x018) {
-               msleep(150);
-       }
-       alc_shutup_pins(codec);
-}
-
-static const struct coef_fw alc282_coefs[] = {
-       WRITE_COEF(0x03, 0x0002), /* Power Down Control */
-       UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
-       WRITE_COEF(0x07, 0x0200), /* DMIC control */
-       UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
-       UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
-       WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */
-       WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */
-       WRITE_COEF(0x0e, 0x6e00), /* LDO1/2/3, DAC/ADC */
-       UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */
-       UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */
-       WRITE_COEF(0x6f, 0x0), /* Class D test 4 */
-       UPDATE_COEF(0x0c, 0xfe00, 0), /* IO power down directly */
-       WRITE_COEF(0x34, 0xa0c0), /* ANC */
-       UPDATE_COEF(0x16, 0x0008, 0), /* AGC MUX */
-       UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */
-       UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */
-       WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */
-       WRITE_COEF(0x63, 0x2902), /* PLL */
-       WRITE_COEF(0x68, 0xa080), /* capless control 2 */
-       WRITE_COEF(0x69, 0x3400), /* capless control 3 */
-       WRITE_COEF(0x6a, 0x2f3e), /* capless control 4 */
-       WRITE_COEF(0x6b, 0x0), /* capless control 5 */
-       UPDATE_COEF(0x6d, 0x0fff, 0x0900), /* class D test 2 */
-       WRITE_COEF(0x6e, 0x110a), /* class D test 3 */
-       UPDATE_COEF(0x70, 0x00f8, 0x00d8), /* class D test 5 */
-       WRITE_COEF(0x71, 0x0014), /* class D test 6 */
-       WRITE_COEF(0x72, 0xc2ba), /* classD OCP */
-       UPDATE_COEF(0x77, 0x0f80, 0), /* classD pure DC test */
-       WRITE_COEF(0x6c, 0xfc06), /* Class D amp control */
-       {}
-};
-
-static void alc282_restore_default_value(struct hda_codec *codec)
-{
-       alc_process_coef_fw(codec, alc282_coefs);
-}
-
-static void alc282_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp_pin_sense;
-       int coef78;
-
-       alc282_restore_default_value(codec);
-
-       if (!hp_pin)
-               return;
-       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-       coef78 = alc_read_coef_idx(codec, 0x78);
-
-       /* Index 0x78 Direct Drive HP AMP LPM Control 1 */
-       /* Headphone capless set to high power mode */
-       alc_write_coef_idx(codec, 0x78, 0x9004);
-
-       if (hp_pin_sense)
-               msleep(2);
-
-       snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-       if (hp_pin_sense)
-               msleep(85);
-
-       snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-
-       if (hp_pin_sense)
-               msleep(100);
-
-       /* Headphone capless set to normal mode */
-       alc_write_coef_idx(codec, 0x78, coef78);
-}
-
-static void alc282_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp_pin_sense;
-       int coef78;
-
-       if (!hp_pin) {
-               alc269_shutup(codec);
-               return;
-       }
-
-       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-       coef78 = alc_read_coef_idx(codec, 0x78);
-       alc_write_coef_idx(codec, 0x78, 0x9004);
-
-       if (hp_pin_sense)
-               msleep(2);
-
-       snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-       if (hp_pin_sense)
-               msleep(85);
-
-       if (!spec->no_shutup_pins)
-               snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
-       if (hp_pin_sense)
-               msleep(100);
-
-       alc_auto_setup_eapd(codec, false);
-       alc_shutup_pins(codec);
-       alc_write_coef_idx(codec, 0x78, coef78);
-}
-
-static const struct coef_fw alc283_coefs[] = {
-       WRITE_COEF(0x03, 0x0002), /* Power Down Control */
-       UPDATE_COEF(0x05, 0xff3f, 0x0700), /* FIFO and filter clock */
-       WRITE_COEF(0x07, 0x0200), /* DMIC control */
-       UPDATE_COEF(0x06, 0x00f0, 0), /* Analog clock */
-       UPDATE_COEF(0x08, 0xfffc, 0x0c2c), /* JD */
-       WRITE_COEF(0x0a, 0xcccc), /* JD offset1 */
-       WRITE_COEF(0x0b, 0xcccc), /* JD offset2 */
-       WRITE_COEF(0x0e, 0x6fc0), /* LDO1/2/3, DAC/ADC */
-       UPDATE_COEF(0x0f, 0xf800, 0x1000), /* JD */
-       UPDATE_COEF(0x10, 0xfc00, 0x0c00), /* Capless */
-       WRITE_COEF(0x3a, 0x0), /* Class D test 4 */
-       UPDATE_COEF(0x0c, 0xfe00, 0x0), /* IO power down directly */
-       WRITE_COEF(0x22, 0xa0c0), /* ANC */
-       UPDATE_COEFEX(0x53, 0x01, 0x000f, 0x0008), /* AGC MUX */
-       UPDATE_COEF(0x1d, 0x00e0, 0), /* DAC simple content protection */
-       UPDATE_COEF(0x1f, 0x00e0, 0), /* ADC simple content protection */
-       WRITE_COEF(0x21, 0x8804), /* DAC ADC Zero Detection */
-       WRITE_COEF(0x2e, 0x2902), /* PLL */
-       WRITE_COEF(0x33, 0xa080), /* capless control 2 */
-       WRITE_COEF(0x34, 0x3400), /* capless control 3 */
-       WRITE_COEF(0x35, 0x2f3e), /* capless control 4 */
-       WRITE_COEF(0x36, 0x0), /* capless control 5 */
-       UPDATE_COEF(0x38, 0x0fff, 0x0900), /* class D test 2 */
-       WRITE_COEF(0x39, 0x110a), /* class D test 3 */
-       UPDATE_COEF(0x3b, 0x00f8, 0x00d8), /* class D test 5 */
-       WRITE_COEF(0x3c, 0x0014), /* class D test 6 */
-       WRITE_COEF(0x3d, 0xc2ba), /* classD OCP */
-       UPDATE_COEF(0x42, 0x0f80, 0x0), /* classD pure DC test */
-       WRITE_COEF(0x49, 0x0), /* test mode */
-       UPDATE_COEF(0x40, 0xf800, 0x9800), /* Class D DC enable */
-       UPDATE_COEF(0x42, 0xf000, 0x2000), /* DC offset */
-       WRITE_COEF(0x37, 0xfc06), /* Class D amp control */
-       UPDATE_COEF(0x1b, 0x8000, 0), /* HP JD control */
-       {}
-};
-
-static void alc283_restore_default_value(struct hda_codec *codec)
-{
-       alc_process_coef_fw(codec, alc283_coefs);
-}
-
-static void alc283_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp_pin_sense;
-
-       alc283_restore_default_value(codec);
-
-       if (!hp_pin)
-               return;
-
-       msleep(30);
-       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-
-       /* Index 0x43 Direct Drive HP AMP LPM Control 1 */
-       /* Headphone capless set to high power mode */
-       alc_write_coef_idx(codec, 0x43, 0x9004);
-
-       snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-       if (hp_pin_sense)
-               msleep(85);
-
-       snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-
-       if (hp_pin_sense)
-               msleep(85);
-       /* Index 0x46 Combo jack auto switch control 2 */
-       /* 3k pull low control for Headset jack. */
-       alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
-       /* Headphone capless set to normal mode */
-       alc_write_coef_idx(codec, 0x43, 0x9614);
-}
-
-static void alc283_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp_pin_sense;
-
-       if (!hp_pin) {
-               alc269_shutup(codec);
-               return;
-       }
-
-       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-
-       alc_write_coef_idx(codec, 0x43, 0x9004);
-
-       /*depop hp during suspend*/
-       alc_write_coef_idx(codec, 0x06, 0x2100);
-
-       snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-       if (hp_pin_sense)
-               msleep(100);
-
-       if (!spec->no_shutup_pins)
-               snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
-       alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
-
-       if (hp_pin_sense)
-               msleep(100);
-       alc_auto_setup_eapd(codec, false);
-       alc_shutup_pins(codec);
-       alc_write_coef_idx(codec, 0x43, 0x9614);
-}
-
-static void alc256_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp_pin_sense;
-
-       if (spec->ultra_low_power) {
-               alc_update_coef_idx(codec, 0x03, 1<<1, 1<<1);
-               alc_update_coef_idx(codec, 0x08, 3<<2, 3<<2);
-               alc_update_coef_idx(codec, 0x08, 7<<4, 0);
-               alc_update_coef_idx(codec, 0x3b, 1<<15, 0);
-               alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
-               msleep(30);
-       }
-
-       if (!hp_pin)
-               hp_pin = 0x21;
-
-       msleep(30);
-
-       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-
-       if (hp_pin_sense) {
-               msleep(2);
-               alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
-
-               snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-
-               msleep(75);
-
-               snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-
-               msleep(75);
-               alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
-       }
-       alc_update_coef_idx(codec, 0x46, 3 << 12, 0);
-       alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 1 << 15); /* Clear bit */
-       alc_update_coefex_idx(codec, 0x53, 0x02, 0x8000, 0 << 15);
-       /*
-        * Expose headphone mic (or possibly Line In on some machines) instead
-        * of PC Beep on 1Ah, and disable 1Ah loopback for all outputs. See
-        * Documentation/sound/hd-audio/realtek-pc-beep.rst for details of
-        * this register.
-        */
-       alc_write_coef_idx(codec, 0x36, 0x5757);
-}
-
-static void alc256_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp_pin_sense;
-
-       if (!hp_pin)
-               hp_pin = 0x21;
-
-       alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
-       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-
-       if (hp_pin_sense) {
-               msleep(2);
-
-               snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-               msleep(75);
-
-       /* 3k pull low control for Headset jack. */
-       /* NOTE: call this before clearing the pin, otherwise codec stalls */
-       /* If disable 3k pulldown control for alc257, the Mic detection will not work correctly
-        * when booting with headset plugged. So skip setting it for the codec alc257
-        */
-               if (spec->en_3kpull_low)
-                       alc_update_coef_idx(codec, 0x46, 0, 3 << 12);
-
-               if (!spec->no_shutup_pins)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
-               msleep(75);
-       }
-
-       alc_auto_setup_eapd(codec, false);
-       alc_shutup_pins(codec);
-       if (spec->ultra_low_power) {
-               msleep(50);
-               alc_update_coef_idx(codec, 0x03, 1<<1, 0);
-               alc_update_coef_idx(codec, 0x08, 7<<4, 7<<4);
-               alc_update_coef_idx(codec, 0x08, 3<<2, 0);
-               alc_update_coef_idx(codec, 0x3b, 1<<15, 1<<15);
-               alc_update_coef_idx(codec, 0x0e, 7<<6, 0);
-               msleep(30);
-       }
-}
-
-static void alc285_hp_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       int i, val;
-       int coef38, coef0d, coef36;
-
-       alc_write_coefex_idx(codec, 0x58, 0x00, 0x1888); /* write default value */
-       alc_update_coef_idx(codec, 0x4a, 1<<15, 1<<15); /* Reset HP JD */
-       coef38 = alc_read_coef_idx(codec, 0x38); /* Amp control */
-       coef0d = alc_read_coef_idx(codec, 0x0d); /* Digital Misc control */
-       coef36 = alc_read_coef_idx(codec, 0x36); /* Passthrough Control */
-       alc_update_coef_idx(codec, 0x38, 1<<4, 0x0);
-       alc_update_coef_idx(codec, 0x0d, 0x110, 0x0);
-
-       alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
-
-       if (hp_pin)
-               snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-       msleep(130);
-       alc_update_coef_idx(codec, 0x36, 1<<14, 1<<14);
-       alc_update_coef_idx(codec, 0x36, 1<<13, 0x0);
-
-       if (hp_pin)
-               snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-       msleep(10);
-       alc_write_coef_idx(codec, 0x67, 0x0); /* Set HP depop to manual mode */
-       alc_write_coefex_idx(codec, 0x58, 0x00, 0x7880);
-       alc_write_coefex_idx(codec, 0x58, 0x0f, 0xf049);
-       alc_update_coefex_idx(codec, 0x58, 0x03, 0x00f0, 0x00c0);
-
-       alc_write_coefex_idx(codec, 0x58, 0x00, 0xf888); /* HP depop procedure start */
-       val = alc_read_coefex_idx(codec, 0x58, 0x00);
-       for (i = 0; i < 20 && val & 0x8000; i++) {
-               msleep(50);
-               val = alc_read_coefex_idx(codec, 0x58, 0x00);
-       } /* Wait for depop procedure finish  */
-
-       alc_write_coefex_idx(codec, 0x58, 0x00, val); /* write back the result */
-       alc_update_coef_idx(codec, 0x38, 1<<4, coef38);
-       alc_update_coef_idx(codec, 0x0d, 0x110, coef0d);
-       alc_update_coef_idx(codec, 0x36, 3<<13, coef36);
-
-       msleep(50);
-       alc_update_coef_idx(codec, 0x4a, 1<<15, 0);
-}
-
-static void alc225_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp1_pin_sense, hp2_pin_sense;
-
-       if (spec->ultra_low_power) {
-               alc_update_coef_idx(codec, 0x08, 0x0f << 2, 3<<2);
-               alc_update_coef_idx(codec, 0x0e, 7<<6, 7<<6);
-               alc_update_coef_idx(codec, 0x33, 1<<11, 0);
-               msleep(30);
-       }
-
-       if (spec->codec_variant != ALC269_TYPE_ALC287 &&
-               spec->codec_variant != ALC269_TYPE_ALC245)
-               /* required only at boot or S3 and S4 resume time */
-               if (!spec->done_hp_init ||
-                       is_s3_resume(codec) ||
-                       is_s4_resume(codec)) {
-                       alc285_hp_init(codec);
-                       spec->done_hp_init = true;
-               }
-
-       if (!hp_pin)
-               hp_pin = 0x21;
-       msleep(30);
-
-       hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-       hp2_pin_sense = snd_hda_jack_detect(codec, 0x16);
-
-       if (hp1_pin_sense || hp2_pin_sense) {
-               msleep(2);
-               alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x1); /* Low power */
-
-               if (hp1_pin_sense)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-               if (hp2_pin_sense)
-                       snd_hda_codec_write(codec, 0x16, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-               msleep(75);
-
-               if (hp1_pin_sense)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-               if (hp2_pin_sense)
-                       snd_hda_codec_write(codec, 0x16, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-
-               msleep(75);
-               alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
-               alc_update_coefex_idx(codec, 0x57, 0x04, 0x0007, 0x4); /* Hight power */
-       }
-}
-
-static void alc225_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp1_pin_sense, hp2_pin_sense;
-
-       if (!hp_pin)
-               hp_pin = 0x21;
-
-       hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-       hp2_pin_sense = snd_hda_jack_detect(codec, 0x16);
-
-       if (hp1_pin_sense || hp2_pin_sense) {
-               alc_disable_headset_jack_key(codec);
-               /* 3k pull low control for Headset jack. */
-               alc_update_coef_idx(codec, 0x4a, 0, 3 << 10);
-               msleep(2);
-
-               if (hp1_pin_sense)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-               if (hp2_pin_sense)
-                       snd_hda_codec_write(codec, 0x16, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-               msleep(75);
-
-               if (hp1_pin_sense)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-               if (hp2_pin_sense)
-                       snd_hda_codec_write(codec, 0x16, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
-               msleep(75);
-               alc_update_coef_idx(codec, 0x4a, 3 << 10, 0);
-               alc_enable_headset_jack_key(codec);
-       }
-       alc_auto_setup_eapd(codec, false);
-       alc_shutup_pins(codec);
-       if (spec->ultra_low_power) {
-               msleep(50);
-               alc_update_coef_idx(codec, 0x08, 0x0f << 2, 0x0c << 2);
-               alc_update_coef_idx(codec, 0x0e, 7<<6, 0);
-               alc_update_coef_idx(codec, 0x33, 1<<11, 1<<11);
-               alc_update_coef_idx(codec, 0x4a, 3<<4, 2<<4);
-               msleep(30);
-       }
-}
-
-static void alc222_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp1_pin_sense, hp2_pin_sense;
-
-       if (!hp_pin)
-               return;
-
-       msleep(30);
-
-       hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-       hp2_pin_sense = snd_hda_jack_detect(codec, 0x14);
-
-       if (hp1_pin_sense || hp2_pin_sense) {
-               msleep(2);
-
-               if (hp1_pin_sense)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-               if (hp2_pin_sense)
-                       snd_hda_codec_write(codec, 0x14, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-               msleep(75);
-
-               if (hp1_pin_sense)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-               if (hp2_pin_sense)
-                       snd_hda_codec_write(codec, 0x14, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-
-               msleep(75);
-       }
-}
-
-static void alc222_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp1_pin_sense, hp2_pin_sense;
-
-       if (!hp_pin)
-               hp_pin = 0x21;
-
-       hp1_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-       hp2_pin_sense = snd_hda_jack_detect(codec, 0x14);
-
-       if (hp1_pin_sense || hp2_pin_sense) {
-               msleep(2);
-
-               if (hp1_pin_sense)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-               if (hp2_pin_sense)
-                       snd_hda_codec_write(codec, 0x14, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-               msleep(75);
-
-               if (hp1_pin_sense)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-               if (hp2_pin_sense)
-                       snd_hda_codec_write(codec, 0x14, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
-               msleep(75);
-       }
-       alc_auto_setup_eapd(codec, false);
-       alc_shutup_pins(codec);
-}
-
-static void alc_default_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp_pin_sense;
-
-       if (!hp_pin)
-               return;
-
-       msleep(30);
-
-       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-
-       if (hp_pin_sense) {
-               msleep(2);
-
-               snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-
-               msleep(75);
-
-               snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-               msleep(75);
-       }
-}
-
-static void alc_default_shutup(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       bool hp_pin_sense;
-
-       if (!hp_pin) {
-               alc269_shutup(codec);
-               return;
-       }
-
-       hp_pin_sense = snd_hda_jack_detect(codec, hp_pin);
-
-       if (hp_pin_sense) {
-               msleep(2);
-
-               snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-               msleep(75);
-
-               if (!spec->no_shutup_pins)
-                       snd_hda_codec_write(codec, hp_pin, 0,
-                                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
-               msleep(75);
-       }
-       alc_auto_setup_eapd(codec, false);
-       alc_shutup_pins(codec);
-}
-
-static void alc294_hp_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-       int i, val;
-
-       if (!hp_pin)
-               return;
-
-       snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-
-       msleep(100);
-
-       if (!spec->no_shutup_pins)
-               snd_hda_codec_write(codec, hp_pin, 0,
-                                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-
-       alc_update_coef_idx(codec, 0x6f, 0x000f, 0);/* Set HP depop to manual mode */
-       alc_update_coefex_idx(codec, 0x58, 0x00, 0x8000, 0x8000); /* HP depop procedure start */
-
-       /* Wait for depop procedure finish  */
-       val = alc_read_coefex_idx(codec, 0x58, 0x01);
-       for (i = 0; i < 20 && val & 0x0080; i++) {
-               msleep(50);
-               val = alc_read_coefex_idx(codec, 0x58, 0x01);
-       }
-       /* Set HP depop to auto mode */
-       alc_update_coef_idx(codec, 0x6f, 0x000f, 0x000b);
-       msleep(50);
-}
-
-static void alc294_init(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       /* required only at boot or S4 resume time */
-       if (!spec->done_hp_init ||
-           codec->core.dev.power.power_state.event == PM_EVENT_RESTORE) {
-               alc294_hp_init(codec);
-               spec->done_hp_init = true;
-       }
-       alc_default_init(codec);
-}
-
-static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg,
-                            unsigned int val)
-{
-       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
-       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val & 0xffff); /* LSB */
-       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val >> 16); /* MSB */
-}
-
-static int alc5505_coef_get(struct hda_codec *codec, unsigned int index_reg)
-{
-       unsigned int val;
-
-       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1);
-       val = snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
-               & 0xffff;
-       val |= snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0)
-               << 16;
-       return val;
-}
-
-static void alc5505_dsp_halt(struct hda_codec *codec)
-{
-       unsigned int val;
-
-       alc5505_coef_set(codec, 0x3000, 0x000c); /* DSP CPU stop */
-       alc5505_coef_set(codec, 0x880c, 0x0008); /* DDR enter self refresh */
-       alc5505_coef_set(codec, 0x61c0, 0x11110080); /* Clock control for PLL and CPU */
-       alc5505_coef_set(codec, 0x6230, 0xfc0d4011); /* Disable Input OP */
-       alc5505_coef_set(codec, 0x61b4, 0x040a2b03); /* Stop PLL2 */
-       alc5505_coef_set(codec, 0x61b0, 0x00005b17); /* Stop PLL1 */
-       alc5505_coef_set(codec, 0x61b8, 0x04133303); /* Stop PLL3 */
-       val = alc5505_coef_get(codec, 0x6220);
-       alc5505_coef_set(codec, 0x6220, (val | 0x3000)); /* switch Ringbuffer clock to DBUS clock */
-}
-
-static void alc5505_dsp_back_from_halt(struct hda_codec *codec)
-{
-       alc5505_coef_set(codec, 0x61b8, 0x04133302);
-       alc5505_coef_set(codec, 0x61b0, 0x00005b16);
-       alc5505_coef_set(codec, 0x61b4, 0x040a2b02);
-       alc5505_coef_set(codec, 0x6230, 0xf80d4011);
-       alc5505_coef_set(codec, 0x6220, 0x2002010f);
-       alc5505_coef_set(codec, 0x880c, 0x00000004);
-}
-
-static void alc5505_dsp_init(struct hda_codec *codec)
-{
-       unsigned int val;
-
-       alc5505_dsp_halt(codec);
-       alc5505_dsp_back_from_halt(codec);
-       alc5505_coef_set(codec, 0x61b0, 0x5b14); /* PLL1 control */
-       alc5505_coef_set(codec, 0x61b0, 0x5b16);
-       alc5505_coef_set(codec, 0x61b4, 0x04132b00); /* PLL2 control */
-       alc5505_coef_set(codec, 0x61b4, 0x04132b02);
-       alc5505_coef_set(codec, 0x61b8, 0x041f3300); /* PLL3 control*/
-       alc5505_coef_set(codec, 0x61b8, 0x041f3302);
-       snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_CODEC_RESET, 0); /* Function reset */
-       alc5505_coef_set(codec, 0x61b8, 0x041b3302);
-       alc5505_coef_set(codec, 0x61b8, 0x04173302);
-       alc5505_coef_set(codec, 0x61b8, 0x04163302);
-       alc5505_coef_set(codec, 0x8800, 0x348b328b); /* DRAM control */
-       alc5505_coef_set(codec, 0x8808, 0x00020022); /* DRAM control */
-       alc5505_coef_set(codec, 0x8818, 0x00000400); /* DRAM control */
-
-       val = alc5505_coef_get(codec, 0x6200) >> 16; /* Read revision ID */
-       if (val <= 3)
-               alc5505_coef_set(codec, 0x6220, 0x2002010f); /* I/O PAD Configuration */
-       else
-               alc5505_coef_set(codec, 0x6220, 0x6002018f);
-
-       alc5505_coef_set(codec, 0x61ac, 0x055525f0); /**/
-       alc5505_coef_set(codec, 0x61c0, 0x12230080); /* Clock control */
-       alc5505_coef_set(codec, 0x61b4, 0x040e2b02); /* PLL2 control */
-       alc5505_coef_set(codec, 0x61bc, 0x010234f8); /* OSC Control */
-       alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */
-       alc5505_coef_set(codec, 0x880c, 0x00000003);
-       alc5505_coef_set(codec, 0x880c, 0x00000010);
-
-#ifdef HALT_REALTEK_ALC5505
-       alc5505_dsp_halt(codec);
-#endif
-}
-
-#ifdef HALT_REALTEK_ALC5505
-#define alc5505_dsp_suspend(codec)     do { } while (0) /* NOP */
-#define alc5505_dsp_resume(codec)      do { } while (0) /* NOP */
-#else
-#define alc5505_dsp_suspend(codec)     alc5505_dsp_halt(codec)
-#define alc5505_dsp_resume(codec)      alc5505_dsp_back_from_halt(codec)
-#endif
-
-static int alc269_suspend(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->has_alc5505_dsp)
-               alc5505_dsp_suspend(codec);
-
-       return alc_suspend(codec);
-}
-
-static int alc269_resume(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
-               alc269vb_toggle_power_output(codec, 0);
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
-                       (alc_get_coef0(codec) & 0x00ff) == 0x018) {
-               msleep(150);
-       }
-
-       codec->patch_ops.init(codec);
-
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB)
-               alc269vb_toggle_power_output(codec, 1);
-       if (spec->codec_variant == ALC269_TYPE_ALC269VB &&
-                       (alc_get_coef0(codec) & 0x00ff) == 0x017) {
-               msleep(200);
-       }
-
-       snd_hda_regmap_sync(codec);
-       hda_call_check_power_status(codec, 0x01);
-
-       /* on some machine, the BIOS will clear the codec gpio data when enter
-        * suspend, and won't restore the data after resume, so we restore it
-        * in the driver.
-        */
-       if (spec->gpio_data)
-               alc_write_gpio_data(codec);
-
-       if (spec->has_alc5505_dsp)
-               alc5505_dsp_resume(codec);
-
-       return 0;
-}
-
-static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec,
-                                                const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
-}
-
-static void alc269_fixup_pincfg_U7x7_headset_mic(struct hda_codec *codec,
-                                                const struct hda_fixup *fix,
-                                                int action)
-{
-       unsigned int cfg_headphone = snd_hda_codec_get_pincfg(codec, 0x21);
-       unsigned int cfg_headset_mic = snd_hda_codec_get_pincfg(codec, 0x19);
-
-       if (cfg_headphone && cfg_headset_mic == 0x411111f0)
-               snd_hda_codec_set_pincfg(codec, 0x19,
-                       (cfg_headphone & ~AC_DEFCFG_DEVICE) |
-                       (AC_JACK_MIC_IN << AC_DEFCFG_DEVICE_SHIFT));
-}
-
-static void alc269_fixup_hweq(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_INIT)
-               alc_update_coef_idx(codec, 0x1e, 0, 0x80);
-}
-
-static void alc269_fixup_headset_mic(struct hda_codec *codec,
-                                      const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-}
-
-static void alc271_fixup_dmic(struct hda_codec *codec,
-                             const struct hda_fixup *fix, int action)
-{
-       static const struct hda_verb verbs[] = {
-               {0x20, AC_VERB_SET_COEF_INDEX, 0x0d},
-               {0x20, AC_VERB_SET_PROC_COEF, 0x4000},
-               {}
-       };
-       unsigned int cfg;
-
-       if (strcmp(codec->core.chip_name, "ALC271X") &&
-           strcmp(codec->core.chip_name, "ALC269VB"))
-               return;
-       cfg = snd_hda_codec_get_pincfg(codec, 0x12);
-       if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED)
-               snd_hda_sequence_write(codec, verbs);
-}
-
-/* Fix the speaker amp after resume, etc */
-static void alc269vb_fixup_aspire_e1_coef(struct hda_codec *codec,
-                                         const struct hda_fixup *fix,
-                                         int action)
-{
-       if (action == HDA_FIXUP_ACT_INIT)
-               alc_update_coef_idx(codec, 0x0d, 0x6000, 0x6000);
-}
-
-static void alc269_fixup_pcm_44k(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PROBE)
-               return;
-
-       /* Due to a hardware problem on Lenovo Ideadpad, we need to
-        * fix the sample rate of analog I/O to 44.1kHz
-        */
-       spec->gen.stream_analog_playback = &alc269_44k_pcm_analog_playback;
-       spec->gen.stream_analog_capture = &alc269_44k_pcm_analog_capture;
-}
-
-static void alc269_fixup_stereo_dmic(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       /* The digital-mic unit sends PDM (differential signal) instead of
-        * the standard PCM, thus you can't record a valid mono stream as is.
-        * Below is a workaround specific to ALC269 to control the dmic
-        * signal source as mono.
-        */
-       if (action == HDA_FIXUP_ACT_INIT)
-               alc_update_coef_idx(codec, 0x07, 0, 0x80);
-}
-
-static void alc269_quanta_automute(struct hda_codec *codec)
-{
-       snd_hda_gen_update_outputs(codec);
-
-       alc_write_coef_idx(codec, 0x0c, 0x680);
-       alc_write_coef_idx(codec, 0x0c, 0x480);
-}
-
-static void alc269_fixup_quanta_mute(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action != HDA_FIXUP_ACT_PROBE)
-               return;
-       spec->gen.automute_hook = alc269_quanta_automute;
-}
-
-static void alc269_x101_hp_automute_hook(struct hda_codec *codec,
-                                        struct hda_jack_callback *jack)
-{
-       struct alc_spec *spec = codec->spec;
-       int vref;
-       msleep(200);
-       snd_hda_gen_hp_automute(codec, jack);
-
-       vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
-       msleep(100);
-       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           vref);
-       msleep(500);
-       snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           vref);
-}
-
-/*
- * Magic sequence to make Huawei Matebook X right speaker working (bko#197801)
- */
-struct hda_alc298_mbxinit {
-       unsigned char value_0x23;
-       unsigned char value_0x25;
-};
-
-static void alc298_huawei_mbx_stereo_seq(struct hda_codec *codec,
-                                        const struct hda_alc298_mbxinit *initval,
-                                        bool first)
-{
-       snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x0);
-       alc_write_coef_idx(codec, 0x26, 0xb000);
-
-       if (first)
-               snd_hda_codec_write(codec, 0x21, 0, AC_VERB_GET_PIN_SENSE, 0x0);
-
-       snd_hda_codec_write(codec, 0x6, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80);
-       alc_write_coef_idx(codec, 0x26, 0xf000);
-       alc_write_coef_idx(codec, 0x23, initval->value_0x23);
-
-       if (initval->value_0x23 != 0x1e)
-               alc_write_coef_idx(codec, 0x25, initval->value_0x25);
-
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26);
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010);
-}
-
-static void alc298_fixup_huawei_mbx_stereo(struct hda_codec *codec,
-                                          const struct hda_fixup *fix,
-                                          int action)
-{
-       /* Initialization magic */
-       static const struct hda_alc298_mbxinit dac_init[] = {
-               {0x0c, 0x00}, {0x0d, 0x00}, {0x0e, 0x00}, {0x0f, 0x00},
-               {0x10, 0x00}, {0x1a, 0x40}, {0x1b, 0x82}, {0x1c, 0x00},
-               {0x1d, 0x00}, {0x1e, 0x00}, {0x1f, 0x00},
-               {0x20, 0xc2}, {0x21, 0xc8}, {0x22, 0x26}, {0x23, 0x24},
-               {0x27, 0xff}, {0x28, 0xff}, {0x29, 0xff}, {0x2a, 0x8f},
-               {0x2b, 0x02}, {0x2c, 0x48}, {0x2d, 0x34}, {0x2e, 0x00},
-               {0x2f, 0x00},
-               {0x30, 0x00}, {0x31, 0x00}, {0x32, 0x00}, {0x33, 0x00},
-               {0x34, 0x00}, {0x35, 0x01}, {0x36, 0x93}, {0x37, 0x0c},
-               {0x38, 0x00}, {0x39, 0x00}, {0x3a, 0xf8}, {0x38, 0x80},
-               {}
-       };
-       const struct hda_alc298_mbxinit *seq;
-
-       if (action != HDA_FIXUP_ACT_INIT)
-               return;
-
-       /* Start */
-       snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x00);
-       snd_hda_codec_write(codec, 0x06, 0, AC_VERB_SET_DIGI_CONVERT_3, 0x80);
-       alc_write_coef_idx(codec, 0x26, 0xf000);
-       alc_write_coef_idx(codec, 0x22, 0x31);
-       alc_write_coef_idx(codec, 0x23, 0x0b);
-       alc_write_coef_idx(codec, 0x25, 0x00);
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x26);
-       snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, 0xb010);
-
-       for (seq = dac_init; seq->value_0x23; seq++)
-               alc298_huawei_mbx_stereo_seq(codec, seq, seq == dac_init);
-}
-
-static void alc269_fixup_x101_headset_mic(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-               spec->gen.hp_automute_hook = alc269_x101_hp_automute_hook;
-       }
-}
-
-static void alc_update_vref_led(struct hda_codec *codec, hda_nid_t pin,
-                               bool polarity, bool on)
-{
-       unsigned int pinval;
-
-       if (!pin)
-               return;
-       if (polarity)
-               on = !on;
-       pinval = snd_hda_codec_get_pin_target(codec, pin);
-       pinval &= ~AC_PINCTL_VREFEN;
-       pinval |= on ? AC_PINCTL_VREF_80 : AC_PINCTL_VREF_HIZ;
-       /* temporarily power up/down for setting VREF */
-       snd_hda_power_up_pm(codec);
-       snd_hda_set_pin_ctl_cache(codec, pin, pinval);
-       snd_hda_power_down_pm(codec);
-}
-
-/* update mute-LED according to the speaker mute state via mic VREF pin */
-static int vref_mute_led_set(struct led_classdev *led_cdev,
-                            enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct alc_spec *spec = codec->spec;
-
-       alc_update_vref_led(codec, spec->mute_led_nid,
-                           spec->mute_led_polarity, brightness);
-       return 0;
-}
-
-/* Make sure the led works even in runtime suspend */
-static unsigned int led_power_filter(struct hda_codec *codec,
-                                                 hda_nid_t nid,
-                                                 unsigned int power_state)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (power_state != AC_PWRST_D3 || nid == 0 ||
-           (nid != spec->mute_led_nid && nid != spec->cap_mute_led_nid))
-               return power_state;
-
-       /* Set pin ctl again, it might have just been set to 0 */
-       snd_hda_set_pin_ctl(codec, nid,
-                           snd_hda_codec_get_pin_target(codec, nid));
-
-       return snd_hda_gen_path_power_filter(codec, nid, power_state);
-}
-
-static void alc269_fixup_hp_mute_led(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       const struct dmi_device *dev = NULL;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
-               int pol, pin;
-               if (sscanf(dev->name, "HP_Mute_LED_%d_%x", &pol, &pin) != 2)
-                       continue;
-               if (pin < 0x0a || pin >= 0x10)
-                       break;
-               spec->mute_led_polarity = pol;
-               spec->mute_led_nid = pin - 0x0a + 0x18;
-               snd_hda_gen_add_mute_led_cdev(codec, vref_mute_led_set);
-               codec->power_filter = led_power_filter;
-               codec_dbg(codec,
-                         "Detected mute LED for %x:%d\n", spec->mute_led_nid,
-                          spec->mute_led_polarity);
-               break;
-       }
-}
-
-static void alc269_fixup_hp_mute_led_micx(struct hda_codec *codec,
-                                         const struct hda_fixup *fix,
-                                         int action, hda_nid_t pin)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_polarity = 0;
-               spec->mute_led_nid = pin;
-               snd_hda_gen_add_mute_led_cdev(codec, vref_mute_led_set);
-               codec->power_filter = led_power_filter;
-       }
-}
-
-static void alc269_fixup_hp_mute_led_mic1(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x18);
-}
-
-static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x19);
-}
-
-static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b);
-}
-
-/* update LED status via GPIO */
-static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
-                               int polarity, bool enabled)
-{
-       if (polarity)
-               enabled = !enabled;
-       alc_update_gpio_data(codec, mask, !enabled); /* muted -> LED on */
-}
-
-/* turn on/off mute LED via GPIO per vmaster hook */
-static int gpio_mute_led_set(struct led_classdev *led_cdev,
-                            enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct alc_spec *spec = codec->spec;
-
-       alc_update_gpio_led(codec, spec->gpio_mute_led_mask,
-                           spec->mute_led_polarity, !brightness);
-       return 0;
-}
-
-/* turn on/off mic-mute LED via GPIO per capture hook */
-static int micmute_led_set(struct led_classdev *led_cdev,
-                          enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct alc_spec *spec = codec->spec;
-
-       alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
-                           spec->micmute_led_polarity, !brightness);
-       return 0;
-}
-
-/* setup mute and mic-mute GPIO bits, add hooks appropriately */
-static void alc_fixup_hp_gpio_led(struct hda_codec *codec,
-                                 int action,
-                                 unsigned int mute_mask,
-                                 unsigned int micmute_mask)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_fixup_gpio(codec, action, mute_mask | micmute_mask);
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-       if (mute_mask) {
-               spec->gpio_mute_led_mask = mute_mask;
-               snd_hda_gen_add_mute_led_cdev(codec, gpio_mute_led_set);
-       }
-       if (micmute_mask) {
-               spec->gpio_mic_led_mask = micmute_mask;
-               snd_hda_gen_add_micmute_led_cdev(codec, micmute_led_set);
-       }
-}
-
-static void alc236_fixup_hp_gpio_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc_fixup_hp_gpio_led(codec, action, 0x02, 0x01);
-}
-
-static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
-}
-
-static void alc285_fixup_hp_gpio_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc_fixup_hp_gpio_led(codec, action, 0x04, 0x01);
-}
-
-static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc_fixup_hp_gpio_led(codec, action, 0x02, 0x20);
-}
-
-static void alc287_fixup_hp_gpio_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc_fixup_hp_gpio_led(codec, action, 0x10, 0);
-}
-
-static void alc245_fixup_hp_gpio_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->micmute_led_polarity = 1;
-       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
-}
-
-/* turn on/off mic-mute LED per capture hook via VREF change */
-static int vref_micmute_led_set(struct led_classdev *led_cdev,
-                               enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct alc_spec *spec = codec->spec;
-
-       alc_update_vref_led(codec, spec->cap_mute_led_nid,
-                           spec->micmute_led_polarity, brightness);
-       return 0;
-}
-
-static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               /* Like hp_gpio_mic1_led, but also needs GPIO4 low to
-                * enable headphone amp
-                */
-               spec->gpio_mask |= 0x10;
-               spec->gpio_dir |= 0x10;
-               spec->cap_mute_led_nid = 0x18;
-               snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
-               codec->power_filter = led_power_filter;
-       }
-}
-
-static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->cap_mute_led_nid = 0x18;
-               snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
-               codec->power_filter = led_power_filter;
-       }
-}
-
-/* HP Spectre x360 14 model needs a unique workaround for enabling the amp;
- * it needs to toggle the GPIO0 once on and off at each time (bko#210633)
- */
-static void alc245_fixup_hp_x360_amp(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gpio_mask |= 0x01;
-               spec->gpio_dir |= 0x01;
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               /* need to toggle GPIO to enable the amp */
-               alc_update_gpio_data(codec, 0x01, true);
-               msleep(100);
-               alc_update_gpio_data(codec, 0x01, false);
-               break;
-       }
-}
-
-/* toggle GPIO2 at each time stream is started; we use PREPARE state instead */
-static void alc274_hp_envy_pcm_hook(struct hda_pcm_stream *hinfo,
-                                   struct hda_codec *codec,
-                                   struct snd_pcm_substream *substream,
-                                   int action)
-{
-       switch (action) {
-       case HDA_GEN_PCM_ACT_PREPARE:
-               alc_update_gpio_data(codec, 0x04, true);
-               break;
-       case HDA_GEN_PCM_ACT_CLEANUP:
-               alc_update_gpio_data(codec, 0x04, false);
-               break;
-       }
-}
-
-static void alc274_fixup_hp_envy_gpio(struct hda_codec *codec,
-                                     const struct hda_fixup *fix,
-                                     int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               spec->gpio_mask |= 0x04;
-               spec->gpio_dir |= 0x04;
-               spec->gen.pcm_playback_hook = alc274_hp_envy_pcm_hook;
-       }
-}
-
-static void alc_update_coef_led(struct hda_codec *codec,
-                               struct alc_coef_led *led,
-                               bool polarity, bool on)
-{
-       if (polarity)
-               on = !on;
-       /* temporarily power up/down for setting COEF bit */
-       alc_update_coef_idx(codec, led->idx, led->mask,
-                           on ? led->on : led->off);
-}
-
-/* update mute-LED according to the speaker mute state via COEF bit */
-static int coef_mute_led_set(struct led_classdev *led_cdev,
-                            enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct alc_spec *spec = codec->spec;
-
-       alc_update_coef_led(codec, &spec->mute_led_coef,
-                           spec->mute_led_polarity, brightness);
-       return 0;
-}
-
-static void alc285_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
-                                         const struct hda_fixup *fix,
-                                         int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_polarity = 0;
-               spec->mute_led_coef.idx = 0x0b;
-               spec->mute_led_coef.mask = 1 << 3;
-               spec->mute_led_coef.on = 1 << 3;
-               spec->mute_led_coef.off = 0;
-               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
-       }
-}
-
-static void alc236_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
-                                         const struct hda_fixup *fix,
-                                         int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_polarity = 0;
-               spec->mute_led_coef.idx = 0x34;
-               spec->mute_led_coef.mask = 1 << 5;
-               spec->mute_led_coef.on = 0;
-               spec->mute_led_coef.off = 1 << 5;
-               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
-       }
-}
-
-static void alc236_fixup_hp_mute_led_coefbit2(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_polarity = 0;
-               spec->mute_led_coef.idx = 0x07;
-               spec->mute_led_coef.mask = 1;
-               spec->mute_led_coef.on = 1;
-               spec->mute_led_coef.off = 0;
-               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
-       }
-}
-
-static void alc245_fixup_hp_mute_led_coefbit(struct hda_codec *codec,
-                                         const struct hda_fixup *fix,
-                                         int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_polarity = 0;
-               spec->mute_led_coef.idx = 0x0b;
-               spec->mute_led_coef.mask = 3 << 2;
-               spec->mute_led_coef.on = 2 << 2;
-               spec->mute_led_coef.off = 1 << 2;
-               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
-       }
-}
-
-static void alc245_fixup_hp_mute_led_v1_coefbit(struct hda_codec *codec,
-                                         const struct hda_fixup *fix,
-                                         int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_polarity = 0;
-               spec->mute_led_coef.idx = 0x0b;
-               spec->mute_led_coef.mask = 1 << 3;
-               spec->mute_led_coef.on = 1 << 3;
-               spec->mute_led_coef.off = 0;
-               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
-       }
-}
-
-/* turn on/off mic-mute LED per capture hook by coef bit */
-static int coef_micmute_led_set(struct led_classdev *led_cdev,
-                               enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct alc_spec *spec = codec->spec;
-
-       alc_update_coef_led(codec, &spec->mic_led_coef,
-                           spec->micmute_led_polarity, brightness);
-       return 0;
-}
-
-static void alc285_fixup_hp_coef_micmute_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mic_led_coef.idx = 0x19;
-               spec->mic_led_coef.mask = 1 << 13;
-               spec->mic_led_coef.on = 1 << 13;
-               spec->mic_led_coef.off = 0;
-               snd_hda_gen_add_micmute_led_cdev(codec, coef_micmute_led_set);
-       }
-}
-
-static void alc285_fixup_hp_gpio_micmute_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->micmute_led_polarity = 1;
-       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
-}
-
-static void alc236_fixup_hp_coef_micmute_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mic_led_coef.idx = 0x35;
-               spec->mic_led_coef.mask = 3 << 2;
-               spec->mic_led_coef.on = 2 << 2;
-               spec->mic_led_coef.off = 1 << 2;
-               snd_hda_gen_add_micmute_led_cdev(codec, coef_micmute_led_set);
-       }
-}
-
-static void alc295_fixup_hp_mute_led_coefbit11(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_polarity = 0;
-               spec->mute_led_coef.idx = 0xb;
-               spec->mute_led_coef.mask = 3 << 3;
-               spec->mute_led_coef.on = 1 << 3;
-               spec->mute_led_coef.off = 1 << 4;
-               snd_hda_gen_add_mute_led_cdev(codec, coef_mute_led_set);
-       }
-}
-
-static void alc285_fixup_hp_mute_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
-       alc285_fixup_hp_coef_micmute_led(codec, fix, action);
-}
-
-static void alc285_fixup_hp_spectre_x360_mute_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
-       alc285_fixup_hp_gpio_micmute_led(codec, fix, action);
-}
-
-static void alc236_fixup_hp_mute_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc236_fixup_hp_mute_led_coefbit(codec, fix, action);
-       alc236_fixup_hp_coef_micmute_led(codec, fix, action);
-}
-
-static void alc236_fixup_hp_micmute_led_vref(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->cap_mute_led_nid = 0x1a;
-               snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
-               codec->power_filter = led_power_filter;
-       }
-}
-
-static void alc236_fixup_hp_mute_led_micmute_vref(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc236_fixup_hp_mute_led_coefbit(codec, fix, action);
-       alc236_fixup_hp_micmute_led_vref(codec, fix, action);
-}
-
-static inline void alc298_samsung_write_coef_pack(struct hda_codec *codec,
-                                                 const unsigned short coefs[2])
-{
-       alc_write_coef_idx(codec, 0x23, coefs[0]);
-       alc_write_coef_idx(codec, 0x25, coefs[1]);
-       alc_write_coef_idx(codec, 0x26, 0xb011);
-}
-
-struct alc298_samsung_amp_desc {
-       unsigned char nid;
-       unsigned short init_seq[2][2];
-};
-
-static void alc298_fixup_samsung_amp(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       int i, j;
-       static const unsigned short init_seq[][2] = {
-               { 0x19, 0x00 }, { 0x20, 0xc0 }, { 0x22, 0x44 }, { 0x23, 0x08 },
-               { 0x24, 0x85 }, { 0x25, 0x41 }, { 0x35, 0x40 }, { 0x36, 0x01 },
-               { 0x38, 0x81 }, { 0x3a, 0x03 }, { 0x3b, 0x81 }, { 0x40, 0x3e },
-               { 0x41, 0x07 }, { 0x400, 0x1 }
-       };
-       static const struct alc298_samsung_amp_desc amps[] = {
-               { 0x3a, { { 0x18, 0x1 }, { 0x26, 0x0 } } },
-               { 0x39, { { 0x18, 0x2 }, { 0x26, 0x1 } } }
-       };
-
-       if (action != HDA_FIXUP_ACT_INIT)
-               return;
-
-       for (i = 0; i < ARRAY_SIZE(amps); i++) {
-               alc_write_coef_idx(codec, 0x22, amps[i].nid);
-
-               for (j = 0; j < ARRAY_SIZE(amps[i].init_seq); j++)
-                       alc298_samsung_write_coef_pack(codec, amps[i].init_seq[j]);
-
-               for (j = 0; j < ARRAY_SIZE(init_seq); j++)
-                       alc298_samsung_write_coef_pack(codec, init_seq[j]);
-       }
-}
-
-struct alc298_samsung_v2_amp_desc {
-       unsigned short nid;
-       int init_seq_size;
-       unsigned short init_seq[18][2];
-};
-
-static const struct alc298_samsung_v2_amp_desc
-alc298_samsung_v2_amp_desc_tbl[] = {
-       { 0x38, 18, {
-               { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
-               { 0x201b, 0x0001 }, { 0x201d, 0x0001 }, { 0x201f, 0x00fe },
-               { 0x2021, 0x0000 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
-               { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
-               { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x2399, 0x0003 },
-               { 0x23a4, 0x00b5 }, { 0x23a5, 0x0001 }, { 0x23ba, 0x0094 }
-       }},
-       { 0x39, 18, {
-               { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
-               { 0x201b, 0x0002 }, { 0x201d, 0x0002 }, { 0x201f, 0x00fd },
-               { 0x2021, 0x0001 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
-               { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
-               { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x2399, 0x0003 },
-               { 0x23a4, 0x00b5 }, { 0x23a5, 0x0001 }, { 0x23ba, 0x0094 }
-       }},
-       { 0x3c, 15, {
-               { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
-               { 0x201b, 0x0001 }, { 0x201d, 0x0001 }, { 0x201f, 0x00fe },
-               { 0x2021, 0x0000 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
-               { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
-               { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x23ba, 0x008d }
-       }},
-       { 0x3d, 15, {
-               { 0x23e1, 0x0000 }, { 0x2012, 0x006f }, { 0x2014, 0x0000 },
-               { 0x201b, 0x0002 }, { 0x201d, 0x0002 }, { 0x201f, 0x00fd },
-               { 0x2021, 0x0001 }, { 0x2022, 0x0010 }, { 0x203d, 0x0005 },
-               { 0x203f, 0x0003 }, { 0x2050, 0x002c }, { 0x2076, 0x000e },
-               { 0x207c, 0x004a }, { 0x2081, 0x0003 }, { 0x23ba, 0x008d }
-       }}
-};
-
-static void alc298_samsung_v2_enable_amps(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       static const unsigned short enable_seq[][2] = {
-               { 0x203a, 0x0081 }, { 0x23ff, 0x0001 },
-       };
-       int i, j;
-
-       for (i = 0; i < spec->num_speaker_amps; i++) {
-               alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
-               for (j = 0; j < ARRAY_SIZE(enable_seq); j++)
-                       alc298_samsung_write_coef_pack(codec, enable_seq[j]);
-               codec_dbg(codec, "alc298_samsung_v2: Enabled speaker amp 0x%02x\n",
-                               alc298_samsung_v2_amp_desc_tbl[i].nid);
-       }
-}
-
-static void alc298_samsung_v2_disable_amps(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       static const unsigned short disable_seq[][2] = {
-               { 0x23ff, 0x0000 }, { 0x203a, 0x0080 },
-       };
-       int i, j;
-
-       for (i = 0; i < spec->num_speaker_amps; i++) {
-               alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
-               for (j = 0; j < ARRAY_SIZE(disable_seq); j++)
-                       alc298_samsung_write_coef_pack(codec, disable_seq[j]);
-               codec_dbg(codec, "alc298_samsung_v2: Disabled speaker amp 0x%02x\n",
-                               alc298_samsung_v2_amp_desc_tbl[i].nid);
-       }
-}
-
-static void alc298_samsung_v2_playback_hook(struct hda_pcm_stream *hinfo,
-                               struct hda_codec *codec,
-                               struct snd_pcm_substream *substream,
-                               int action)
-{
-       /* Dynamically enable/disable speaker amps before and after playback */
-       if (action == HDA_GEN_PCM_ACT_OPEN)
-               alc298_samsung_v2_enable_amps(codec);
-       if (action == HDA_GEN_PCM_ACT_CLOSE)
-               alc298_samsung_v2_disable_amps(codec);
-}
-
-static void alc298_samsung_v2_init_amps(struct hda_codec *codec,
-                               int num_speaker_amps)
-{
-       struct alc_spec *spec = codec->spec;
-       int i, j;
-
-       /* Set spec's num_speaker_amps before doing anything else */
-       spec->num_speaker_amps = num_speaker_amps;
-
-       /* Disable speaker amps before init to prevent any physical damage */
-       alc298_samsung_v2_disable_amps(codec);
-
-       /* Initialize the speaker amps */
-       for (i = 0; i < spec->num_speaker_amps; i++) {
-               alc_write_coef_idx(codec, 0x22, alc298_samsung_v2_amp_desc_tbl[i].nid);
-               for (j = 0; j < alc298_samsung_v2_amp_desc_tbl[i].init_seq_size; j++) {
-                       alc298_samsung_write_coef_pack(codec,
-                                       alc298_samsung_v2_amp_desc_tbl[i].init_seq[j]);
-               }
-               alc_write_coef_idx(codec, 0x89, 0x0);
-               codec_dbg(codec, "alc298_samsung_v2: Initialized speaker amp 0x%02x\n",
-                               alc298_samsung_v2_amp_desc_tbl[i].nid);
-       }
-
-       /* register hook to enable speaker amps only when they are needed */
-       spec->gen.pcm_playback_hook = alc298_samsung_v2_playback_hook;
-}
-
-static void alc298_fixup_samsung_amp_v2_2_amps(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PROBE)
-               alc298_samsung_v2_init_amps(codec, 2);
-}
-
-static void alc298_fixup_samsung_amp_v2_4_amps(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PROBE)
-               alc298_samsung_v2_init_amps(codec, 4);
-}
-
-static void gpio2_mic_hotkey_event(struct hda_codec *codec,
-                                  struct hda_jack_callback *event)
-{
-       struct alc_spec *spec = codec->spec;
-
-       /* GPIO2 just toggles on a keypress/keyrelease cycle. Therefore
-          send both key on and key off event for every interrupt. */
-       input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 1);
-       input_sync(spec->kb_dev);
-       input_report_key(spec->kb_dev, spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX], 0);
-       input_sync(spec->kb_dev);
-}
-
-static int alc_register_micmute_input_device(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int i;
-
-       spec->kb_dev = input_allocate_device();
-       if (!spec->kb_dev) {
-               codec_err(codec, "Out of memory (input_allocate_device)\n");
-               return -ENOMEM;
-       }
-
-       spec->alc_mute_keycode_map[ALC_KEY_MICMUTE_INDEX] = KEY_MICMUTE;
-
-       spec->kb_dev->name = "Microphone Mute Button";
-       spec->kb_dev->evbit[0] = BIT_MASK(EV_KEY);
-       spec->kb_dev->keycodesize = sizeof(spec->alc_mute_keycode_map[0]);
-       spec->kb_dev->keycodemax = ARRAY_SIZE(spec->alc_mute_keycode_map);
-       spec->kb_dev->keycode = spec->alc_mute_keycode_map;
-       for (i = 0; i < ARRAY_SIZE(spec->alc_mute_keycode_map); i++)
-               set_bit(spec->alc_mute_keycode_map[i], spec->kb_dev->keybit);
-
-       if (input_register_device(spec->kb_dev)) {
-               codec_err(codec, "input_register_device failed\n");
-               input_free_device(spec->kb_dev);
-               spec->kb_dev = NULL;
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-/* GPIO1 = set according to SKU external amp
- * GPIO2 = mic mute hotkey
- * GPIO3 = mute LED
- * GPIO4 = mic mute LED
- */
-static void alc280_fixup_hp_gpio2_mic_hotkey(struct hda_codec *codec,
-                                            const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_fixup_hp_gpio_led(codec, action, 0x08, 0x10);
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->init_amp = ALC_INIT_DEFAULT;
-               if (alc_register_micmute_input_device(codec) != 0)
-                       return;
-
-               spec->gpio_mask |= 0x06;
-               spec->gpio_dir |= 0x02;
-               spec->gpio_data |= 0x02;
-               snd_hda_codec_write_cache(codec, codec->core.afg, 0,
-                                         AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x04);
-               snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
-                                                   gpio2_mic_hotkey_event);
-               return;
-       }
-
-       if (!spec->kb_dev)
-               return;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_FREE:
-               input_unregister_device(spec->kb_dev);
-               spec->kb_dev = NULL;
-       }
-}
-
-/* Line2 = mic mute hotkey
- * GPIO2 = mic mute LED
- */
-static void alc233_fixup_lenovo_line2_mic_hotkey(struct hda_codec *codec,
-                                            const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->init_amp = ALC_INIT_DEFAULT;
-               if (alc_register_micmute_input_device(codec) != 0)
-                       return;
-
-               snd_hda_jack_detect_enable_callback(codec, 0x1b,
-                                                   gpio2_mic_hotkey_event);
-               return;
-       }
-
-       if (!spec->kb_dev)
-               return;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_FREE:
-               input_unregister_device(spec->kb_dev);
-               spec->kb_dev = NULL;
-       }
-}
-
-static void alc269_fixup_hp_line1_mic1_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1a);
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->cap_mute_led_nid = 0x18;
-               snd_hda_gen_add_micmute_led_cdev(codec, vref_micmute_led_set);
-       }
-}
-
-static void alc233_fixup_lenovo_low_en_micmute_led(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->micmute_led_polarity = 1;
-       alc233_fixup_lenovo_line2_mic_hotkey(codec, fix, action);
-}
-
-static void alc_hp_mute_disable(struct hda_codec *codec, unsigned int delay)
-{
-       if (delay <= 0)
-               delay = 75;
-       snd_hda_codec_write(codec, 0x21, 0,
-                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-       msleep(delay);
-       snd_hda_codec_write(codec, 0x21, 0,
-                   AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-       msleep(delay);
-}
-
-static void alc_hp_enable_unmute(struct hda_codec *codec, unsigned int delay)
-{
-       if (delay <= 0)
-               delay = 75;
-       snd_hda_codec_write(codec, 0x21, 0,
-                   AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
-       msleep(delay);
-       snd_hda_codec_write(codec, 0x21, 0,
-                   AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-       msleep(delay);
-}
-
-static const struct coef_fw alc225_pre_hsmode[] = {
-       UPDATE_COEF(0x4a, 1<<8, 0),
-       UPDATE_COEFEX(0x57, 0x05, 1<<14, 0),
-       UPDATE_COEF(0x63, 3<<14, 3<<14),
-       UPDATE_COEF(0x4a, 3<<4, 2<<4),
-       UPDATE_COEF(0x4a, 3<<10, 3<<10),
-       UPDATE_COEF(0x45, 0x3f<<10, 0x34<<10),
-       UPDATE_COEF(0x4a, 3<<10, 0),
-       {}
-};
-
-static void alc_headset_mode_unplugged(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       static const struct coef_fw coef0255[] = {
-               WRITE_COEF(0x1b, 0x0c0b), /* LDO and MISC control */
-               WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
-               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
-               WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
-               WRITE_COEFEX(0x57, 0x03, 0x8aa6), /* Direct Drive HP Amp control */
-               {}
-       };
-       static const struct coef_fw coef0256[] = {
-               WRITE_COEF(0x1b, 0x0c4b), /* LDO and MISC control */
-               WRITE_COEF(0x45, 0xd089), /* UAJ function set to menual mode */
-               WRITE_COEF(0x06, 0x6104), /* Set MIC2 Vref gate with HP */
-               WRITE_COEFEX(0x57, 0x03, 0x09a3), /* Direct Drive HP Amp control */
-               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
-               {}
-       };
-       static const struct coef_fw coef0233[] = {
-               WRITE_COEF(0x1b, 0x0c0b),
-               WRITE_COEF(0x45, 0xc429),
-               UPDATE_COEF(0x35, 0x4000, 0),
-               WRITE_COEF(0x06, 0x2104),
-               WRITE_COEF(0x1a, 0x0001),
-               WRITE_COEF(0x26, 0x0004),
-               WRITE_COEF(0x32, 0x42a3),
-               {}
-       };
-       static const struct coef_fw coef0288[] = {
-               UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
-               UPDATE_COEF(0x50, 0x2000, 0x2000),
-               UPDATE_COEF(0x56, 0x0006, 0x0006),
-               UPDATE_COEF(0x66, 0x0008, 0),
-               UPDATE_COEF(0x67, 0x2000, 0),
-               {}
-       };
-       static const struct coef_fw coef0298[] = {
-               UPDATE_COEF(0x19, 0x1300, 0x0300),
-               {}
-       };
-       static const struct coef_fw coef0292[] = {
-               WRITE_COEF(0x76, 0x000e),
-               WRITE_COEF(0x6c, 0x2400),
-               WRITE_COEF(0x18, 0x7308),
-               WRITE_COEF(0x6b, 0xc429),
-               {}
-       };
-       static const struct coef_fw coef0293[] = {
-               UPDATE_COEF(0x10, 7<<8, 6<<8), /* SET Line1 JD to 0 */
-               UPDATE_COEFEX(0x57, 0x05, 1<<15|1<<13, 0x0), /* SET charge pump by verb */
-               UPDATE_COEFEX(0x57, 0x03, 1<<10, 1<<10), /* SET EN_OSW to 1 */
-               UPDATE_COEF(0x1a, 1<<3, 1<<3), /* Combo JD gating with LINE1-VREFO */
-               WRITE_COEF(0x45, 0xc429), /* Set to TRS type */
-               UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
-               {}
-       };
-       static const struct coef_fw coef0668[] = {
-               WRITE_COEF(0x15, 0x0d40),
-               WRITE_COEF(0xb7, 0x802b),
-               {}
-       };
-       static const struct coef_fw coef0225[] = {
-               UPDATE_COEF(0x63, 3<<14, 0),
-               {}
-       };
-       static const struct coef_fw coef0274[] = {
-               UPDATE_COEF(0x4a, 0x0100, 0),
-               UPDATE_COEFEX(0x57, 0x05, 0x4000, 0),
-               UPDATE_COEF(0x6b, 0xf000, 0x5000),
-               UPDATE_COEF(0x4a, 0x0010, 0),
-               UPDATE_COEF(0x4a, 0x0c00, 0x0c00),
-               WRITE_COEF(0x45, 0x5289),
-               UPDATE_COEF(0x4a, 0x0c00, 0),
-               {}
-       };
-
-       if (spec->no_internal_mic_pin) {
-               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
-               return;
-       }
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0255:
-               alc_process_coef_fw(codec, coef0255);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x19e58326:
-               alc_hp_mute_disable(codec, 75);
-               alc_process_coef_fw(codec, coef0256);
-               break;
-       case 0x10ec0234:
-       case 0x10ec0274:
-       case 0x10ec0294:
-               alc_process_coef_fw(codec, coef0274);
-               break;
-       case 0x10ec0233:
-       case 0x10ec0283:
-               alc_process_coef_fw(codec, coef0233);
-               break;
-       case 0x10ec0286:
-       case 0x10ec0288:
-               alc_process_coef_fw(codec, coef0288);
-               break;
-       case 0x10ec0298:
-               alc_process_coef_fw(codec, coef0298);
-               alc_process_coef_fw(codec, coef0288);
-               break;
-       case 0x10ec0292:
-               alc_process_coef_fw(codec, coef0292);
-               break;
-       case 0x10ec0293:
-               alc_process_coef_fw(codec, coef0293);
-               break;
-       case 0x10ec0668:
-               alc_process_coef_fw(codec, coef0668);
-               break;
-       case 0x10ec0215:
-       case 0x10ec0225:
-       case 0x10ec0285:
-       case 0x10ec0295:
-       case 0x10ec0289:
-       case 0x10ec0299:
-               alc_hp_mute_disable(codec, 75);
-               alc_process_coef_fw(codec, alc225_pre_hsmode);
-               alc_process_coef_fw(codec, coef0225);
-               break;
-       case 0x10ec0867:
-               alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-               break;
-       }
-       codec_dbg(codec, "Headset jack set to unplugged mode.\n");
-}
-
-
-static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin,
-                                   hda_nid_t mic_pin)
-{
-       static const struct coef_fw coef0255[] = {
-               WRITE_COEFEX(0x57, 0x03, 0x8aa6),
-               WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
-               {}
-       };
-       static const struct coef_fw coef0256[] = {
-               UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14), /* Direct Drive HP Amp control(Set to verb control)*/
-               WRITE_COEFEX(0x57, 0x03, 0x09a3),
-               WRITE_COEF(0x06, 0x6100), /* Set MIC2 Vref gate to normal */
-               {}
-       };
-       static const struct coef_fw coef0233[] = {
-               UPDATE_COEF(0x35, 0, 1<<14),
-               WRITE_COEF(0x06, 0x2100),
-               WRITE_COEF(0x1a, 0x0021),
-               WRITE_COEF(0x26, 0x008c),
-               {}
-       };
-       static const struct coef_fw coef0288[] = {
-               UPDATE_COEF(0x4f, 0x00c0, 0),
-               UPDATE_COEF(0x50, 0x2000, 0),
-               UPDATE_COEF(0x56, 0x0006, 0),
-               UPDATE_COEF(0x4f, 0xfcc0, 0xc400),
-               UPDATE_COEF(0x66, 0x0008, 0x0008),
-               UPDATE_COEF(0x67, 0x2000, 0x2000),
-               {}
-       };
-       static const struct coef_fw coef0292[] = {
-               WRITE_COEF(0x19, 0xa208),
-               WRITE_COEF(0x2e, 0xacf0),
-               {}
-       };
-       static const struct coef_fw coef0293[] = {
-               UPDATE_COEFEX(0x57, 0x05, 0, 1<<15|1<<13), /* SET charge pump by verb */
-               UPDATE_COEFEX(0x57, 0x03, 1<<10, 0), /* SET EN_OSW to 0 */
-               UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
-               {}
-       };
-       static const struct coef_fw coef0688[] = {
-               WRITE_COEF(0xb7, 0x802b),
-               WRITE_COEF(0xb5, 0x1040),
-               UPDATE_COEF(0xc3, 0, 1<<12),
-               {}
-       };
-       static const struct coef_fw coef0225[] = {
-               UPDATE_COEFEX(0x57, 0x05, 1<<14, 1<<14),
-               UPDATE_COEF(0x4a, 3<<4, 2<<4),
-               UPDATE_COEF(0x63, 3<<14, 0),
-               {}
-       };
-       static const struct coef_fw coef0274[] = {
-               UPDATE_COEFEX(0x57, 0x05, 0x4000, 0x4000),
-               UPDATE_COEF(0x4a, 0x0010, 0),
-               UPDATE_COEF(0x6b, 0xf000, 0),
-               {}
-       };
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0255:
-               alc_write_coef_idx(codec, 0x45, 0xc489);
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0255);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x19e58326:
-               alc_write_coef_idx(codec, 0x45, 0xc489);
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0256);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       case 0x10ec0234:
-       case 0x10ec0274:
-       case 0x10ec0294:
-               alc_write_coef_idx(codec, 0x45, 0x4689);
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0274);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       case 0x10ec0233:
-       case 0x10ec0283:
-               alc_write_coef_idx(codec, 0x45, 0xc429);
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0233);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       case 0x10ec0286:
-       case 0x10ec0288:
-       case 0x10ec0298:
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0288);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       case 0x10ec0292:
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0292);
-               break;
-       case 0x10ec0293:
-               /* Set to TRS mode */
-               alc_write_coef_idx(codec, 0x45, 0xc429);
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0293);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       case 0x10ec0867:
-               alc_update_coefex_idx(codec, 0x57, 0x5, 0, 1<<14);
-               fallthrough;
-       case 0x10ec0221:
-       case 0x10ec0662:
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       case 0x10ec0668:
-               alc_write_coef_idx(codec, 0x11, 0x0001);
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0688);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       case 0x10ec0215:
-       case 0x10ec0225:
-       case 0x10ec0285:
-       case 0x10ec0295:
-       case 0x10ec0289:
-       case 0x10ec0299:
-               alc_process_coef_fw(codec, alc225_pre_hsmode);
-               alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x31<<10);
-               snd_hda_set_pin_ctl_cache(codec, hp_pin, 0);
-               alc_process_coef_fw(codec, coef0225);
-               snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50);
-               break;
-       }
-       codec_dbg(codec, "Headset jack set to mic-in mode.\n");
-}
-
-static void alc_headset_mode_default(struct hda_codec *codec)
-{
-       static const struct coef_fw coef0225[] = {
-               UPDATE_COEF(0x45, 0x3f<<10, 0x30<<10),
-               UPDATE_COEF(0x45, 0x3f<<10, 0x31<<10),
-               UPDATE_COEF(0x49, 3<<8, 0<<8),
-               UPDATE_COEF(0x4a, 3<<4, 3<<4),
-               UPDATE_COEF(0x63, 3<<14, 0),
-               UPDATE_COEF(0x67, 0xf000, 0x3000),
-               {}
-       };
-       static const struct coef_fw coef0255[] = {
-               WRITE_COEF(0x45, 0xc089),
-               WRITE_COEF(0x45, 0xc489),
-               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
-               WRITE_COEF(0x49, 0x0049),
-               {}
-       };
-       static const struct coef_fw coef0256[] = {
-               WRITE_COEF(0x45, 0xc489),
-               WRITE_COEFEX(0x57, 0x03, 0x0da3),
-               WRITE_COEF(0x49, 0x0049),
-               UPDATE_COEFEX(0x57, 0x05, 1<<14, 0), /* Direct Drive HP Amp control(Set to verb control)*/
-               WRITE_COEF(0x06, 0x6100),
-               {}
-       };
-       static const struct coef_fw coef0233[] = {
-               WRITE_COEF(0x06, 0x2100),
-               WRITE_COEF(0x32, 0x4ea3),
-               {}
-       };
-       static const struct coef_fw coef0288[] = {
-               UPDATE_COEF(0x4f, 0xfcc0, 0xc400), /* Set to TRS type */
-               UPDATE_COEF(0x50, 0x2000, 0x2000),
-               UPDATE_COEF(0x56, 0x0006, 0x0006),
-               UPDATE_COEF(0x66, 0x0008, 0),
-               UPDATE_COEF(0x67, 0x2000, 0),
-               {}
-       };
-       static const struct coef_fw coef0292[] = {
-               WRITE_COEF(0x76, 0x000e),
-               WRITE_COEF(0x6c, 0x2400),
-               WRITE_COEF(0x6b, 0xc429),
-               WRITE_COEF(0x18, 0x7308),
-               {}
-       };
-       static const struct coef_fw coef0293[] = {
-               UPDATE_COEF(0x4a, 0x000f, 0x000e), /* Combo Jack auto detect */
-               WRITE_COEF(0x45, 0xC429), /* Set to TRS type */
-               UPDATE_COEF(0x1a, 1<<3, 0), /* Combo JD gating without LINE1-VREFO */
-               {}
-       };
-       static const struct coef_fw coef0688[] = {
-               WRITE_COEF(0x11, 0x0041),
-               WRITE_COEF(0x15, 0x0d40),
-               WRITE_COEF(0xb7, 0x802b),
-               {}
-       };
-       static const struct coef_fw coef0274[] = {
-               WRITE_COEF(0x45, 0x4289),
-               UPDATE_COEF(0x4a, 0x0010, 0x0010),
-               UPDATE_COEF(0x6b, 0x0f00, 0),
-               UPDATE_COEF(0x49, 0x0300, 0x0300),
-               {}
-       };
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0215:
-       case 0x10ec0225:
-       case 0x10ec0285:
-       case 0x10ec0295:
-       case 0x10ec0289:
-       case 0x10ec0299:
-               alc_process_coef_fw(codec, alc225_pre_hsmode);
-               alc_process_coef_fw(codec, coef0225);
-               alc_hp_enable_unmute(codec, 75);
-               break;
-       case 0x10ec0255:
-               alc_process_coef_fw(codec, coef0255);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x19e58326:
-               alc_write_coef_idx(codec, 0x1b, 0x0e4b);
-               alc_write_coef_idx(codec, 0x45, 0xc089);
-               msleep(50);
-               alc_process_coef_fw(codec, coef0256);
-               alc_hp_enable_unmute(codec, 75);
-               break;
-       case 0x10ec0234:
-       case 0x10ec0274:
-       case 0x10ec0294:
-               alc_process_coef_fw(codec, coef0274);
-               break;
-       case 0x10ec0233:
-       case 0x10ec0283:
-               alc_process_coef_fw(codec, coef0233);
-               break;
-       case 0x10ec0286:
-       case 0x10ec0288:
-       case 0x10ec0298:
-               alc_process_coef_fw(codec, coef0288);
-               break;
-       case 0x10ec0292:
-               alc_process_coef_fw(codec, coef0292);
-               break;
-       case 0x10ec0293:
-               alc_process_coef_fw(codec, coef0293);
-               break;
-       case 0x10ec0668:
-               alc_process_coef_fw(codec, coef0688);
-               break;
-       case 0x10ec0867:
-               alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-               break;
-       }
-       codec_dbg(codec, "Headset jack set to headphone (default) mode.\n");
-}
-
-/* Iphone type */
-static void alc_headset_mode_ctia(struct hda_codec *codec)
-{
-       int val;
-
-       static const struct coef_fw coef0255[] = {
-               WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
-               WRITE_COEF(0x1b, 0x0c2b),
-               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
-               {}
-       };
-       static const struct coef_fw coef0256[] = {
-               WRITE_COEF(0x45, 0xd489), /* Set to CTIA type */
-               WRITE_COEF(0x1b, 0x0e6b),
-               {}
-       };
-       static const struct coef_fw coef0233[] = {
-               WRITE_COEF(0x45, 0xd429),
-               WRITE_COEF(0x1b, 0x0c2b),
-               WRITE_COEF(0x32, 0x4ea3),
-               {}
-       };
-       static const struct coef_fw coef0288[] = {
-               UPDATE_COEF(0x50, 0x2000, 0x2000),
-               UPDATE_COEF(0x56, 0x0006, 0x0006),
-               UPDATE_COEF(0x66, 0x0008, 0),
-               UPDATE_COEF(0x67, 0x2000, 0),
-               {}
-       };
-       static const struct coef_fw coef0292[] = {
-               WRITE_COEF(0x6b, 0xd429),
-               WRITE_COEF(0x76, 0x0008),
-               WRITE_COEF(0x18, 0x7388),
-               {}
-       };
-       static const struct coef_fw coef0293[] = {
-               WRITE_COEF(0x45, 0xd429), /* Set to ctia type */
-               UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
-               {}
-       };
-       static const struct coef_fw coef0688[] = {
-               WRITE_COEF(0x11, 0x0001),
-               WRITE_COEF(0x15, 0x0d60),
-               WRITE_COEF(0xc3, 0x0000),
-               {}
-       };
-       static const struct coef_fw coef0225_1[] = {
-               UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
-               UPDATE_COEF(0x63, 3<<14, 2<<14),
-               {}
-       };
-       static const struct coef_fw coef0225_2[] = {
-               UPDATE_COEF(0x45, 0x3f<<10, 0x35<<10),
-               UPDATE_COEF(0x63, 3<<14, 1<<14),
-               {}
-       };
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0255:
-               alc_process_coef_fw(codec, coef0255);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x19e58326:
-               alc_process_coef_fw(codec, coef0256);
-               alc_hp_enable_unmute(codec, 75);
-               break;
-       case 0x10ec0234:
-       case 0x10ec0274:
-       case 0x10ec0294:
-               alc_write_coef_idx(codec, 0x45, 0xd689);
-               break;
-       case 0x10ec0233:
-       case 0x10ec0283:
-               alc_process_coef_fw(codec, coef0233);
-               break;
-       case 0x10ec0298:
-               val = alc_read_coef_idx(codec, 0x50);
-               if (val & (1 << 12)) {
-                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
-                       alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
-                       msleep(300);
-               } else {
-                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
-                       alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
-                       msleep(300);
-               }
-               break;
-       case 0x10ec0286:
-       case 0x10ec0288:
-               alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xd400);
-               msleep(300);
-               alc_process_coef_fw(codec, coef0288);
-               break;
-       case 0x10ec0292:
-               alc_process_coef_fw(codec, coef0292);
-               break;
-       case 0x10ec0293:
-               alc_process_coef_fw(codec, coef0293);
-               break;
-       case 0x10ec0668:
-               alc_process_coef_fw(codec, coef0688);
-               break;
-       case 0x10ec0215:
-       case 0x10ec0225:
-       case 0x10ec0285:
-       case 0x10ec0295:
-       case 0x10ec0289:
-       case 0x10ec0299:
-               val = alc_read_coef_idx(codec, 0x45);
-               if (val & (1 << 9))
-                       alc_process_coef_fw(codec, coef0225_2);
-               else
-                       alc_process_coef_fw(codec, coef0225_1);
-               alc_hp_enable_unmute(codec, 75);
-               break;
-       case 0x10ec0867:
-               alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-               break;
-       }
-       codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n");
-}
-
-/* Nokia type */
-static void alc_headset_mode_omtp(struct hda_codec *codec)
-{
-       static const struct coef_fw coef0255[] = {
-               WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
-               WRITE_COEF(0x1b, 0x0c2b),
-               WRITE_COEFEX(0x57, 0x03, 0x8ea6),
-               {}
-       };
-       static const struct coef_fw coef0256[] = {
-               WRITE_COEF(0x45, 0xe489), /* Set to OMTP Type */
-               WRITE_COEF(0x1b, 0x0e6b),
-               {}
-       };
-       static const struct coef_fw coef0233[] = {
-               WRITE_COEF(0x45, 0xe429),
-               WRITE_COEF(0x1b, 0x0c2b),
-               WRITE_COEF(0x32, 0x4ea3),
-               {}
-       };
-       static const struct coef_fw coef0288[] = {
-               UPDATE_COEF(0x50, 0x2000, 0x2000),
-               UPDATE_COEF(0x56, 0x0006, 0x0006),
-               UPDATE_COEF(0x66, 0x0008, 0),
-               UPDATE_COEF(0x67, 0x2000, 0),
-               {}
-       };
-       static const struct coef_fw coef0292[] = {
-               WRITE_COEF(0x6b, 0xe429),
-               WRITE_COEF(0x76, 0x0008),
-               WRITE_COEF(0x18, 0x7388),
-               {}
-       };
-       static const struct coef_fw coef0293[] = {
-               WRITE_COEF(0x45, 0xe429), /* Set to omtp type */
-               UPDATE_COEF(0x10, 7<<8, 7<<8), /* SET Line1 JD to 1 */
-               {}
-       };
-       static const struct coef_fw coef0688[] = {
-               WRITE_COEF(0x11, 0x0001),
-               WRITE_COEF(0x15, 0x0d50),
-               WRITE_COEF(0xc3, 0x0000),
-               {}
-       };
-       static const struct coef_fw coef0225[] = {
-               UPDATE_COEF(0x45, 0x3f<<10, 0x39<<10),
-               UPDATE_COEF(0x63, 3<<14, 2<<14),
-               {}
-       };
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0255:
-               alc_process_coef_fw(codec, coef0255);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x19e58326:
-               alc_process_coef_fw(codec, coef0256);
-               alc_hp_enable_unmute(codec, 75);
-               break;
-       case 0x10ec0234:
-       case 0x10ec0274:
-       case 0x10ec0294:
-               alc_write_coef_idx(codec, 0x45, 0xe689);
-               break;
-       case 0x10ec0233:
-       case 0x10ec0283:
-               alc_process_coef_fw(codec, coef0233);
-               break;
-       case 0x10ec0298:
-               alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);/* Headset output enable */
-               alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
-               msleep(300);
-               break;
-       case 0x10ec0286:
-       case 0x10ec0288:
-               alc_update_coef_idx(codec, 0x4f, 0xfcc0, 0xe400);
-               msleep(300);
-               alc_process_coef_fw(codec, coef0288);
-               break;
-       case 0x10ec0292:
-               alc_process_coef_fw(codec, coef0292);
-               break;
-       case 0x10ec0293:
-               alc_process_coef_fw(codec, coef0293);
-               break;
-       case 0x10ec0668:
-               alc_process_coef_fw(codec, coef0688);
-               break;
-       case 0x10ec0215:
-       case 0x10ec0225:
-       case 0x10ec0285:
-       case 0x10ec0295:
-       case 0x10ec0289:
-       case 0x10ec0299:
-               alc_process_coef_fw(codec, coef0225);
-               alc_hp_enable_unmute(codec, 75);
-               break;
-       }
-       codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n");
-}
-
-static void alc_determine_headset_type(struct hda_codec *codec)
-{
-       int val;
-       bool is_ctia = false;
-       struct alc_spec *spec = codec->spec;
-       static const struct coef_fw coef0255[] = {
-               WRITE_COEF(0x45, 0xd089), /* combo jack auto switch control(Check type)*/
-               WRITE_COEF(0x49, 0x0149), /* combo jack auto switch control(Vref
- conteol) */
-               {}
-       };
-       static const struct coef_fw coef0288[] = {
-               UPDATE_COEF(0x4f, 0xfcc0, 0xd400), /* Check Type */
-               {}
-       };
-       static const struct coef_fw coef0298[] = {
-               UPDATE_COEF(0x50, 0x2000, 0x2000),
-               UPDATE_COEF(0x56, 0x0006, 0x0006),
-               UPDATE_COEF(0x66, 0x0008, 0),
-               UPDATE_COEF(0x67, 0x2000, 0),
-               UPDATE_COEF(0x19, 0x1300, 0x1300),
-               {}
-       };
-       static const struct coef_fw coef0293[] = {
-               UPDATE_COEF(0x4a, 0x000f, 0x0008), /* Combo Jack auto detect */
-               WRITE_COEF(0x45, 0xD429), /* Set to ctia type */
-               {}
-       };
-       static const struct coef_fw coef0688[] = {
-               WRITE_COEF(0x11, 0x0001),
-               WRITE_COEF(0xb7, 0x802b),
-               WRITE_COEF(0x15, 0x0d60),
-               WRITE_COEF(0xc3, 0x0c00),
-               {}
-       };
-       static const struct coef_fw coef0274[] = {
-               UPDATE_COEF(0x4a, 0x0010, 0),
-               UPDATE_COEF(0x4a, 0x8000, 0),
-               WRITE_COEF(0x45, 0xd289),
-               UPDATE_COEF(0x49, 0x0300, 0x0300),
-               {}
-       };
-
-       if (spec->no_internal_mic_pin) {
-               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
-               return;
-       }
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0255:
-               alc_process_coef_fw(codec, coef0255);
-               msleep(300);
-               val = alc_read_coef_idx(codec, 0x46);
-               is_ctia = (val & 0x0070) == 0x0070;
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x19e58326:
-               alc_write_coef_idx(codec, 0x1b, 0x0e4b);
-               alc_write_coef_idx(codec, 0x06, 0x6104);
-               alc_write_coefex_idx(codec, 0x57, 0x3, 0x09a3);
-
-               alc_process_coef_fw(codec, coef0255);
-               msleep(300);
-               val = alc_read_coef_idx(codec, 0x46);
-               is_ctia = (val & 0x0070) == 0x0070;
-               if (!is_ctia) {
-                       alc_write_coef_idx(codec, 0x45, 0xe089);
-                       msleep(100);
-                       val = alc_read_coef_idx(codec, 0x46);
-                       if ((val & 0x0070) == 0x0070)
-                               is_ctia = false;
-                       else
-                               is_ctia = true;
-               }
-               alc_write_coefex_idx(codec, 0x57, 0x3, 0x0da3);
-               alc_update_coefex_idx(codec, 0x57, 0x5, 1<<14, 0);
-               break;
-       case 0x10ec0234:
-       case 0x10ec0274:
-       case 0x10ec0294:
-               alc_process_coef_fw(codec, coef0274);
-               msleep(850);
-               val = alc_read_coef_idx(codec, 0x46);
-               is_ctia = (val & 0x00f0) == 0x00f0;
-               break;
-       case 0x10ec0233:
-       case 0x10ec0283:
-               alc_write_coef_idx(codec, 0x45, 0xd029);
-               msleep(300);
-               val = alc_read_coef_idx(codec, 0x46);
-               is_ctia = (val & 0x0070) == 0x0070;
-               break;
-       case 0x10ec0298:
-               snd_hda_codec_write(codec, 0x21, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-               msleep(100);
-               snd_hda_codec_write(codec, 0x21, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0);
-               msleep(200);
-
-               val = alc_read_coef_idx(codec, 0x50);
-               if (val & (1 << 12)) {
-                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0020);
-                       alc_process_coef_fw(codec, coef0288);
-                       msleep(350);
-                       val = alc_read_coef_idx(codec, 0x50);
-                       is_ctia = (val & 0x0070) == 0x0070;
-               } else {
-                       alc_update_coef_idx(codec, 0x8e, 0x0070, 0x0010);
-                       alc_process_coef_fw(codec, coef0288);
-                       msleep(350);
-                       val = alc_read_coef_idx(codec, 0x50);
-                       is_ctia = (val & 0x0070) == 0x0070;
-               }
-               alc_process_coef_fw(codec, coef0298);
-               snd_hda_codec_write(codec, 0x21, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP);
-               msleep(75);
-               snd_hda_codec_write(codec, 0x21, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-               break;
-       case 0x10ec0286:
-       case 0x10ec0288:
-               alc_process_coef_fw(codec, coef0288);
-               msleep(350);
-               val = alc_read_coef_idx(codec, 0x50);
-               is_ctia = (val & 0x0070) == 0x0070;
-               break;
-       case 0x10ec0292:
-               alc_write_coef_idx(codec, 0x6b, 0xd429);
-               msleep(300);
-               val = alc_read_coef_idx(codec, 0x6c);
-               is_ctia = (val & 0x001c) == 0x001c;
-               break;
-       case 0x10ec0293:
-               alc_process_coef_fw(codec, coef0293);
-               msleep(300);
-               val = alc_read_coef_idx(codec, 0x46);
-               is_ctia = (val & 0x0070) == 0x0070;
-               break;
-       case 0x10ec0668:
-               alc_process_coef_fw(codec, coef0688);
-               msleep(300);
-               val = alc_read_coef_idx(codec, 0xbe);
-               is_ctia = (val & 0x1c02) == 0x1c02;
-               break;
-       case 0x10ec0215:
-       case 0x10ec0225:
-       case 0x10ec0285:
-       case 0x10ec0295:
-       case 0x10ec0289:
-       case 0x10ec0299:
-               alc_process_coef_fw(codec, alc225_pre_hsmode);
-               alc_update_coef_idx(codec, 0x67, 0xf000, 0x1000);
-               val = alc_read_coef_idx(codec, 0x45);
-               if (val & (1 << 9)) {
-                       alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
-                       alc_update_coef_idx(codec, 0x49, 3<<8, 2<<8);
-                       msleep(800);
-                       val = alc_read_coef_idx(codec, 0x46);
-                       is_ctia = (val & 0x00f0) == 0x00f0;
-               } else {
-                       alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x34<<10);
-                       alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
-                       msleep(800);
-                       val = alc_read_coef_idx(codec, 0x46);
-                       is_ctia = (val & 0x00f0) == 0x00f0;
-               }
-               if (!is_ctia) {
-                       alc_update_coef_idx(codec, 0x45, 0x3f<<10, 0x38<<10);
-                       alc_update_coef_idx(codec, 0x49, 3<<8, 1<<8);
-                       msleep(100);
-                       val = alc_read_coef_idx(codec, 0x46);
-                       if ((val & 0x00f0) == 0x00f0)
-                               is_ctia = false;
-                       else
-                               is_ctia = true;
-               }
-               alc_update_coef_idx(codec, 0x4a, 7<<6, 7<<6);
-               alc_update_coef_idx(codec, 0x4a, 3<<4, 3<<4);
-               alc_update_coef_idx(codec, 0x67, 0xf000, 0x3000);
-               break;
-       case 0x10ec0867:
-               is_ctia = true;
-               break;
-       }
-
-       codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n",
-                 str_yes_no(is_ctia));
-       spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP;
-}
-
-static void alc_update_headset_mode(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-
-       hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]];
-       hda_nid_t hp_pin = alc_get_hp_pin(spec);
-
-       int new_headset_mode;
-
-       if (!snd_hda_jack_detect(codec, hp_pin))
-               new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED;
-       else if (mux_pin == spec->headset_mic_pin)
-               new_headset_mode = ALC_HEADSET_MODE_HEADSET;
-       else if (mux_pin == spec->headphone_mic_pin)
-               new_headset_mode = ALC_HEADSET_MODE_MIC;
-       else
-               new_headset_mode = ALC_HEADSET_MODE_HEADPHONE;
-
-       if (new_headset_mode == spec->current_headset_mode) {
-               snd_hda_gen_update_outputs(codec);
-               return;
-       }
-
-       switch (new_headset_mode) {
-       case ALC_HEADSET_MODE_UNPLUGGED:
-               alc_headset_mode_unplugged(codec);
-               spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
-               spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
-               spec->gen.hp_jack_present = false;
-               break;
-       case ALC_HEADSET_MODE_HEADSET:
-               if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN)
-                       alc_determine_headset_type(codec);
-               if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA)
-                       alc_headset_mode_ctia(codec);
-               else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP)
-                       alc_headset_mode_omtp(codec);
-               spec->gen.hp_jack_present = true;
-               break;
-       case ALC_HEADSET_MODE_MIC:
-               alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin);
-               spec->gen.hp_jack_present = false;
-               break;
-       case ALC_HEADSET_MODE_HEADPHONE:
-               alc_headset_mode_default(codec);
-               spec->gen.hp_jack_present = true;
-               break;
-       }
-       if (new_headset_mode != ALC_HEADSET_MODE_MIC) {
-               snd_hda_set_pin_ctl_cache(codec, hp_pin,
-                                         AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN);
-               if (spec->headphone_mic_pin && spec->headphone_mic_pin != hp_pin)
-                       snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin,
-                                                 PIN_VREFHIZ);
-       }
-       spec->current_headset_mode = new_headset_mode;
-
-       snd_hda_gen_update_outputs(codec);
-}
-
-static void alc_update_headset_mode_hook(struct hda_codec *codec,
-                                        struct snd_kcontrol *kcontrol,
-                                        struct snd_ctl_elem_value *ucontrol)
-{
-       alc_update_headset_mode(codec);
-}
-
-static void alc_update_headset_jack_cb(struct hda_codec *codec,
-                                      struct hda_jack_callback *jack)
-{
-       snd_hda_gen_hp_automute(codec, jack);
-       alc_update_headset_mode(codec);
-}
-
-static void alc_probe_headset_mode(struct hda_codec *codec)
-{
-       int i;
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-
-       /* Find mic pins */
-       for (i = 0; i < cfg->num_inputs; i++) {
-               if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin)
-                       spec->headset_mic_pin = cfg->inputs[i].pin;
-               if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin)
-                       spec->headphone_mic_pin = cfg->inputs[i].pin;
-       }
-
-       WARN_ON(spec->gen.cap_sync_hook);
-       spec->gen.cap_sync_hook = alc_update_headset_mode_hook;
-       spec->gen.automute_hook = alc_update_headset_mode;
-       spec->gen.hp_automute_hook = alc_update_headset_jack_cb;
-}
-
-static void alc_fixup_headset_mode(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC;
-               break;
-       case HDA_FIXUP_ACT_PROBE:
-               alc_probe_headset_mode(codec);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               if (is_s3_resume(codec) || is_s4_resume(codec)) {
-                       spec->current_headset_mode = ALC_HEADSET_MODE_UNKNOWN;
-                       spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN;
-               }
-               alc_update_headset_mode(codec);
-               break;
-       }
-}
-
-static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               struct alc_spec *spec = codec->spec;
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-       }
-       else
-               alc_fixup_headset_mode(codec, fix, action);
-}
-
-static void alc255_set_default_jack_type(struct hda_codec *codec)
-{
-       /* Set to iphone type */
-       static const struct coef_fw alc255fw[] = {
-               WRITE_COEF(0x1b, 0x880b),
-               WRITE_COEF(0x45, 0xd089),
-               WRITE_COEF(0x1b, 0x080b),
-               WRITE_COEF(0x46, 0x0004),
-               WRITE_COEF(0x1b, 0x0c0b),
-               {}
-       };
-       static const struct coef_fw alc256fw[] = {
-               WRITE_COEF(0x1b, 0x884b),
-               WRITE_COEF(0x45, 0xd089),
-               WRITE_COEF(0x1b, 0x084b),
-               WRITE_COEF(0x46, 0x0004),
-               WRITE_COEF(0x1b, 0x0c4b),
-               {}
-       };
-       switch (codec->core.vendor_id) {
-       case 0x10ec0255:
-               alc_process_coef_fw(codec, alc255fw);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x19e58326:
-               alc_process_coef_fw(codec, alc256fw);
-               break;
-       }
-       msleep(30);
-}
-
-static void alc_fixup_headset_mode_alc255(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               alc255_set_default_jack_type(codec);
-       }
-       alc_fixup_headset_mode(codec, fix, action);
-}
-
-static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               struct alc_spec *spec = codec->spec;
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-               alc255_set_default_jack_type(codec);
-       }
-       else
-               alc_fixup_headset_mode(codec, fix, action);
-}
-
-static void alc288_update_headset_jack_cb(struct hda_codec *codec,
-                                      struct hda_jack_callback *jack)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_update_headset_jack_cb(codec, jack);
-       /* Headset Mic enable or disable, only for Dell Dino */
-       alc_update_gpio_data(codec, 0x40, spec->gen.hp_jack_present);
-}
-
-static void alc_fixup_headset_mode_dell_alc288(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       alc_fixup_headset_mode(codec, fix, action);
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               struct alc_spec *spec = codec->spec;
-               /* toggled via hp_automute_hook */
-               spec->gpio_mask |= 0x40;
-               spec->gpio_dir |= 0x40;
-               spec->gen.hp_automute_hook = alc288_update_headset_jack_cb;
-       }
-}
-
-static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec,
-                                       const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               struct alc_spec *spec = codec->spec;
-               spec->gen.auto_mute_via_amp = 1;
-       }
-}
-
-static void alc_fixup_no_shutup(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               struct alc_spec *spec = codec->spec;
-               spec->no_shutup_pins = 1;
-       }
-}
-
-static void alc_fixup_disable_aamix(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               struct alc_spec *spec = codec->spec;
-               /* Disable AA-loopback as it causes white noise */
-               spec->gen.mixer_nid = 0;
-       }
-}
-
-/* fixup for Thinkpad docks: add dock pins, avoid HP parser fixup */
-static void alc_fixup_tpt440_dock(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x16, 0x21211010 }, /* dock headphone */
-               { 0x19, 0x21a11010 }, /* dock mic */
-               { }
-       };
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
-               codec->power_save_node = 0; /* avoid click noises */
-               snd_hda_apply_pincfgs(codec, pincfgs);
-       }
-}
-
-static void alc_fixup_tpt470_dock(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x17, 0x21211010 }, /* dock headphone */
-               { 0x19, 0x21a11010 }, /* dock mic */
-               { }
-       };
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
-               snd_hda_apply_pincfgs(codec, pincfgs);
-       } else if (action == HDA_FIXUP_ACT_INIT) {
-               /* Enable DOCK device */
-               snd_hda_codec_write(codec, 0x17, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);
-               /* Enable DOCK device */
-               snd_hda_codec_write(codec, 0x19, 0,
-                           AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, 0);
-       }
-}
-
-static void alc_fixup_tpt470_dacs(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       /* Assure the speaker pin to be coupled with DAC NID 0x03; otherwise
-        * the speaker output becomes too low by some reason on Thinkpads with
-        * ALC298 codec
-        */
-       static const hda_nid_t preferred_pairs[] = {
-               0x14, 0x03, 0x17, 0x02, 0x21, 0x02,
-               0
-       };
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->gen.preferred_dacs = preferred_pairs;
-}
-
-static void alc295_fixup_asus_dacs(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t preferred_pairs[] = {
-               0x17, 0x02, 0x21, 0x03, 0
-       };
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->gen.preferred_dacs = preferred_pairs;
-}
-
-static void alc_shutup_dell_xps13(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int hp_pin = alc_get_hp_pin(spec);
-
-       /* Prevent pop noises when headphones are plugged in */
-       snd_hda_codec_write(codec, hp_pin, 0,
-                           AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
-       msleep(20);
-}
-
-static void alc_fixup_dell_xps13(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->gen.input_mux;
-       int i;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               /* mic pin 0x19 must be initialized with Vref Hi-Z, otherwise
-                * it causes a click noise at start up
-                */
-               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
-               spec->shutup = alc_shutup_dell_xps13;
-               break;
-       case HDA_FIXUP_ACT_PROBE:
-               /* Make the internal mic the default input source. */
-               for (i = 0; i < imux->num_items; i++) {
-                       if (spec->gen.imux_pins[i] == 0x12) {
-                               spec->gen.cur_mux[0] = i;
-                               break;
-                       }
-               }
-               break;
-       }
-}
-
-static void alc_fixup_headset_mode_alc662(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-               spec->gen.hp_mic = 1; /* Mic-in is same pin as headphone */
-
-               /* Disable boost for mic-in permanently. (This code is only called
-                  from quirks that guarantee that the headphone is at NID 0x1b.) */
-               snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000);
-               snd_hda_override_wcaps(codec, 0x1b, get_wcaps(codec, 0x1b) & ~AC_WCAP_IN_AMP);
-       } else
-               alc_fixup_headset_mode(codec, fix, action);
-}
-
-static void alc_fixup_headset_mode_alc668(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               alc_write_coef_idx(codec, 0xc4, 0x8000);
-               alc_update_coef_idx(codec, 0xc2, ~0xfe, 0);
-               snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
-       }
-       alc_fixup_headset_mode(codec, fix, action);
-}
-
-/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */
-static int find_ext_mic_pin(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-       hda_nid_t nid;
-       unsigned int defcfg;
-       int i;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               if (cfg->inputs[i].type != AUTO_PIN_MIC)
-                       continue;
-               nid = cfg->inputs[i].pin;
-               defcfg = snd_hda_codec_get_pincfg(codec, nid);
-               if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT)
-                       continue;
-               return nid;
-       }
-
-       return 0;
-}
-
-static void alc271_hp_gate_mic_jack(struct hda_codec *codec,
-                                   const struct hda_fixup *fix,
-                                   int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               int mic_pin = find_ext_mic_pin(codec);
-               int hp_pin = alc_get_hp_pin(spec);
-
-               if (snd_BUG_ON(!mic_pin || !hp_pin))
-                       return;
-               snd_hda_jack_set_gating_jack(codec, mic_pin, hp_pin);
-       }
-}
-
-static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec,
-                                            const struct hda_fixup *fix,
-                                            int action)
-{
-       struct alc_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-       int i;
-
-       /* The mic boosts on level 2 and 3 are too noisy
-          on the internal mic input.
-          Therefore limit the boost to 0 or 1. */
-
-       if (action != HDA_FIXUP_ACT_PROBE)
-               return;
-
-       for (i = 0; i < cfg->num_inputs; i++) {
-               hda_nid_t nid = cfg->inputs[i].pin;
-               unsigned int defcfg;
-               if (cfg->inputs[i].type != AUTO_PIN_MIC)
-                       continue;
-               defcfg = snd_hda_codec_get_pincfg(codec, nid);
-               if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT)
-                       continue;
-
-               snd_hda_override_amp_caps(codec, nid, HDA_INPUT,
-                                         (0x00 << AC_AMPCAP_OFFSET_SHIFT) |
-                                         (0x01 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                         (0x2f << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                         (0 << AC_AMPCAP_MUTE_SHIFT));
-       }
-}
-
-static void alc283_hp_automute_hook(struct hda_codec *codec,
-                                   struct hda_jack_callback *jack)
-{
-       struct alc_spec *spec = codec->spec;
-       int vref;
-
-       msleep(200);
-       snd_hda_gen_hp_automute(codec, jack);
-
-       vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
-
-       msleep(600);
-       snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           vref);
-}
-
-static void alc283_fixup_chromebook(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_override_wcaps(codec, 0x03, 0);
-               /* Disable AA-loopback as it causes white noise */
-               spec->gen.mixer_nid = 0;
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               /* MIC2-VREF control */
-               /* Set to manual mode */
-               alc_update_coef_idx(codec, 0x06, 0x000c, 0);
-               /* Enable Line1 input control by verb */
-               alc_update_coef_idx(codec, 0x1a, 0, 1 << 4);
-               break;
-       }
-}
-
-static void alc283_fixup_sense_combo_jack(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gen.hp_automute_hook = alc283_hp_automute_hook;
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               /* MIC2-VREF control */
-               /* Set to manual mode */
-               alc_update_coef_idx(codec, 0x06, 0x000c, 0);
-               break;
-       }
-}
-
-/* mute tablet speaker pin (0x14) via dock plugging in addition */
-static void asus_tx300_automute(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       snd_hda_gen_update_outputs(codec);
-       if (snd_hda_jack_detect(codec, 0x1b))
-               spec->gen.mute_bits |= (1ULL << 0x14);
-}
-
-static void alc282_fixup_asus_tx300(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       static const struct hda_pintbl dock_pins[] = {
-               { 0x1b, 0x21114000 }, /* dock speaker pin */
-               {}
-       };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->init_amp = ALC_INIT_DEFAULT;
-               /* TX300 needs to set up GPIO2 for the speaker amp */
-               alc_setup_gpio(codec, 0x04);
-               snd_hda_apply_pincfgs(codec, dock_pins);
-               spec->gen.auto_mute_via_amp = 1;
-               spec->gen.automute_hook = asus_tx300_automute;
-               snd_hda_jack_detect_enable_callback(codec, 0x1b,
-                                                   snd_hda_gen_hp_automute);
-               break;
-       case HDA_FIXUP_ACT_PROBE:
-               spec->init_amp = ALC_INIT_DEFAULT;
-               break;
-       case HDA_FIXUP_ACT_BUILD:
-               /* this is a bit tricky; give more sane names for the main
-                * (tablet) speaker and the dock speaker, respectively
-                */
-               rename_ctl(codec, "Speaker Playback Switch",
-                          "Dock Speaker Playback Switch");
-               rename_ctl(codec, "Bass Speaker Playback Switch",
-                          "Speaker Playback Switch");
-               break;
-       }
-}
-
-static void alc290_fixup_mono_speakers(struct hda_codec *codec,
-                                      const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               /* DAC node 0x03 is giving mono output. We therefore want to
-                  make sure 0x14 (front speaker) and 0x15 (headphones) use the
-                  stereo DAC, while leaving 0x17 (bass speaker) for node 0x03. */
-               static const hda_nid_t conn1[] = { 0x0c };
-               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn1), conn1);
-               snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn1), conn1);
-       }
-}
-
-static void alc298_fixup_speaker_volume(struct hda_codec *codec,
-                                       const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               /* The speaker is routed to the Node 0x06 by a mistake, as a result
-                  we can't adjust the speaker's volume since this node does not has
-                  Amp-out capability. we change the speaker's route to:
-                  Node 0x02 (Audio Output) -> Node 0x0c (Audio Mixer) -> Node 0x17 (
-                  Pin Complex), since Node 0x02 has Amp-out caps, we can adjust
-                  speaker's volume now. */
-
-               static const hda_nid_t conn1[] = { 0x0c };
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn1), conn1);
-       }
-}
-
-/* disable DAC3 (0x06) selection on NID 0x17 as it has no volume amp control */
-static void alc295_fixup_disable_dac3(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               static const hda_nid_t conn[] = { 0x02, 0x03 };
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-       }
-}
-
-/* force NID 0x17 (Bass Speaker) to DAC1 to share it with the main speaker */
-static void alc285_fixup_speaker2_to_dac1(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               static const hda_nid_t conn[] = { 0x02 };
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-       }
-}
-
-/* disable DAC3 (0x06) selection on NID 0x15 - share Speaker/Bass Speaker DAC 0x03 */
-static void alc294_fixup_bass_speaker_15(struct hda_codec *codec,
-                                        const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               static const hda_nid_t conn[] = { 0x02, 0x03 };
-               snd_hda_override_conn_list(codec, 0x15, ARRAY_SIZE(conn), conn);
-               snd_hda_gen_add_micmute_led_cdev(codec, NULL);
-       }
-}
-
-/* Hook to update amp GPIO4 for automute */
-static void alc280_hp_gpio4_automute_hook(struct hda_codec *codec,
-                                         struct hda_jack_callback *jack)
-{
-       struct alc_spec *spec = codec->spec;
-
-       snd_hda_gen_hp_automute(codec, jack);
-       /* mute_led_polarity is set to 0, so we pass inverted value here */
-       alc_update_gpio_led(codec, 0x10, spec->mute_led_polarity,
-                           !spec->gen.hp_jack_present);
-}
-
-/* Manage GPIOs for HP EliteBook Folio 9480m.
- *
- * GPIO4 is the headphone amplifier power control
- * GPIO3 is the audio output mute indicator LED
- */
-
-static void alc280_fixup_hp_9480m(struct hda_codec *codec,
-                                 const struct hda_fixup *fix,
-                                 int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_fixup_hp_gpio_led(codec, action, 0x08, 0);
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               /* amp at GPIO4; toggled via alc280_hp_gpio4_automute_hook() */
-               spec->gpio_mask |= 0x10;
-               spec->gpio_dir |= 0x10;
-               spec->gen.hp_automute_hook = alc280_hp_gpio4_automute_hook;
-       }
-}
-
-static void alc275_fixup_gpio4_off(struct hda_codec *codec,
-                                  const struct hda_fixup *fix,
-                                  int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gpio_mask |= 0x04;
-               spec->gpio_dir |= 0x04;
-               /* set data bit low */
-       }
-}
-
-/* Quirk for Thinkpad X1 7th and 8th Gen
- * The following fixed routing needed
- * DAC1 (NID 0x02) -> Speaker (NID 0x14); some eq applied secretly
- * DAC2 (NID 0x03) -> Bass (NID 0x17) & Headphone (NID 0x21); sharing a DAC
- * DAC3 (NID 0x06) -> Unused, due to the lack of volume amp
- */
-static void alc285_fixup_thinkpad_x1_gen7(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
-       static const hda_nid_t preferred_pairs[] = {
-               0x14, 0x02, 0x17, 0x03, 0x21, 0x03, 0
-       };
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               spec->gen.preferred_dacs = preferred_pairs;
-               break;
-       case HDA_FIXUP_ACT_BUILD:
-               /* The generic parser creates somewhat unintuitive volume ctls
-                * with the fixed routing above, and the shared DAC2 may be
-                * confusing for PA.
-                * Rename those to unique names so that PA doesn't touch them
-                * and use only Master volume.
-                */
-               rename_ctl(codec, "Front Playback Volume", "DAC1 Playback Volume");
-               rename_ctl(codec, "Bass Speaker Playback Volume", "DAC2 Playback Volume");
-               break;
-       }
-}
-
-static void alc233_alc662_fixup_lenovo_dual_codecs(struct hda_codec *codec,
-                                        const struct hda_fixup *fix,
-                                        int action)
-{
-       alc_fixup_dual_codecs(codec, fix, action);
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               /* override card longname to provide a unique UCM profile */
-               strcpy(codec->card->longname, "HDAudio-Lenovo-DualCodecs");
-               break;
-       case HDA_FIXUP_ACT_BUILD:
-               /* rename Capture controls depending on the codec */
-               rename_ctl(codec, "Capture Volume",
-                          codec->addr == 0 ?
-                          "Rear-Panel Capture Volume" :
-                          "Front-Panel Capture Volume");
-               rename_ctl(codec, "Capture Switch",
-                          codec->addr == 0 ?
-                          "Rear-Panel Capture Switch" :
-                          "Front-Panel Capture Switch");
-               break;
-       }
-}
-
-static void alc225_fixup_s3_pop_noise(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       codec->power_save_node = 1;
-}
-
-/* Forcibly assign NID 0x03 to HP/LO while NID 0x02 to SPK for EQ */
-static void alc274_fixup_bind_dacs(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       static const hda_nid_t preferred_pairs[] = {
-               0x21, 0x03, 0x1b, 0x03, 0x16, 0x02,
-               0
-       };
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       spec->gen.preferred_dacs = preferred_pairs;
-       spec->gen.auto_mute_via_amp = 1;
-       codec->power_save_node = 0;
-}
-
-/* avoid DAC 0x06 for speaker switch 0x17; it has no volume control */
-static void alc274_fixup_hp_aio_bind_dacs(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
-       /* The speaker is routed to the Node 0x06 by a mistake, thus the
-        * speaker's volume can't be adjusted since the node doesn't have
-        * Amp-out capability. Assure the speaker and lineout pin to be
-        * coupled with DAC NID 0x02.
-        */
-       static const hda_nid_t preferred_pairs[] = {
-               0x16, 0x02, 0x17, 0x02, 0x21, 0x03, 0
-       };
-       struct alc_spec *spec = codec->spec;
-
-       snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-       spec->gen.preferred_dacs = preferred_pairs;
-}
-
-/* avoid DAC 0x06 for bass speaker 0x17; it has no volume control */
-static void alc289_fixup_asus_ga401(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t preferred_pairs[] = {
-               0x14, 0x02, 0x17, 0x02, 0x21, 0x03, 0
-       };
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->gen.preferred_dacs = preferred_pairs;
-}
-
-/* The DAC of NID 0x3 will introduce click/pop noise on headphones, so invalidate it */
-static void alc285_fixup_invalidate_dacs(struct hda_codec *codec,
-                             const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       snd_hda_override_wcaps(codec, 0x03, 0);
-}
-
-static void alc_combo_jack_hp_jd_restart(struct hda_codec *codec)
-{
-       switch (codec->core.vendor_id) {
-       case 0x10ec0274:
-       case 0x10ec0294:
-       case 0x10ec0225:
-       case 0x10ec0295:
-       case 0x10ec0299:
-               alc_update_coef_idx(codec, 0x4a, 0x8000, 1 << 15); /* Reset HP JD */
-               alc_update_coef_idx(codec, 0x4a, 0x8000, 0 << 15);
-               break;
-       case 0x10ec0230:
-       case 0x10ec0235:
-       case 0x10ec0236:
-       case 0x10ec0255:
-       case 0x10ec0256:
-       case 0x10ec0257:
-       case 0x19e58326:
-               alc_update_coef_idx(codec, 0x1b, 0x8000, 1 << 15); /* Reset HP JD */
-               alc_update_coef_idx(codec, 0x1b, 0x8000, 0 << 15);
-               break;
-       }
-}
-
-static void alc295_fixup_chromebook(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->ultra_low_power = true;
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               alc_combo_jack_hp_jd_restart(codec);
-               break;
-       }
-}
-
-static void alc256_fixup_chromebook(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               if (codec->core.subsystem_id == 0x10280d76)
-                       spec->gen.suppress_auto_mute = 0;
-               else
-                       spec->gen.suppress_auto_mute = 1;
-               spec->gen.suppress_auto_mic = 1;
-               spec->en_3kpull_low = false;
-               break;
-       }
-}
-
-static void alc_fixup_disable_mic_vref(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
-}
-
-
-static void alc294_gx502_toggle_output(struct hda_codec *codec,
-                                       struct hda_jack_callback *cb)
-{
-       /* The Windows driver sets the codec up in a very different way where
-        * it appears to leave 0x10 = 0x8a20 set. For Linux we need to toggle it
-        */
-       if (snd_hda_jack_detect_state(codec, 0x21) == HDA_JACK_PRESENT)
-               alc_write_coef_idx(codec, 0x10, 0x8a20);
-       else
-               alc_write_coef_idx(codec, 0x10, 0x0a20);
-}
-
-static void alc294_fixup_gx502_hp(struct hda_codec *codec,
-                                       const struct hda_fixup *fix, int action)
-{
-       /* Pin 0x21: headphones/headset mic */
-       if (!is_jack_detectable(codec, 0x21))
-               return;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_jack_detect_enable_callback(codec, 0x21,
-                               alc294_gx502_toggle_output);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               /* Make sure to start in a correct state, i.e. if
-                * headphones have been plugged in before powering up the system
-                */
-               alc294_gx502_toggle_output(codec, NULL);
-               break;
-       }
-}
-
-static void alc294_gu502_toggle_output(struct hda_codec *codec,
-                                      struct hda_jack_callback *cb)
-{
-       /* Windows sets 0x10 to 0x8420 for Node 0x20 which is
-        * responsible from changes between speakers and headphones
-        */
-       if (snd_hda_jack_detect_state(codec, 0x21) == HDA_JACK_PRESENT)
-               alc_write_coef_idx(codec, 0x10, 0x8420);
-       else
-               alc_write_coef_idx(codec, 0x10, 0x0a20);
-}
-
-static void alc294_fixup_gu502_hp(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       if (!is_jack_detectable(codec, 0x21))
-               return;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_jack_detect_enable_callback(codec, 0x21,
-                               alc294_gu502_toggle_output);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               alc294_gu502_toggle_output(codec, NULL);
-               break;
-       }
-}
-
-static void  alc285_fixup_hp_gpio_amp_init(struct hda_codec *codec,
-                             const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_INIT)
-               return;
-
-       msleep(100);
-       alc_write_coef_idx(codec, 0x65, 0x0);
-}
-
-static void alc274_fixup_hp_headset_mic(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       switch (action) {
-       case HDA_FIXUP_ACT_INIT:
-               alc_combo_jack_hp_jd_restart(codec);
-               break;
-       }
-}
-
-static void alc_fixup_no_int_mic(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               /* Mic RING SLEEVE swap for combo jack */
-               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
-               spec->no_internal_mic_pin = true;
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               alc_combo_jack_hp_jd_restart(codec);
-               break;
-       }
-}
-
-/* GPIO1 = amplifier on/off
- * GPIO3 = mic mute LED
- */
-static void alc285_fixup_hp_spectre_x360_eb1(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t conn[] = { 0x02 };
-
-       struct alc_spec *spec = codec->spec;
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x14, 0x90170110 },  /* front/high speakers */
-               { 0x17, 0x90170130 },  /* back/bass speakers */
-               { }
-       };
-
-       //enable micmute led
-       alc_fixup_hp_gpio_led(codec, action, 0x00, 0x04);
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->micmute_led_polarity = 1;
-               /* needed for amp of back speakers */
-               spec->gpio_mask |= 0x01;
-               spec->gpio_dir |= 0x01;
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               /* share DAC to have unified volume control */
-               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               /* need to toggle GPIO to enable the amp of back speakers */
-               alc_update_gpio_data(codec, 0x01, true);
-               msleep(100);
-               alc_update_gpio_data(codec, 0x01, false);
-               break;
-       }
-}
-
-/* GPIO1 = amplifier on/off */
-static void alc285_fixup_hp_spectre_x360_df1(struct hda_codec *codec,
-                                            const struct hda_fixup *fix,
-                                            int action)
-{
-       struct alc_spec *spec = codec->spec;
-       static const hda_nid_t conn[] = { 0x02 };
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x14, 0x90170110 },  /* front/high speakers */
-               { 0x17, 0x90170130 },  /* back/bass speakers */
-               { }
-       };
-
-       // enable mute led
-       alc285_fixup_hp_mute_led_coefbit(codec, fix, action);
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               /* needed for amp of back speakers */
-               spec->gpio_mask |= 0x01;
-               spec->gpio_dir |= 0x01;
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               /* share DAC to have unified volume control */
-               snd_hda_override_conn_list(codec, 0x14, ARRAY_SIZE(conn), conn);
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               /* need to toggle GPIO to enable the amp of back speakers */
-               alc_update_gpio_data(codec, 0x01, true);
-               msleep(100);
-               alc_update_gpio_data(codec, 0x01, false);
-               break;
-       }
-}
-
-static void alc285_fixup_hp_spectre_x360(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       static const hda_nid_t conn[] = { 0x02 };
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x14, 0x90170110 },  /* rear speaker */
-               { }
-       };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               /* force front speaker to DAC1 */
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               break;
-       }
-}
-
-static void alc285_fixup_hp_envy_x360(struct hda_codec *codec,
-                                     const struct hda_fixup *fix,
-                                     int action)
-{
-       static const struct coef_fw coefs[] = {
-               WRITE_COEF(0x08, 0x6a0c), WRITE_COEF(0x0d, 0xa023),
-               WRITE_COEF(0x10, 0x0320), WRITE_COEF(0x1a, 0x8c03),
-               WRITE_COEF(0x25, 0x1800), WRITE_COEF(0x26, 0x003a),
-               WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb014),
-               WRITE_COEF(0x2b, 0x1dfe), WRITE_COEF(0x37, 0xfe15),
-               WRITE_COEF(0x38, 0x7909), WRITE_COEF(0x45, 0xd489),
-               WRITE_COEF(0x46, 0x00f4), WRITE_COEF(0x4a, 0x21e0),
-               WRITE_COEF(0x66, 0x03f0), WRITE_COEF(0x67, 0x1000),
-               WRITE_COEF(0x6e, 0x1005), { }
-       };
-
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x12, 0xb7a60130 },  /* Internal microphone*/
-               { 0x14, 0x90170150 },  /* B&O soundbar speakers */
-               { 0x17, 0x90170153 },  /* Side speakers */
-               { 0x19, 0x03a11040 },  /* Headset microphone */
-               { }
-       };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_apply_pincfgs(codec, pincfgs);
-
-               /* Fixes volume control problem for side speakers */
-               alc295_fixup_disable_dac3(codec, fix, action);
-
-               /* Fixes no sound from headset speaker */
-               snd_hda_codec_amp_stereo(codec, 0x21, HDA_OUTPUT, 0, -1, 0);
-
-               /* Auto-enable headset mic when plugged */
-               snd_hda_jack_set_gating_jack(codec, 0x19, 0x21);
-
-               /* Headset mic volume enhancement */
-               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREF50);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               alc_process_coef_fw(codec, coefs);
-               break;
-       case HDA_FIXUP_ACT_BUILD:
-               rename_ctl(codec, "Bass Speaker Playback Volume",
-                          "B&O-Tuned Playback Volume");
-               rename_ctl(codec, "Front Playback Switch",
-                          "B&O Soundbar Playback Switch");
-               rename_ctl(codec, "Bass Speaker Playback Switch",
-                          "Side Speaker Playback Switch");
-               break;
-       }
-}
-
-static void alc285_fixup_hp_beep(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               codec->beep_just_power_on = true;
-       } else  if (action == HDA_FIXUP_ACT_INIT) {
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-               /*
-                * Just enable loopback to internal speaker and headphone jack.
-                * Disable amplification to get about the same beep volume as
-                * was on pure BIOS setup before loading the driver.
-                */
-               alc_update_coef_idx(codec, 0x36, 0x7070, BIT(13));
-
-               snd_hda_enable_beep_device(codec, 1);
-
-#if !IS_ENABLED(CONFIG_INPUT_PCSPKR)
-               dev_warn_once(hda_codec_dev(codec),
-                             "enable CONFIG_INPUT_PCSPKR to get PC beeps\n");
-#endif
-#endif
-       }
-}
-
-/* for hda_fixup_thinkpad_acpi() */
-#include "thinkpad_helper.c"
-
-static void alc_fixup_thinkpad_acpi(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       alc_fixup_no_shutup(codec, fix, action); /* reduce click noise */
-       hda_fixup_thinkpad_acpi(codec, fix, action);
-}
-
-/* for hda_fixup_ideapad_acpi() */
-#include "ideapad_hotkey_led_helper.c"
-
-static void alc_fixup_ideapad_acpi(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       hda_fixup_ideapad_acpi(codec, fix, action);
-}
-
-/* Fixup for Lenovo Legion 15IMHg05 speaker output on headset removal. */
-static void alc287_fixup_legion_15imhg05_speakers(struct hda_codec *codec,
-                                                 const struct hda_fixup *fix,
-                                                 int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gen.suppress_auto_mute = 1;
-               break;
-       }
-}
-
-static void comp_acpi_device_notify(acpi_handle handle, u32 event, void *data)
-{
-       struct hda_codec *cdc = data;
-       struct alc_spec *spec = cdc->spec;
-
-       codec_info(cdc, "ACPI Notification %d\n", event);
-
-       hda_component_acpi_device_notify(&spec->comps, handle, event, data);
-}
-
-static int comp_bind(struct device *dev)
-{
-       struct hda_codec *cdc = dev_to_hda_codec(dev);
-       struct alc_spec *spec = cdc->spec;
-       int ret;
-
-       ret = hda_component_manager_bind(cdc, &spec->comps);
-       if (ret)
-               return ret;
-
-       return hda_component_manager_bind_acpi_notifications(cdc,
-                                                            &spec->comps,
-                                                            comp_acpi_device_notify, cdc);
-}
-
-static void comp_unbind(struct device *dev)
-{
-       struct hda_codec *cdc = dev_to_hda_codec(dev);
-       struct alc_spec *spec = cdc->spec;
-
-       hda_component_manager_unbind_acpi_notifications(cdc, &spec->comps, comp_acpi_device_notify);
-       hda_component_manager_unbind(cdc, &spec->comps);
-}
-
-static const struct component_master_ops comp_master_ops = {
-       .bind = comp_bind,
-       .unbind = comp_unbind,
-};
-
-static void comp_generic_playback_hook(struct hda_pcm_stream *hinfo, struct hda_codec *cdc,
-                                      struct snd_pcm_substream *sub, int action)
-{
-       struct alc_spec *spec = cdc->spec;
-
-       hda_component_manager_playback_hook(&spec->comps, action);
-}
-
-static void comp_generic_fixup(struct hda_codec *cdc, int action, const char *bus,
-                              const char *hid, const char *match_str, int count)
-{
-       struct alc_spec *spec = cdc->spec;
-       int ret;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               ret = hda_component_manager_init(cdc, &spec->comps, count, bus, hid,
-                                                match_str, &comp_master_ops);
-               if (ret)
-                       return;
-
-               spec->gen.pcm_playback_hook = comp_generic_playback_hook;
-               break;
-       case HDA_FIXUP_ACT_FREE:
-               hda_component_manager_free(&spec->comps, &comp_master_ops);
-               break;
-       }
-}
-
-static void find_cirrus_companion_amps(struct hda_codec *cdc)
-{
-       struct device *dev = hda_codec_dev(cdc);
-       struct acpi_device *adev;
-       struct fwnode_handle *fwnode __free(fwnode_handle) = NULL;
-       const char *bus = NULL;
-       static const struct {
-               const char *hid;
-               const char *name;
-       } acpi_ids[] = {{ "CSC3554", "cs35l54-hda" },
-                       { "CSC3556", "cs35l56-hda" },
-                       { "CSC3557", "cs35l57-hda" }};
-       char *match;
-       int i, count = 0, count_devindex = 0;
-
-       for (i = 0; i < ARRAY_SIZE(acpi_ids); ++i) {
-               adev = acpi_dev_get_first_match_dev(acpi_ids[i].hid, NULL, -1);
-               if (adev)
-                       break;
-       }
-       if (!adev) {
-               codec_dbg(cdc, "Did not find ACPI entry for a Cirrus Amp\n");
-               return;
-       }
-
-       count = i2c_acpi_client_count(adev);
-       if (count > 0) {
-               bus = "i2c";
-       } else {
-               count = acpi_spi_count_resources(adev);
-               if (count > 0)
-                       bus = "spi";
-       }
-
-       fwnode = fwnode_handle_get(acpi_fwnode_handle(adev));
-       acpi_dev_put(adev);
-
-       if (!bus) {
-               codec_err(cdc, "Did not find any buses for %s\n", acpi_ids[i].hid);
-               return;
-       }
-
-       if (!fwnode) {
-               codec_err(cdc, "Could not get fwnode for %s\n", acpi_ids[i].hid);
-               return;
-       }
-
-       /*
-        * When available the cirrus,dev-index property is an accurate
-        * count of the amps in a system and is used in preference to
-        * the count of bus devices that can contain additional address
-        * alias entries.
-        */
-       count_devindex = fwnode_property_count_u32(fwnode, "cirrus,dev-index");
-       if (count_devindex > 0)
-               count = count_devindex;
-
-       match = devm_kasprintf(dev, GFP_KERNEL, "-%%s:00-%s.%%d", acpi_ids[i].name);
-       if (!match)
-               return;
-       codec_info(cdc, "Found %d %s on %s (%s)\n", count, acpi_ids[i].hid, bus, match);
-       comp_generic_fixup(cdc, HDA_FIXUP_ACT_PRE_PROBE, bus, acpi_ids[i].hid, match, count);
-}
-
-static void cs35l41_fixup_i2c_two(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
-}
-
-static void cs35l41_fixup_i2c_four(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(cdc, action, "i2c", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
-}
-
-static void cs35l41_fixup_spi_two(struct hda_codec *codec, const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 2);
-}
-
-static void cs35l41_fixup_spi_one(struct hda_codec *codec, const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 1);
-}
-
-static void cs35l41_fixup_spi_four(struct hda_codec *codec, const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(codec, action, "spi", "CSC3551", "-%s:00-cs35l41-hda.%d", 4);
-}
-
-static void alc287_fixup_legion_16achg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
-                                                int action)
-{
-       comp_generic_fixup(cdc, action, "i2c", "CLSA0100", "-%s:00-cs35l41-hda.%d", 2);
-}
-
-static void alc287_fixup_legion_16ithg6_speakers(struct hda_codec *cdc, const struct hda_fixup *fix,
-                                                int action)
-{
-       comp_generic_fixup(cdc, action, "i2c", "CLSA0101", "-%s:00-cs35l41-hda.%d", 2);
-}
-
-static void alc285_fixup_asus_ga403u(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
-{
-       /*
-        * The same SSID has been re-used in different hardware, they have
-        * different codecs and the newer GA403U has a ALC285.
-        */
-       if (cdc->core.vendor_id != 0x10ec0285)
-               alc_fixup_inv_dmic(cdc, fix, action);
-}
-
-static void tas2781_fixup_tias_i2c(struct hda_codec *cdc,
-       const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
-}
-
-static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2);
-}
-
-static void tas2781_fixup_txnw_i2c(struct hda_codec *cdc,
-       const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(cdc, action, "i2c", "TXNW2781", "-%s:00-tas2781-hda.%d", 1);
-}
-
-static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
-       const struct hda_fixup *fix, int action)
-{
-       comp_generic_fixup(cdc, action, "i2c", "INT8866", "-%s:00", 1);
-}
-
-static void alc256_fixup_acer_sfg16_micmute_led(struct hda_codec *codec,
-       const struct hda_fixup *fix, int action)
-{
-       alc_fixup_hp_gpio_led(codec, action, 0, 0x04);
-}
-
-
-/* for alc295_fixup_hp_top_speakers */
-#include "hp_x360_helper.c"
-
-/* for alc285_fixup_ideapad_s740_coef() */
-#include "ideapad_s740_helper.c"
-
-static const struct coef_fw alc256_fixup_set_coef_defaults_coefs[] = {
-       WRITE_COEF(0x10, 0x0020), WRITE_COEF(0x24, 0x0000),
-       WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x29, 0x3000),
-       WRITE_COEF(0x37, 0xfe05), WRITE_COEF(0x45, 0x5089),
-       {}
-};
-
-static void alc256_fixup_set_coef_defaults(struct hda_codec *codec,
-                                          const struct hda_fixup *fix,
-                                          int action)
-{
-       /*
-        * A certain other OS sets these coeffs to different values. On at least
-        * one TongFang barebone these settings might survive even a cold
-        * reboot. So to restore a clean slate the values are explicitly reset
-        * to default here. Without this, the external microphone is always in a
-        * plugged-in state, while the internal microphone is always in an
-        * unplugged state, breaking the ability to use the internal microphone.
-        */
-       alc_process_coef_fw(codec, alc256_fixup_set_coef_defaults_coefs);
-}
-
-static const struct coef_fw alc233_fixup_no_audio_jack_coefs[] = {
-       WRITE_COEF(0x1a, 0x9003), WRITE_COEF(0x1b, 0x0e2b), WRITE_COEF(0x37, 0xfe06),
-       WRITE_COEF(0x38, 0x4981), WRITE_COEF(0x45, 0xd489), WRITE_COEF(0x46, 0x0074),
-       WRITE_COEF(0x49, 0x0149),
-       {}
-};
-
-static void alc233_fixup_no_audio_jack(struct hda_codec *codec,
-                                      const struct hda_fixup *fix,
-                                      int action)
-{
-       /*
-        * The audio jack input and output is not detected on the ASRock NUC Box
-        * 1100 series when cold booting without this fix. Warm rebooting from a
-        * certain other OS makes the audio functional, as COEF settings are
-        * preserved in this case. This fix sets these altered COEF values as
-        * the default.
-        */
-       alc_process_coef_fw(codec, alc233_fixup_no_audio_jack_coefs);
-}
-
-static void alc256_fixup_mic_no_presence_and_resume(struct hda_codec *codec,
-                                                   const struct hda_fixup *fix,
-                                                   int action)
-{
-       /*
-        * The Clevo NJ51CU comes either with the ALC293 or the ALC256 codec,
-        * but uses the 0x8686 subproduct id in both cases. The ALC256 codec
-        * needs an additional quirk for sound working after suspend and resume.
-        */
-       if (codec->core.vendor_id == 0x10ec0256) {
-               alc_update_coef_idx(codec, 0x10, 1<<9, 0);
-               snd_hda_codec_set_pincfg(codec, 0x19, 0x04a11120);
-       } else {
-               snd_hda_codec_set_pincfg(codec, 0x1a, 0x04a1113c);
-       }
-}
-
-static void alc256_decrease_headphone_amp_val(struct hda_codec *codec,
-                                             const struct hda_fixup *fix, int action)
-{
-       u32 caps;
-       u8 nsteps, offs;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       caps = query_amp_caps(codec, 0x3, HDA_OUTPUT);
-       nsteps = ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) - 10;
-       offs = ((caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT) - 10;
-       caps &= ~AC_AMPCAP_NUM_STEPS & ~AC_AMPCAP_OFFSET;
-       caps |= (nsteps << AC_AMPCAP_NUM_STEPS_SHIFT) | (offs << AC_AMPCAP_OFFSET_SHIFT);
-
-       if (snd_hda_override_amp_caps(codec, 0x3, HDA_OUTPUT, caps))
-               codec_warn(codec, "failed to override amp caps for NID 0x3\n");
-}
-
-static void alc_fixup_dell4_mic_no_presence_quiet(struct hda_codec *codec,
-                                                 const struct hda_fixup *fix,
-                                                 int action)
-{
-       struct alc_spec *spec = codec->spec;
-       struct hda_input_mux *imux = &spec->gen.input_mux;
-       int i;
-
-       alc269_fixup_limit_int_mic_boost(codec, fix, action);
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               /**
-                * Set the vref of pin 0x19 (Headset Mic) and pin 0x1b (Headphone Mic)
-                * to Hi-Z to avoid pop noises at startup and when plugging and
-                * unplugging headphones.
-                */
-               snd_hda_codec_set_pin_target(codec, 0x19, PIN_VREFHIZ);
-               snd_hda_codec_set_pin_target(codec, 0x1b, PIN_VREFHIZ);
-               break;
-       case HDA_FIXUP_ACT_PROBE:
-               /**
-                * Make the internal mic (0x12) the default input source to
-                * prevent pop noises on cold boot.
-                */
-               for (i = 0; i < imux->num_items; i++) {
-                       if (spec->gen.imux_pins[i] == 0x12) {
-                               spec->gen.cur_mux[0] = i;
-                               break;
-                       }
-               }
-               break;
-       }
-}
-
-static void alc287_fixup_yoga9_14iap7_bass_spk_pin(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       /*
-        * The Pin Complex 0x17 for the bass speakers is wrongly reported as
-        * unconnected.
-        */
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x17, 0x90170121 },
-               { }
-       };
-       /*
-        * Avoid DAC 0x06 and 0x08, as they have no volume controls.
-        * DAC 0x02 and 0x03 would be fine.
-        */
-       static const hda_nid_t conn[] = { 0x02, 0x03 };
-       /*
-        * Prefer both speakerbar (0x14) and bass speakers (0x17) connected to DAC 0x02.
-        * Headphones (0x21) are connected to DAC 0x03.
-        */
-       static const hda_nid_t preferred_pairs[] = {
-               0x14, 0x02,
-               0x17, 0x02,
-               0x21, 0x03,
-               0
-       };
-       struct alc_spec *spec = codec->spec;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               spec->gen.preferred_dacs = preferred_pairs;
-               break;
-       }
-}
-
-static void alc295_fixup_dell_inspiron_top_speakers(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x14, 0x90170151 },
-               { 0x17, 0x90170150 },
-               { }
-       };
-       static const hda_nid_t conn[] = { 0x02, 0x03 };
-       static const hda_nid_t preferred_pairs[] = {
-               0x14, 0x02,
-               0x17, 0x03,
-               0x21, 0x02,
-               0
-       };
-       struct alc_spec *spec = codec->spec;
-
-       alc_fixup_no_shutup(codec, fix, action);
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               spec->gen.preferred_dacs = preferred_pairs;
-               break;
-       }
-}
-
-/* Forcibly assign NID 0x03 to HP while NID 0x02 to SPK */
-static void alc287_fixup_bind_dacs(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       static const hda_nid_t conn[] = { 0x02, 0x03 }; /* exclude 0x06 */
-       static const hda_nid_t preferred_pairs[] = {
-               0x17, 0x02, 0x21, 0x03, 0
-       };
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-       spec->gen.preferred_dacs = preferred_pairs;
-       spec->gen.auto_mute_via_amp = 1;
-       if (spec->gen.autocfg.speaker_pins[0] != 0x14) {
-               snd_hda_codec_write_cache(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                                       0x0); /* Make sure 0x14 was disable */
-       }
-}
-/* Fix none verb table of Headset Mic pin */
-static void alc_fixup_headset_mic(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x19, 0x03a1103c },
-               { }
-       };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               alc_update_coef_idx(codec, 0x45, 0xf<<12 | 1<<10, 5<<12);
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-               break;
-       }
-}
-
-static void alc245_fixup_hp_spectre_x360_eu0xxx(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       /*
-        * The Pin Complex 0x14 for the treble speakers is wrongly reported as
-        * unconnected.
-        * The Pin Complex 0x17 for the bass speakers has the lowest association
-        * and sequence values so shift it up a bit to squeeze 0x14 in.
-        */
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x14, 0x90170110 }, // top/treble
-               { 0x17, 0x90170111 }, // bottom/bass
-               { }
-       };
-
-       /*
-        * Force DAC 0x02 for the bass speakers 0x17.
-        */
-       static const hda_nid_t conn[] = { 0x02 };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               break;
-       }
-
-       cs35l41_fixup_i2c_two(codec, fix, action);
-       alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
-       alc245_fixup_hp_gpio_led(codec, fix, action);
-}
-
-/* some changes for Spectre x360 16, 2024 model */
-static void alc245_fixup_hp_spectre_x360_16_aa0xxx(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       /*
-        * The Pin Complex 0x14 for the treble speakers is wrongly reported as
-        * unconnected.
-        * The Pin Complex 0x17 for the bass speakers has the lowest association
-        * and sequence values so shift it up a bit to squeeze 0x14 in.
-        */
-       struct alc_spec *spec = codec->spec;
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x14, 0x90170110 }, // top/treble
-               { 0x17, 0x90170111 }, // bottom/bass
-               { }
-       };
-
-       /*
-        * Force DAC 0x02 for the bass speakers 0x17.
-        */
-       static const hda_nid_t conn[] = { 0x02 };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               /* needed for amp of back speakers */
-               spec->gpio_mask |= 0x01;
-               spec->gpio_dir |= 0x01;
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               /* need to toggle GPIO to enable the amp of back speakers */
-               alc_update_gpio_data(codec, 0x01, true);
-               msleep(100);
-               alc_update_gpio_data(codec, 0x01, false);
-               break;
-       }
-
-       cs35l41_fixup_i2c_two(codec, fix, action);
-       alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
-       alc245_fixup_hp_gpio_led(codec, fix, action);
-}
-
-static void alc245_fixup_hp_zbook_firefly_g12a(struct hda_codec *codec,
-                                         const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       static const hda_nid_t conn[] = { 0x02 };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gen.auto_mute_via_amp = 1;
-               snd_hda_override_conn_list(codec, 0x17, ARRAY_SIZE(conn), conn);
-               break;
-       }
-
-       cs35l41_fixup_i2c_two(codec, fix, action);
-       alc245_fixup_hp_mute_led_coefbit(codec, fix, action);
-       alc285_fixup_hp_coef_micmute_led(codec, fix, action);
-}
-
-/*
- * ALC287 PCM hooks
- */
-static void alc287_alc1318_playback_pcm_hook(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream,
-                                  int action)
-{
-       switch (action) {
-       case HDA_GEN_PCM_ACT_OPEN:
-               alc_write_coefex_idx(codec, 0x5a, 0x00, 0x954f); /* write gpio3 to high */
-               break;
-       case HDA_GEN_PCM_ACT_CLOSE:
-               alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
-               break;
-       }
-}
-
-static void alc287_s4_power_gpio3_default(struct hda_codec *codec)
-{
-       if (is_s4_suspend(codec)) {
-               alc_write_coefex_idx(codec, 0x5a, 0x00, 0x554f); /* write gpio3 as default value */
-       }
-}
-
-static void alc287_fixup_lenovo_thinkpad_with_alc1318(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       static const struct coef_fw coefs[] = {
-               WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC300),
-               WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023),
-               WRITE_COEF(0x24, 0x0013), WRITE_COEF(0x25, 0x0000), WRITE_COEF(0x26, 0xC301),
-               WRITE_COEF(0x28, 0x0001), WRITE_COEF(0x29, 0xb023),
-       };
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-       alc_update_coef_idx(codec, 0x10, 1<<11, 1<<11);
-       alc_process_coef_fw(codec, coefs);
-       spec->power_hook = alc287_s4_power_gpio3_default;
-       spec->gen.pcm_playback_hook = alc287_alc1318_playback_pcm_hook;
-}
-
-/*
- * Clear COEF 0x0d (PCBEEP passthrough) bit 0x40 where BIOS sets it wrongly
- * at PM resume
- */
-static void alc283_fixup_dell_hp_resume(struct hda_codec *codec,
-                                       const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_INIT)
-               alc_write_coef_idx(codec, 0xd, 0x2800);
-}
-
-enum {
-       ALC269_FIXUP_GPIO2,
-       ALC269_FIXUP_SONY_VAIO,
-       ALC275_FIXUP_SONY_VAIO_GPIO2,
-       ALC269_FIXUP_DELL_M101Z,
-       ALC269_FIXUP_SKU_IGNORE,
-       ALC269_FIXUP_ASUS_G73JW,
-       ALC269_FIXUP_ASUS_N7601ZM_PINS,
-       ALC269_FIXUP_ASUS_N7601ZM,
-       ALC269_FIXUP_LENOVO_EAPD,
-       ALC275_FIXUP_SONY_HWEQ,
-       ALC275_FIXUP_SONY_DISABLE_AAMIX,
-       ALC271_FIXUP_DMIC,
-       ALC269_FIXUP_PCM_44K,
-       ALC269_FIXUP_STEREO_DMIC,
-       ALC269_FIXUP_HEADSET_MIC,
-       ALC269_FIXUP_QUANTA_MUTE,
-       ALC269_FIXUP_LIFEBOOK,
-       ALC269_FIXUP_LIFEBOOK_EXTMIC,
-       ALC269_FIXUP_LIFEBOOK_HP_PIN,
-       ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT,
-       ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC,
-       ALC269_FIXUP_AMIC,
-       ALC269_FIXUP_DMIC,
-       ALC269VB_FIXUP_AMIC,
-       ALC269VB_FIXUP_DMIC,
-       ALC269_FIXUP_HP_MUTE_LED,
-       ALC269_FIXUP_HP_MUTE_LED_MIC1,
-       ALC269_FIXUP_HP_MUTE_LED_MIC2,
-       ALC269_FIXUP_HP_MUTE_LED_MIC3,
-       ALC269_FIXUP_HP_GPIO_LED,
-       ALC269_FIXUP_HP_GPIO_MIC1_LED,
-       ALC269_FIXUP_HP_LINE1_MIC1_LED,
-       ALC269_FIXUP_INV_DMIC,
-       ALC269_FIXUP_LENOVO_DOCK,
-       ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST,
-       ALC269_FIXUP_NO_SHUTUP,
-       ALC286_FIXUP_SONY_MIC_NO_PRESENCE,
-       ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT,
-       ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
-       ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
-       ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
-       ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
-       ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
-       ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET,
-       ALC269_FIXUP_HEADSET_MODE,
-       ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
-       ALC269_FIXUP_ASPIRE_HEADSET_MIC,
-       ALC269_FIXUP_ASUS_X101_FUNC,
-       ALC269_FIXUP_ASUS_X101_VERB,
-       ALC269_FIXUP_ASUS_X101,
-       ALC271_FIXUP_AMIC_MIC2,
-       ALC271_FIXUP_HP_GATE_MIC_JACK,
-       ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572,
-       ALC269_FIXUP_ACER_AC700,
-       ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
-       ALC269VB_FIXUP_ASUS_ZENBOOK,
-       ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A,
-       ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE,
-       ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED,
-       ALC269VB_FIXUP_ORDISSIMO_EVE2,
-       ALC283_FIXUP_CHROME_BOOK,
-       ALC283_FIXUP_SENSE_COMBO_JACK,
-       ALC282_FIXUP_ASUS_TX300,
-       ALC283_FIXUP_INT_MIC,
-       ALC290_FIXUP_MONO_SPEAKERS,
-       ALC290_FIXUP_MONO_SPEAKERS_HSJACK,
-       ALC290_FIXUP_SUBWOOFER,
-       ALC290_FIXUP_SUBWOOFER_HSJACK,
-       ALC295_FIXUP_HP_MUTE_LED_COEFBIT11,
-       ALC269_FIXUP_THINKPAD_ACPI,
-       ALC269_FIXUP_LENOVO_XPAD_ACPI,
-       ALC269_FIXUP_DMIC_THINKPAD_ACPI,
-       ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13,
-       ALC269VC_FIXUP_INFINIX_Y4_MAX,
-       ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO,
-       ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
-       ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
-       ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-       ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
-       ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
-       ALC255_FIXUP_HEADSET_MODE,
-       ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC,
-       ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
-       ALC292_FIXUP_TPT440_DOCK,
-       ALC292_FIXUP_TPT440,
-       ALC283_FIXUP_HEADSET_MIC,
-       ALC255_FIXUP_MIC_MUTE_LED,
-       ALC282_FIXUP_ASPIRE_V5_PINS,
-       ALC269VB_FIXUP_ASPIRE_E1_COEF,
-       ALC280_FIXUP_HP_GPIO4,
-       ALC286_FIXUP_HP_GPIO_LED,
-       ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY,
-       ALC280_FIXUP_HP_DOCK_PINS,
-       ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED,
-       ALC280_FIXUP_HP_9480M,
-       ALC245_FIXUP_HP_X360_AMP,
-       ALC285_FIXUP_HP_SPECTRE_X360_EB1,
-       ALC285_FIXUP_HP_SPECTRE_X360_DF1,
-       ALC285_FIXUP_HP_ENVY_X360,
-       ALC288_FIXUP_DELL_HEADSET_MODE,
-       ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
-       ALC288_FIXUP_DELL_XPS_13,
-       ALC288_FIXUP_DISABLE_AAMIX,
-       ALC292_FIXUP_DELL_E7X_AAMIX,
-       ALC292_FIXUP_DELL_E7X,
-       ALC292_FIXUP_DISABLE_AAMIX,
-       ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK,
-       ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE,
-       ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
-       ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
-       ALC275_FIXUP_DELL_XPS,
-       ALC293_FIXUP_LENOVO_SPK_NOISE,
-       ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
-       ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED,
-       ALC255_FIXUP_DELL_SPK_NOISE,
-       ALC225_FIXUP_DISABLE_MIC_VREF,
-       ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
-       ALC295_FIXUP_DISABLE_DAC3,
-       ALC285_FIXUP_SPEAKER2_TO_DAC1,
-       ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1,
-       ALC285_FIXUP_ASUS_HEADSET_MIC,
-       ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS,
-       ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1,
-       ALC285_FIXUP_ASUS_I2C_HEADSET_MIC,
-       ALC280_FIXUP_HP_HEADSET_MIC,
-       ALC221_FIXUP_HP_FRONT_MIC,
-       ALC292_FIXUP_TPT460,
-       ALC298_FIXUP_SPK_VOLUME,
-       ALC298_FIXUP_LENOVO_SPK_VOLUME,
-       ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER,
-       ALC269_FIXUP_ATIV_BOOK_8,
-       ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE,
-       ALC221_FIXUP_HP_MIC_NO_PRESENCE,
-       ALC256_FIXUP_ASUS_HEADSET_MODE,
-       ALC256_FIXUP_ASUS_MIC,
-       ALC256_FIXUP_ASUS_AIO_GPIO2,
-       ALC233_FIXUP_ASUS_MIC_NO_PRESENCE,
-       ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE,
-       ALC233_FIXUP_LENOVO_MULTI_CODECS,
-       ALC233_FIXUP_ACER_HEADSET_MIC,
-       ALC294_FIXUP_LENOVO_MIC_LOCATION,
-       ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE,
-       ALC225_FIXUP_S3_POP_NOISE,
-       ALC700_FIXUP_INTEL_REFERENCE,
-       ALC274_FIXUP_DELL_BIND_DACS,
-       ALC274_FIXUP_DELL_AIO_LINEOUT_VERB,
-       ALC298_FIXUP_TPT470_DOCK_FIX,
-       ALC298_FIXUP_TPT470_DOCK,
-       ALC255_FIXUP_DUMMY_LINEOUT_VERB,
-       ALC255_FIXUP_DELL_HEADSET_MIC,
-       ALC256_FIXUP_HUAWEI_MACH_WX9_PINS,
-       ALC298_FIXUP_HUAWEI_MBX_STEREO,
-       ALC295_FIXUP_HP_X360,
-       ALC221_FIXUP_HP_HEADSET_MIC,
-       ALC285_FIXUP_LENOVO_HEADPHONE_NOISE,
-       ALC295_FIXUP_HP_AUTO_MUTE,
-       ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE,
-       ALC294_FIXUP_ASUS_MIC,
-       ALC294_FIXUP_ASUS_HEADSET_MIC,
-       ALC294_FIXUP_ASUS_SPK,
-       ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
-       ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE,
-       ALC255_FIXUP_ACER_HEADSET_MIC,
-       ALC295_FIXUP_CHROME_BOOK,
-       ALC225_FIXUP_HEADSET_JACK,
-       ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE,
-       ALC225_FIXUP_WYSE_AUTO_MUTE,
-       ALC225_FIXUP_WYSE_DISABLE_MIC_VREF,
-       ALC286_FIXUP_ACER_AIO_HEADSET_MIC,
-       ALC256_FIXUP_ASUS_HEADSET_MIC,
-       ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
-       ALC255_FIXUP_PREDATOR_SUBWOOFER,
-       ALC299_FIXUP_PREDATOR_SPK,
-       ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE,
-       ALC289_FIXUP_DELL_SPK1,
-       ALC289_FIXUP_DELL_SPK2,
-       ALC289_FIXUP_DUAL_SPK,
-       ALC289_FIXUP_RTK_AMP_DUAL_SPK,
-       ALC294_FIXUP_SPK2_TO_DAC1,
-       ALC294_FIXUP_ASUS_DUAL_SPK,
-       ALC285_FIXUP_THINKPAD_X1_GEN7,
-       ALC285_FIXUP_THINKPAD_HEADSET_JACK,
-       ALC294_FIXUP_ASUS_ALLY,
-       ALC294_FIXUP_ASUS_ALLY_PINS,
-       ALC294_FIXUP_ASUS_ALLY_VERBS,
-       ALC294_FIXUP_ASUS_ALLY_SPEAKER,
-       ALC294_FIXUP_ASUS_HPE,
-       ALC294_FIXUP_ASUS_COEF_1B,
-       ALC294_FIXUP_ASUS_GX502_HP,
-       ALC294_FIXUP_ASUS_GX502_PINS,
-       ALC294_FIXUP_ASUS_GX502_VERBS,
-       ALC294_FIXUP_ASUS_GU502_HP,
-       ALC294_FIXUP_ASUS_GU502_PINS,
-       ALC294_FIXUP_ASUS_GU502_VERBS,
-       ALC294_FIXUP_ASUS_G513_PINS,
-       ALC285_FIXUP_ASUS_G533Z_PINS,
-       ALC285_FIXUP_HP_GPIO_LED,
-       ALC285_FIXUP_HP_MUTE_LED,
-       ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED,
-       ALC285_FIXUP_HP_BEEP_MICMUTE_LED,
-       ALC236_FIXUP_HP_MUTE_LED_COEFBIT2,
-       ALC236_FIXUP_HP_GPIO_LED,
-       ALC236_FIXUP_HP_MUTE_LED,
-       ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
-       ALC236_FIXUP_LENOVO_INV_DMIC,
-       ALC298_FIXUP_SAMSUNG_AMP,
-       ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS,
-       ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS,
-       ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
-       ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET,
-       ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
-       ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS,
-       ALC269VC_FIXUP_ACER_HEADSET_MIC,
-       ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE,
-       ALC289_FIXUP_ASUS_GA401,
-       ALC289_FIXUP_ASUS_GA502,
-       ALC256_FIXUP_ACER_MIC_NO_PRESENCE,
-       ALC285_FIXUP_HP_GPIO_AMP_INIT,
-       ALC269_FIXUP_CZC_B20,
-       ALC269_FIXUP_CZC_TMI,
-       ALC269_FIXUP_CZC_L101,
-       ALC269_FIXUP_LEMOTE_A1802,
-       ALC269_FIXUP_LEMOTE_A190X,
-       ALC256_FIXUP_INTEL_NUC8_RUGGED,
-       ALC233_FIXUP_INTEL_NUC8_DMIC,
-       ALC233_FIXUP_INTEL_NUC8_BOOST,
-       ALC256_FIXUP_INTEL_NUC10,
-       ALC255_FIXUP_XIAOMI_HEADSET_MIC,
-       ALC274_FIXUP_HP_MIC,
-       ALC274_FIXUP_HP_HEADSET_MIC,
-       ALC274_FIXUP_HP_ENVY_GPIO,
-       ALC274_FIXUP_ASUS_ZEN_AIO_27,
-       ALC256_FIXUP_ASUS_HPE,
-       ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
-       ALC287_FIXUP_HP_GPIO_LED,
-       ALC256_FIXUP_HP_HEADSET_MIC,
-       ALC245_FIXUP_HP_GPIO_LED,
-       ALC236_FIXUP_DELL_AIO_HEADSET_MIC,
-       ALC282_FIXUP_ACER_DISABLE_LINEOUT,
-       ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST,
-       ALC256_FIXUP_ACER_HEADSET_MIC,
-       ALC285_FIXUP_IDEAPAD_S740_COEF,
-       ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST,
-       ALC295_FIXUP_ASUS_DACS,
-       ALC295_FIXUP_HP_OMEN,
-       ALC285_FIXUP_HP_SPECTRE_X360,
-       ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP,
-       ALC623_FIXUP_LENOVO_THINKSTATION_P340,
-       ALC255_FIXUP_ACER_HEADPHONE_AND_MIC,
-       ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST,
-       ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS,
-       ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
-       ALC287_FIXUP_YOGA7_14ITL_SPEAKERS,
-       ALC298_FIXUP_LENOVO_C940_DUET7,
-       ALC287_FIXUP_13S_GEN2_SPEAKERS,
-       ALC256_FIXUP_SET_COEF_DEFAULTS,
-       ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
-       ALC233_FIXUP_NO_AUDIO_JACK,
-       ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME,
-       ALC285_FIXUP_LEGION_Y9000X_SPEAKERS,
-       ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE,
-       ALC287_FIXUP_LEGION_16ACHG6,
-       ALC287_FIXUP_CS35L41_I2C_2,
-       ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED,
-       ALC287_FIXUP_CS35L41_I2C_4,
-       ALC245_FIXUP_CS35L41_SPI_1,
-       ALC245_FIXUP_CS35L41_SPI_2,
-       ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED,
-       ALC245_FIXUP_CS35L41_SPI_4,
-       ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED,
-       ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED,
-       ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE,
-       ALC287_FIXUP_LEGION_16ITHG6,
-       ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
-       ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN,
-       ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN,
-       ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS,
-       ALC236_FIXUP_DELL_DUAL_CODECS,
-       ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
-       ALC287_FIXUP_TAS2781_I2C,
-       ALC245_FIXUP_TAS2781_SPI_2,
-       ALC287_FIXUP_TXNW2781_I2C,
-       ALC287_FIXUP_YOGA7_14ARB7_I2C,
-       ALC245_FIXUP_HP_MUTE_LED_COEFBIT,
-       ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT,
-       ALC245_FIXUP_HP_X360_MUTE_LEDS,
-       ALC287_FIXUP_THINKPAD_I2S_SPK,
-       ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD,
-       ALC2XX_FIXUP_HEADSET_MIC,
-       ALC289_FIXUP_DELL_CS35L41_SPI_2,
-       ALC294_FIXUP_CS35L41_I2C_2,
-       ALC256_FIXUP_ACER_SFG16_MICMUTE_LED,
-       ALC256_FIXUP_HEADPHONE_AMP_VOL,
-       ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX,
-       ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX,
-       ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A,
-       ALC285_FIXUP_ASUS_GA403U,
-       ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC,
-       ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1,
-       ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC,
-       ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1,
-       ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318,
-       ALC256_FIXUP_CHROME_BOOK,
-       ALC245_FIXUP_CLEVO_NOISY_MIC,
-       ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE,
-       ALC233_FIXUP_MEDION_MTL_SPK,
-       ALC294_FIXUP_BASS_SPEAKER_15,
-       ALC283_FIXUP_DELL_HP_RESUME,
-       ALC294_FIXUP_ASUS_CS35L41_SPI_2,
-       ALC274_FIXUP_HP_AIO_BIND_DACS,
-       ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2,
-       ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC,
-       ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1,
-       ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC,
-};
-
-/* A special fixup for Lenovo C940 and Yoga Duet 7;
- * both have the very same PCI SSID, and we need to apply different fixups
- * depending on the codec ID
- */
-static void alc298_fixup_lenovo_c940_duet7(struct hda_codec *codec,
-                                          const struct hda_fixup *fix,
-                                          int action)
-{
-       int id;
-
-       if (codec->core.vendor_id == 0x10ec0298)
-               id = ALC298_FIXUP_LENOVO_SPK_VOLUME; /* C940 */
-       else
-               id = ALC287_FIXUP_YOGA7_14ITL_SPEAKERS; /* Duet 7 */
-       __snd_hda_apply_fixup(codec, id, action, 0);
-}
-
-static const struct hda_fixup alc269_fixups[] = {
-       [ALC269_FIXUP_GPIO2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_gpio2,
-       },
-       [ALC269_FIXUP_SONY_VAIO] = {
-               .type = HDA_FIXUP_PINCTLS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       {0x19, PIN_VREFGRD},
-                       {}
-               }
-       },
-       [ALC275_FIXUP_SONY_VAIO_GPIO2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc275_fixup_gpio4_off,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_SONY_VAIO
-       },
-       [ALC269_FIXUP_DELL_M101Z] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Enables internal speaker */
-                       {0x20, AC_VERB_SET_COEF_INDEX, 13},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x4040},
-                       {}
-               }
-       },
-       [ALC269_FIXUP_SKU_IGNORE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_sku_ignore,
-       },
-       [ALC269_FIXUP_ASUS_G73JW] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x17, 0x99130111 }, /* subwoofer */
-                       { }
-               }
-       },
-       [ALC269_FIXUP_ASUS_N7601ZM_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03A11050 },
-                       { 0x1a, 0x03A11C30 },
-                       { 0x21, 0x03211420 },
-                       { }
-               }
-       },
-       [ALC269_FIXUP_ASUS_N7601ZM] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x62},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0xa007},
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x10},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x8420},
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x0f},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x7774},
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_ASUS_N7601ZM_PINS,
-       },
-       [ALC269_FIXUP_LENOVO_EAPD] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
-                       {}
-               }
-       },
-       [ALC275_FIXUP_SONY_HWEQ] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_hweq,
-               .chained = true,
-               .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2
-       },
-       [ALC275_FIXUP_SONY_DISABLE_AAMIX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_SONY_VAIO
-       },
-       [ALC271_FIXUP_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc271_fixup_dmic,
-       },
-       [ALC269_FIXUP_PCM_44K] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_pcm_44k,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_QUANTA_MUTE
-       },
-       [ALC269_FIXUP_STEREO_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_stereo_dmic,
-       },
-       [ALC269_FIXUP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_headset_mic,
-       },
-       [ALC269_FIXUP_QUANTA_MUTE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_quanta_mute,
-       },
-       [ALC269_FIXUP_LIFEBOOK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x2101103f }, /* dock line-out */
-                       { 0x1b, 0x23a11040 }, /* dock mic-in */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_QUANTA_MUTE
-       },
-       [ALC269_FIXUP_LIFEBOOK_EXTMIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1903c }, /* headset mic, with jack detect */
-                       { }
-               },
-       },
-       [ALC269_FIXUP_LIFEBOOK_HP_PIN] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x21, 0x0221102f }, /* HP out */
-                       { }
-               },
-       },
-       [ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
-       },
-       [ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_pincfg_U7x7_headset_mic,
-       },
-       [ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x90170151 }, /* use as internal speaker (LFE) */
-                       { 0x1b, 0x90170152 }, /* use as internal speaker (back) */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
-       },
-       [ALC269VC_FIXUP_INFINIX_Y4_MAX] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x90170150 }, /* use as internal speaker */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
-       },
-       [ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x03a19020 }, /* headset mic */
-                       { 0x1b, 0x90170150 }, /* speaker */
-                       { }
-               },
-       },
-       [ALC269_FIXUP_AMIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x0121401f }, /* HP out */
-                       { 0x18, 0x01a19c20 }, /* mic */
-                       { 0x19, 0x99a3092f }, /* int-mic */
-                       { }
-               },
-       },
-       [ALC269_FIXUP_DMIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x99a3092f }, /* int-mic */
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x0121401f }, /* HP out */
-                       { 0x18, 0x01a19c20 }, /* mic */
-                       { }
-               },
-       },
-       [ALC269VB_FIXUP_AMIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x18, 0x01a19c20 }, /* mic */
-                       { 0x19, 0x99a3092f }, /* int-mic */
-                       { 0x21, 0x0121401f }, /* HP out */
-                       { }
-               },
-       },
-       [ALC269VB_FIXUP_DMIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x99a3092f }, /* int-mic */
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x18, 0x01a19c20 }, /* mic */
-                       { 0x21, 0x0121401f }, /* HP out */
-                       { }
-               },
-       },
-       [ALC269_FIXUP_HP_MUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_hp_mute_led,
-       },
-       [ALC269_FIXUP_HP_MUTE_LED_MIC1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_hp_mute_led_mic1,
-       },
-       [ALC269_FIXUP_HP_MUTE_LED_MIC2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_hp_mute_led_mic2,
-       },
-       [ALC269_FIXUP_HP_MUTE_LED_MIC3] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_hp_mute_led_mic3,
-               .chained = true,
-               .chain_id = ALC295_FIXUP_HP_AUTO_MUTE
-       },
-       [ALC269_FIXUP_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_hp_gpio_led,
-       },
-       [ALC269_FIXUP_HP_GPIO_MIC1_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_hp_gpio_mic1_led,
-       },
-       [ALC269_FIXUP_HP_LINE1_MIC1_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_hp_line1_mic1_led,
-       },
-       [ALC269_FIXUP_INV_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic,
-       },
-       [ALC269_FIXUP_NO_SHUTUP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_no_shutup,
-       },
-       [ALC269_FIXUP_LENOVO_DOCK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x23a11040 }, /* dock mic */
-                       { 0x1b, 0x2121103f }, /* dock headphone */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT
-       },
-       [ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_LENOVO_DOCK,
-       },
-       [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_pincfg_no_hp_to_lineout,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
-       },
-       [ALC269_FIXUP_DELL1_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC269_FIXUP_DELL2_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x21014020 }, /* dock line out */
-                       { 0x19, 0x21a19030 }, /* dock mic */
-                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC269_FIXUP_DELL3_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC269_FIXUP_DELL4_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { 0x1b, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC269_FIXUP_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
-       },
-       [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode_no_hp_mic,
-       },
-       [ALC269_FIXUP_ASPIRE_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* headset mic w/o jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE,
-       },
-       [ALC286_FIXUP_SONY_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC256_FIXUP_HUAWEI_MACH_WX9_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       {0x12, 0x90a60130},
-                       {0x13, 0x40000000},
-                       {0x14, 0x90170110},
-                       {0x18, 0x411111f0},
-                       {0x19, 0x04a11040},
-                       {0x1a, 0x411111f0},
-                       {0x1b, 0x90170112},
-                       {0x1d, 0x40759a05},
-                       {0x1e, 0x411111f0},
-                       {0x21, 0x04211020},
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
-       },
-       [ALC298_FIXUP_HUAWEI_MBX_STEREO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc298_fixup_huawei_mbx_stereo,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
-       },
-       [ALC269_FIXUP_ASUS_X101_FUNC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_x101_headset_mic,
-       },
-       [ALC269_FIXUP_ASUS_X101_VERB] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0},
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x08},
-                       {0x20, AC_VERB_SET_PROC_COEF,  0x0310},
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_ASUS_X101_FUNC
-       },
-       [ALC269_FIXUP_ASUS_X101] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x04a1182c }, /* Headset mic */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_ASUS_X101_VERB
-       },
-       [ALC271_FIXUP_AMIC_MIC2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x19, 0x01a19c20 }, /* mic */
-                       { 0x1b, 0x99a7012f }, /* int-mic */
-                       { 0x21, 0x0121401f }, /* HP out */
-                       { }
-               },
-       },
-       [ALC271_FIXUP_HP_GATE_MIC_JACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc271_hp_gate_mic_jack,
-               .chained = true,
-               .chain_id = ALC271_FIXUP_AMIC_MIC2,
-       },
-       [ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC271_FIXUP_HP_GATE_MIC_JACK,
-       },
-       [ALC269_FIXUP_ACER_AC700] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x99a3092f }, /* int-mic */
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x18, 0x03a11c20 }, /* mic */
-                       { 0x1e, 0x0346101e }, /* SPDIF1 */
-                       { 0x21, 0x0321101f }, /* HP out */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC271_FIXUP_DMIC,
-       },
-       [ALC269_FIXUP_LIMIT_INT_MIC_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
-       },
-       [ALC269VB_FIXUP_ASUS_ZENBOOK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC269VB_FIXUP_DMIC,
-       },
-       [ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* class-D output amp +5dB */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x12 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2800 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC269VB_FIXUP_ASUS_ZENBOOK,
-       },
-       [ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a110f0 },  /* use as headset mic */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HP_MUTE_LED_MIC1,
-       },
-       [ALC269VB_FIXUP_ORDISSIMO_EVE2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x99a3092f }, /* int-mic */
-                       { 0x18, 0x03a11d20 }, /* mic */
-                       { 0x19, 0x411111f0 }, /* Unused bogus pin */
-                       { }
-               },
-       },
-       [ALC283_FIXUP_CHROME_BOOK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc283_fixup_chromebook,
-       },
-       [ALC283_FIXUP_SENSE_COMBO_JACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc283_fixup_sense_combo_jack,
-               .chained = true,
-               .chain_id = ALC283_FIXUP_CHROME_BOOK,
-       },
-       [ALC282_FIXUP_ASUS_TX300] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc282_fixup_asus_tx300,
-       },
-       [ALC283_FIXUP_INT_MIC] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x1a},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x0011},
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
-       },
-       [ALC290_FIXUP_SUBWOOFER_HSJACK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x17, 0x90170112 }, /* subwoofer */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK,
-       },
-       [ALC290_FIXUP_SUBWOOFER] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x17, 0x90170112 }, /* subwoofer */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC290_FIXUP_MONO_SPEAKERS,
-       },
-       [ALC290_FIXUP_MONO_SPEAKERS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc290_fixup_mono_speakers,
-       },
-       [ALC290_FIXUP_MONO_SPEAKERS_HSJACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc290_fixup_mono_speakers,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
-       },
-       [ALC269_FIXUP_THINKPAD_ACPI] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_thinkpad_acpi,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_SKU_IGNORE,
-       },
-       [ALC269_FIXUP_LENOVO_XPAD_ACPI] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_ideapad_acpi,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
-       },
-       [ALC269_FIXUP_DMIC_THINKPAD_ACPI] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
-       },
-       [ALC255_FIXUP_ACER_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_HEADSET_MODE
-       },
-       [ALC255_FIXUP_ASUS_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_HEADSET_MODE
-       },
-       [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_HEADSET_MODE
-       },
-       [ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC255_FIXUP_DELL2_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC255_FIXUP_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode_alc255,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
-       },
-       [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode_alc255_no_hp_mic,
-       },
-       [ALC293_FIXUP_DELL1_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
-                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC292_FIXUP_TPT440_DOCK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_tpt440_dock,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
-       },
-       [ALC292_FIXUP_TPT440] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC292_FIXUP_TPT440_DOCK,
-       },
-       [ALC283_FIXUP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x04a110f0 },
-                       { },
-               },
-       },
-       [ALC255_FIXUP_MIC_MUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_micmute_led,
-       },
-       [ALC282_FIXUP_ASPIRE_V5_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x90a60130 },
-                       { 0x14, 0x90170110 },
-                       { 0x17, 0x40000008 },
-                       { 0x18, 0x411111f0 },
-                       { 0x19, 0x01a1913c },
-                       { 0x1a, 0x411111f0 },
-                       { 0x1b, 0x411111f0 },
-                       { 0x1d, 0x40f89b2d },
-                       { 0x1e, 0x411111f0 },
-                       { 0x21, 0x0321101f },
-                       { },
-               },
-       },
-       [ALC269VB_FIXUP_ASPIRE_E1_COEF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269vb_fixup_aspire_e1_coef,
-       },
-       [ALC280_FIXUP_HP_GPIO4] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc280_fixup_hp_gpio4,
-       },
-       [ALC286_FIXUP_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc286_fixup_hp_gpio_led,
-       },
-       [ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc280_fixup_hp_gpio2_mic_hotkey,
-       },
-       [ALC280_FIXUP_HP_DOCK_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x21011020 }, /* line-out */
-                       { 0x1a, 0x01a1903c }, /* headset mic */
-                       { 0x18, 0x2181103f }, /* line-in */
-                       { },
-               },
-               .chained = true,
-               .chain_id = ALC280_FIXUP_HP_GPIO4
-       },
-       [ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x21011020 }, /* line-out */
-                       { 0x18, 0x2181103f }, /* line-in */
-                       { },
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HP_GPIO_MIC1_LED
-       },
-       [ALC280_FIXUP_HP_9480M] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc280_fixup_hp_9480m,
-       },
-       [ALC245_FIXUP_HP_X360_AMP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc245_fixup_hp_x360_amp,
-               .chained = true,
-               .chain_id = ALC245_FIXUP_HP_GPIO_LED
-       },
-       [ALC288_FIXUP_DELL_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode_dell_alc288,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_MIC_MUTE_LED
-       },
-       [ALC288_FIXUP_DELL1_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC288_FIXUP_DELL_HEADSET_MODE
-       },
-       [ALC288_FIXUP_DISABLE_AAMIX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC288_FIXUP_DELL_XPS_13] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_dell_xps13,
-               .chained = true,
-               .chain_id = ALC288_FIXUP_DISABLE_AAMIX
-       },
-       [ALC292_FIXUP_DISABLE_AAMIX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE
-       },
-       [ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC292_FIXUP_DELL_E7X_AAMIX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_dell_xps13,
-               .chained = true,
-               .chain_id = ALC292_FIXUP_DISABLE_AAMIX
-       },
-       [ALC292_FIXUP_DELL_E7X] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_micmute_led,
-               /* micmute fixup must be applied at last */
-               .chained_before = true,
-               .chain_id = ALC292_FIXUP_DELL_E7X_AAMIX,
-       },
-       [ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a1913c }, /* headset mic w/o jack detect */
-                       { }
-               },
-               .chained_before = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE,
-       },
-       [ALC298_FIXUP_DELL1_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC275_FIXUP_DELL_XPS] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Enables internal speaker */
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x1f},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x00c0},
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x30},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x00b1},
-                       {}
-               }
-       },
-       [ALC293_FIXUP_LENOVO_SPK_NOISE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
-       },
-       [ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc233_fixup_lenovo_line2_mic_hotkey,
-       },
-       [ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc233_fixup_lenovo_low_en_micmute_led,
-       },
-       [ALC233_FIXUP_INTEL_NUC8_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic,
-               .chained = true,
-               .chain_id = ALC233_FIXUP_INTEL_NUC8_BOOST,
-       },
-       [ALC233_FIXUP_INTEL_NUC8_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost
-       },
-       [ALC255_FIXUP_DELL_SPK_NOISE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC225_FIXUP_DISABLE_MIC_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_mic_vref,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC225_FIXUP_DELL1_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Disable pass-through path for FRONT 14h */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x36 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x57d7 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC225_FIXUP_DISABLE_MIC_VREF
-       },
-       [ALC280_FIXUP_HP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC,
-       },
-       [ALC221_FIXUP_HP_FRONT_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x02a19020 }, /* Front Mic */
-                       { }
-               },
-       },
-       [ALC292_FIXUP_TPT460] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_tpt440_dock,
-               .chained = true,
-               .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE,
-       },
-       [ALC298_FIXUP_SPK_VOLUME] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc298_fixup_speaker_volume,
-               .chained = true,
-               .chain_id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE,
-       },
-       [ALC298_FIXUP_LENOVO_SPK_VOLUME] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc298_fixup_speaker_volume,
-       },
-       [ALC295_FIXUP_DISABLE_DAC3] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc295_fixup_disable_dac3,
-       },
-       [ALC285_FIXUP_SPEAKER2_TO_DAC1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
-       },
-       [ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-               .chained = true,
-               .chain_id = ALC245_FIXUP_CS35L41_SPI_2
-       },
-       [ALC285_FIXUP_ASUS_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11050 },
-                       { 0x1b, 0x03a11c30 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC285_FIXUP_ASUS_SPEAKER2_TO_DAC1
-       },
-       [ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x90170120 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC285_FIXUP_ASUS_HEADSET_MIC
-       },
-       [ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-               .chained = true,
-               .chain_id = ALC287_FIXUP_CS35L41_I2C_2
-       },
-       [ALC285_FIXUP_ASUS_I2C_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11050 },
-                       { 0x1b, 0x03a11c30 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC285_FIXUP_ASUS_I2C_SPEAKER2_TO_DAC1
-       },
-       [ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x90170151 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC269_FIXUP_ATIV_BOOK_8] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_auto_mute_via_amp,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_NO_SHUTUP
-       },
-       [ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { 0x1a, 0x01813030 }, /* use as headphone mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC221_FIXUP_HP_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC256_FIXUP_ASUS_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode,
-       },
-       [ALC256_FIXUP_ASUS_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x13, 0x90a60160 }, /* use as internal mic */
-                       { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
-       },
-       [ALC256_FIXUP_ASUS_AIO_GPIO2] = {
-               .type = HDA_FIXUP_FUNC,
-               /* Set up GPIO2 for the speaker amp */
-               .v.func = alc_fixup_gpio4,
-       },
-       [ALC233_FIXUP_ASUS_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Enables internal speaker */
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x40},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x8800},
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE
-       },
-       [ALC233_FIXUP_LENOVO_MULTI_CODECS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_GPIO2
-       },
-       [ALC233_FIXUP_ACER_HEADSET_MIC] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE
-       },
-       [ALC294_FIXUP_LENOVO_MIC_LOCATION] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* Change the mic location from front to right, otherwise there are
-                          two front mics with the same name, pulseaudio can't handle them.
-                          This is just a temporary workaround, after applying this fixup,
-                          there will be one "Front Mic" and one "Mic" in this machine.
-                        */
-                       { 0x1a, 0x04a19040 },
-                       { }
-               },
-       },
-       [ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x0101102f }, /* Rear Headset HP */
-                       { 0x19, 0x02a1913c }, /* use as Front headset mic, without its own jack detect */
-                       { 0x1a, 0x01a19030 }, /* Rear Headset MIC */
-                       { 0x1b, 0x02011020 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC225_FIXUP_S3_POP_NOISE
-       },
-       [ALC225_FIXUP_S3_POP_NOISE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc225_fixup_s3_pop_noise,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC700_FIXUP_INTEL_REFERENCE] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Enables internal speaker */
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x45},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x5289},
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x4A},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x001b},
-                       {0x58, AC_VERB_SET_COEF_INDEX, 0x00},
-                       {0x58, AC_VERB_SET_PROC_COEF, 0x3888},
-                       {0x20, AC_VERB_SET_COEF_INDEX, 0x6f},
-                       {0x20, AC_VERB_SET_PROC_COEF, 0x2c0b},
-                       {}
-               }
-       },
-       [ALC274_FIXUP_DELL_BIND_DACS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc274_fixup_bind_dacs,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC274_FIXUP_DELL_AIO_LINEOUT_VERB] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x0401102f },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC274_FIXUP_DELL_BIND_DACS
-       },
-       [ALC298_FIXUP_TPT470_DOCK_FIX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_tpt470_dock,
-               .chained = true,
-               .chain_id = ALC293_FIXUP_LENOVO_SPK_NOISE
-       },
-       [ALC298_FIXUP_TPT470_DOCK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_tpt470_dacs,
-               .chained = true,
-               .chain_id = ALC298_FIXUP_TPT470_DOCK_FIX
-       },
-       [ALC255_FIXUP_DUMMY_LINEOUT_VERB] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x0201101f },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC255_FIXUP_DELL_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC295_FIXUP_HP_X360] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc295_fixup_hp_top_speakers,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HP_MUTE_LED_MIC3
-       },
-       [ALC221_FIXUP_HP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x0181313f},
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC285_FIXUP_LENOVO_HEADPHONE_NOISE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_invalidate_dacs,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
-       },
-       [ALC295_FIXUP_HP_AUTO_MUTE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_auto_mute_via_amp,
-       },
-       [ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC294_FIXUP_ASUS_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x13, 0x90a60160 }, /* use as internal mic */
-                       { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC294_FIXUP_ASUS_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1103c }, /* use as headset mic */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC294_FIXUP_ASUS_SPK] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Set EAPD high */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x40 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x8800 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0f },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x7774 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
-       },
-       [ALC295_FIXUP_CHROME_BOOK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc295_fixup_chromebook,
-               .chained = true,
-               .chain_id = ALC225_FIXUP_HEADSET_JACK
-       },
-       [ALC225_FIXUP_HEADSET_JACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_jack,
-       },
-       [ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Disable PCBEEP-IN passthrough */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x36 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x57d7 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC285_FIXUP_LENOVO_HEADPHONE_NOISE
-       },
-       [ALC255_FIXUP_ACER_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11130 },
-                       { 0x1a, 0x90a60140 }, /* use as internal mic */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x01011020 }, /* Rear Line out */
-                       { 0x19, 0x01a1913c }, /* use as Front headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC225_FIXUP_WYSE_AUTO_MUTE
-       },
-       [ALC225_FIXUP_WYSE_AUTO_MUTE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_auto_mute_via_amp,
-               .chained = true,
-               .chain_id = ALC225_FIXUP_WYSE_DISABLE_MIC_VREF
-       },
-       [ALC225_FIXUP_WYSE_DISABLE_MIC_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_mic_vref,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC286_FIXUP_ACER_AIO_HEADSET_MIC] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x4f },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5029 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE
-       },
-       [ALC256_FIXUP_ASUS_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11020 }, /* headset mic with jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
-       },
-       [ALC256_FIXUP_ASUS_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x04a11120 }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
-       },
-       [ALC255_FIXUP_PREDATOR_SUBWOOFER] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x17, 0x90170151 }, /* use as internal speaker (LFE) */
-                       { 0x1b, 0x90170152 } /* use as internal speaker (back) */
-               }
-       },
-       [ALC299_FIXUP_PREDATOR_SPK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x21, 0x90170150 }, /* use as headset mic, without its own jack detect */
-                       { }
-               }
-       },
-       [ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_i2c_two,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_PREDATOR_SUBWOOFER
-       },
-       [ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x04a11040 },
-                       { 0x21, 0x04211020 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
-       },
-       [ALC289_FIXUP_DELL_SPK1] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x90170140 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE
-       },
-       [ALC289_FIXUP_DELL_SPK2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x17, 0x90170130 }, /* bass spk */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE
-       },
-       [ALC289_FIXUP_DUAL_SPK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-               .chained = true,
-               .chain_id = ALC289_FIXUP_DELL_SPK2
-       },
-       [ALC289_FIXUP_RTK_AMP_DUAL_SPK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-               .chained = true,
-               .chain_id = ALC289_FIXUP_DELL_SPK1
-       },
-       [ALC294_FIXUP_SPK2_TO_DAC1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
-       },
-       [ALC294_FIXUP_ASUS_DUAL_SPK] = {
-               .type = HDA_FIXUP_FUNC,
-               /* The GPIO must be pulled to initialize the AMP */
-               .v.func = alc_fixup_gpio4,
-               .chained = true,
-               .chain_id = ALC294_FIXUP_SPK2_TO_DAC1
-       },
-       [ALC294_FIXUP_ASUS_ALLY] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_i2c_two,
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_ALLY_PINS
-       },
-       [ALC294_FIXUP_ASUS_ALLY_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11050 },
-                       { 0x1a, 0x03a11c30 },
-                       { 0x21, 0x03211420 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_ALLY_VERBS
-       },
-       [ALC294_FIXUP_ASUS_ALLY_VERBS] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x46 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0004 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x47 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xa47a },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0049},
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x201b },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x4278},
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_ALLY_SPEAKER
-       },
-       [ALC294_FIXUP_ASUS_ALLY_SPEAKER] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-       },
-       [ALC285_FIXUP_THINKPAD_X1_GEN7] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_thinkpad_x1_gen7,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
-       },
-       [ALC285_FIXUP_THINKPAD_HEADSET_JACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_jack,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_THINKPAD_X1_GEN7
-       },
-       [ALC294_FIXUP_ASUS_HPE] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Set EAPD high */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0f },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x7774 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
-       },
-       [ALC294_FIXUP_ASUS_GX502_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11050 }, /* front HP mic */
-                       { 0x1a, 0x01a11830 }, /* rear external mic */
-                       { 0x21, 0x03211020 }, /* front HP out */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_GX502_VERBS
-       },
-       [ALC294_FIXUP_ASUS_GX502_VERBS] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* set 0x15 to HP-OUT ctrl */
-                       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-                       /* unmute the 0x15 amp */
-                       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_GX502_HP
-       },
-       [ALC294_FIXUP_ASUS_GX502_HP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc294_fixup_gx502_hp,
-       },
-       [ALC294_FIXUP_ASUS_GU502_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a11050 }, /* rear HP mic */
-                       { 0x1a, 0x01a11830 }, /* rear external mic */
-                       { 0x21, 0x012110f0 }, /* rear HP out */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_GU502_VERBS
-       },
-       [ALC294_FIXUP_ASUS_GU502_VERBS] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* set 0x15 to HP-OUT ctrl */
-                       { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 },
-                       /* unmute the 0x15 amp */
-                       { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000 },
-                       /* set 0x1b to HP-OUT */
-                       { 0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_GU502_HP
-       },
-       [ALC294_FIXUP_ASUS_GU502_HP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc294_fixup_gu502_hp,
-       },
-        [ALC294_FIXUP_ASUS_G513_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                               { 0x19, 0x03a11050 }, /* front HP mic */
-                               { 0x1a, 0x03a11c30 }, /* rear external mic */
-                               { 0x21, 0x03211420 }, /* front HP out */
-                               { }
-               },
-       },
-       [ALC285_FIXUP_ASUS_G533Z_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x90170152 }, /* Speaker Surround Playback Switch */
-                       { 0x19, 0x03a19020 }, /* Mic Boost Volume */
-                       { 0x1a, 0x03a11c30 }, /* Mic Boost Volume */
-                       { 0x1e, 0x90170151 }, /* Rear jack, IN OUT EAPD Detect */
-                       { 0x21, 0x03211420 },
-                       { }
-               },
-       },
-       [ALC294_FIXUP_ASUS_COEF_1B] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Set bit 10 to correct noisy output after reboot from
-                        * Windows 10 (due to pop noise reduction?)
-                        */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x1b },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x4e4b },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC289_FIXUP_ASUS_GA401,
-       },
-       [ALC285_FIXUP_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_gpio_led,
-       },
-       [ALC285_FIXUP_HP_MUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_mute_led,
-       },
-       [ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_spectre_x360_mute_led,
-       },
-       [ALC285_FIXUP_HP_BEEP_MICMUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_beep,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_MUTE_LED,
-       },
-       [ALC236_FIXUP_HP_MUTE_LED_COEFBIT2] = {
-           .type = HDA_FIXUP_FUNC,
-           .v.func = alc236_fixup_hp_mute_led_coefbit2,
-       },
-       [ALC236_FIXUP_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc236_fixup_hp_gpio_led,
-       },
-       [ALC236_FIXUP_HP_MUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc236_fixup_hp_mute_led,
-       },
-       [ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc236_fixup_hp_mute_led_micmute_vref,
-       },
-       [ALC236_FIXUP_LENOVO_INV_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic,
-               .chained = true,
-               .chain_id = ALC283_FIXUP_INT_MIC,
-       },
-       [ALC295_FIXUP_HP_MUTE_LED_COEFBIT11] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc295_fixup_hp_mute_led_coefbit11,
-       },
-       [ALC298_FIXUP_SAMSUNG_AMP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc298_fixup_samsung_amp,
-               .chained = true,
-               .chain_id = ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET
-       },
-       [ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc298_fixup_samsung_amp_v2_2_amps
-       },
-       [ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc298_fixup_samsung_amp_v2_4_amps
-       },
-       [ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc5 },
-                       { }
-               },
-       },
-       [ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x08},
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2fcf},
-                       { }
-               },
-       },
-       [ALC295_FIXUP_ASUS_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x90100120 }, /* use as internal speaker */
-                       { 0x18, 0x02a111f0 }, /* use as headset mic, without its own jack detect */
-                       { 0x1a, 0x01011020 }, /* use as line out */
-                       { },
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC269VC_FIXUP_ACER_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x02a11030 }, /* use as headset mic */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x18, 0x01a11130 }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MIC
-       },
-       [ALC289_FIXUP_ASUS_GA401] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc289_fixup_asus_ga401,
-               .chained = true,
-               .chain_id = ALC289_FIXUP_ASUS_GA502,
-       },
-       [ALC289_FIXUP_ASUS_GA502] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11020 }, /* headset mic with jack detect */
-                       { }
-               },
-       },
-       [ALC256_FIXUP_ACER_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x02a11120 }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC256_FIXUP_ASUS_HEADSET_MODE
-       },
-       [ALC285_FIXUP_HP_GPIO_AMP_INIT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_gpio_amp_init,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_GPIO_LED
-       },
-       [ALC269_FIXUP_CZC_B20] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x411111f0 },
-                       { 0x14, 0x90170110 }, /* speaker */
-                       { 0x15, 0x032f1020 }, /* HP out */
-                       { 0x17, 0x411111f0 },
-                       { 0x18, 0x03ab1040 }, /* mic */
-                       { 0x19, 0xb7a7013f },
-                       { 0x1a, 0x0181305f },
-                       { 0x1b, 0x411111f0 },
-                       { 0x1d, 0x411111f0 },
-                       { 0x1e, 0x411111f0 },
-                       { }
-               },
-               .chain_id = ALC269_FIXUP_DMIC,
-       },
-       [ALC269_FIXUP_CZC_TMI] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x4000c000 },
-                       { 0x14, 0x90170110 }, /* speaker */
-                       { 0x15, 0x0421401f }, /* HP out */
-                       { 0x17, 0x411111f0 },
-                       { 0x18, 0x04a19020 }, /* mic */
-                       { 0x19, 0x411111f0 },
-                       { 0x1a, 0x411111f0 },
-                       { 0x1b, 0x411111f0 },
-                       { 0x1d, 0x40448505 },
-                       { 0x1e, 0x411111f0 },
-                       { 0x20, 0x8000ffff },
-                       { }
-               },
-               .chain_id = ALC269_FIXUP_DMIC,
-       },
-       [ALC269_FIXUP_CZC_L101] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x40000000 },
-                       { 0x14, 0x01014010 }, /* speaker */
-                       { 0x15, 0x411111f0 }, /* HP out */
-                       { 0x16, 0x411111f0 },
-                       { 0x18, 0x01a19020 }, /* mic */
-                       { 0x19, 0x02a19021 },
-                       { 0x1a, 0x0181302f },
-                       { 0x1b, 0x0221401f },
-                       { 0x1c, 0x411111f0 },
-                       { 0x1d, 0x4044c601 },
-                       { 0x1e, 0x411111f0 },
-                       { }
-               },
-               .chain_id = ALC269_FIXUP_DMIC,
-       },
-       [ALC269_FIXUP_LEMOTE_A1802] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0x40000000 },
-                       { 0x14, 0x90170110 }, /* speaker */
-                       { 0x17, 0x411111f0 },
-                       { 0x18, 0x03a19040 }, /* mic1 */
-                       { 0x19, 0x90a70130 }, /* mic2 */
-                       { 0x1a, 0x411111f0 },
-                       { 0x1b, 0x411111f0 },
-                       { 0x1d, 0x40489d2d },
-                       { 0x1e, 0x411111f0 },
-                       { 0x20, 0x0003ffff },
-                       { 0x21, 0x03214020 },
-                       { }
-               },
-               .chain_id = ALC269_FIXUP_DMIC,
-       },
-       [ALC269_FIXUP_LEMOTE_A190X] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x0121401f }, /* HP out */
-                       { 0x18, 0x01a19c20 }, /* rear  mic */
-                       { 0x19, 0x99a3092f }, /* front mic */
-                       { 0x1b, 0x0201401f }, /* front lineout */
-                       { }
-               },
-               .chain_id = ALC269_FIXUP_DMIC,
-       },
-       [ALC256_FIXUP_INTEL_NUC8_RUGGED] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC256_FIXUP_INTEL_NUC10] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC255_FIXUP_XIAOMI_HEADSET_MIC] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC289_FIXUP_ASUS_GA502
-       },
-       [ALC274_FIXUP_HP_MIC] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x45 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5089 },
-                       { }
-               },
-       },
-       [ALC274_FIXUP_HP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc274_fixup_hp_headset_mic,
-               .chained = true,
-               .chain_id = ALC274_FIXUP_HP_MIC
-       },
-       [ALC274_FIXUP_HP_ENVY_GPIO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc274_fixup_hp_envy_gpio,
-       },
-       [ALC274_FIXUP_ASUS_ZEN_AIO_27] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x10 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xc420 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x40 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x8800 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x49 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0249 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x4a },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x202b },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x62 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xa007 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x6b },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x5060 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC2XX_FIXUP_HEADSET_MIC,
-       },
-       [ALC256_FIXUP_ASUS_HPE] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* Set EAPD high */
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x0f },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x7778 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC
-       },
-       [ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_jack,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
-       },
-       [ALC287_FIXUP_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_hp_gpio_led,
-       },
-       [ALC256_FIXUP_HP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc274_fixup_hp_headset_mic,
-       },
-       [ALC236_FIXUP_DELL_AIO_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_no_int_mic,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE
-       },
-       [ALC282_FIXUP_ACER_DISABLE_LINEOUT] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x411111f0 },
-                       { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { },
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE
-       },
-       [ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
-       },
-       [ALC256_FIXUP_ACER_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x02a1113c }, /* use as headset mic, without its own jack detect */
-                       { 0x1a, 0x90a1092f }, /* use as internal mic */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC285_FIXUP_IDEAPAD_S740_COEF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_ideapad_s740_coef,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
-       },
-       [ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_MUTE_LED,
-       },
-       [ALC295_FIXUP_ASUS_DACS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc295_fixup_asus_dacs,
-       },
-       [ALC295_FIXUP_HP_OMEN] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x12, 0xb7a60130 },
-                       { 0x13, 0x40000000 },
-                       { 0x14, 0x411111f0 },
-                       { 0x16, 0x411111f0 },
-                       { 0x17, 0x90170110 },
-                       { 0x18, 0x411111f0 },
-                       { 0x19, 0x02a11030 },
-                       { 0x1a, 0x411111f0 },
-                       { 0x1b, 0x04a19030 },
-                       { 0x1d, 0x40600001 },
-                       { 0x1e, 0x411111f0 },
-                       { 0x21, 0x03211020 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HP_LINE1_MIC1_LED,
-       },
-       [ALC285_FIXUP_HP_SPECTRE_X360] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_spectre_x360,
-       },
-       [ALC285_FIXUP_HP_SPECTRE_X360_EB1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_spectre_x360_eb1
-       },
-       [ALC285_FIXUP_HP_SPECTRE_X360_DF1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_spectre_x360_df1
-       },
-       [ALC285_FIXUP_HP_ENVY_X360] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_hp_envy_x360,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_GPIO_AMP_INIT,
-       },
-       [ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_ideapad_s740_coef,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
-       },
-       [ALC623_FIXUP_LENOVO_THINKSTATION_P340] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_no_shutup,
-               .chained = true,
-               .chain_id = ALC283_FIXUP_HEADSET_MIC,
-       },
-       [ALC255_FIXUP_ACER_HEADPHONE_AND_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x21, 0x03211030 }, /* Change the Headphone location to Left */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC255_FIXUP_XIAOMI_HEADSET_MIC
-       },
-       [ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF,
-       },
-       [ALC285_FIXUP_LEGION_Y9000X_SPEAKERS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_ideapad_s740_coef,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE,
-       },
-       [ALC285_FIXUP_LEGION_Y9000X_AUTOMUTE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_legion_15imhg05_speakers,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI,
-       },
-       [ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS] = {
-               .type = HDA_FIXUP_VERBS,
-               //.v.verbs = legion_15imhg05_coefs,
-               .v.verbs = (const struct hda_verb[]) {
-                        // set left speaker Legion 7i.
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
-
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x1a },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                        // set right speaker Legion 7i.
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x42 },
-
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2a },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-                        {}
-               },
-               .chained = true,
-               .chain_id = ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE,
-       },
-       [ALC287_FIXUP_LEGION_15IMHG05_AUTOMUTE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_legion_15imhg05_speakers,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE,
-       },
-       [ALC287_FIXUP_YOGA7_14ITL_SPEAKERS] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                        // set left speaker Yoga 7i.
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
-
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x1a },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                        // set right speaker Yoga 7i.
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x46 },
-
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2a },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-                        {}
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE,
-       },
-       [ALC298_FIXUP_LENOVO_C940_DUET7] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc298_fixup_lenovo_c940_duet7,
-       },
-       [ALC287_FIXUP_13S_GEN2_SPEAKERS] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x42 },
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE,
-       },
-       [ALC256_FIXUP_SET_COEF_DEFAULTS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc256_fixup_set_coef_defaults,
-       },
-       [ALC245_FIXUP_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc245_fixup_hp_gpio_led,
-       },
-       [ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11120 }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC,
-       },
-       [ALC233_FIXUP_NO_AUDIO_JACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc233_fixup_no_audio_jack,
-       },
-       [ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc256_fixup_mic_no_presence_and_resume,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC287_FIXUP_LEGION_16ACHG6] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_legion_16achg6_speakers,
-       },
-       [ALC287_FIXUP_CS35L41_I2C_2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_i2c_two,
-       },
-       [ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_i2c_two,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_MUTE_LED,
-       },
-       [ALC287_FIXUP_CS35L41_I2C_4] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_i2c_four,
-       },
-       [ALC245_FIXUP_CS35L41_SPI_2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_spi_two,
-       },
-       [ALC245_FIXUP_CS35L41_SPI_1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_spi_one,
-       },
-       [ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_spi_two,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_GPIO_LED,
-       },
-       [ALC245_FIXUP_CS35L41_SPI_4] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_spi_four,
-       },
-       [ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_spi_four,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_GPIO_LED,
-       },
-       [ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                        { 0x20, AC_VERB_SET_COEF_INDEX, 0x19 },
-                        { 0x20, AC_VERB_SET_PROC_COEF, 0x8e11 },
-                        { }
-               },
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_MUTE_LED,
-       },
-       [ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_dell4_mic_no_presence_quiet,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
-       },
-       [ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x02a1112c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC
-       },
-       [ALC287_FIXUP_LEGION_16ITHG6] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_legion_16ithg6_speakers,
-       },
-       [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       // enable left speaker
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x41 },
-
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x1a },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xf },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x42 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x10 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x40 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                       // enable right speaker
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x24 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x46 },
-
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xc },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2a },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xf },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x46 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x10 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x44 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x26 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0xb020 },
-
-                       { },
-               },
-       },
-       [ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin,
-               .chained = true,
-               .chain_id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK,
-       },
-       [ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_yoga9_14iap7_bass_spk_pin,
-               .chained = true,
-               .chain_id = ALC287_FIXUP_CS35L41_I2C_2,
-       },
-       [ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc295_fixup_dell_inspiron_top_speakers,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
-       },
-       [ALC236_FIXUP_DELL_DUAL_CODECS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.func = alc1220_fixup_gb_dual_codecs,
-               .chained = true,
-               .chain_id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-       },
-       [ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_i2c_two,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
-       },
-       [ALC287_FIXUP_TAS2781_I2C] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = tas2781_fixup_tias_i2c,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
-       },
-       [ALC245_FIXUP_TAS2781_SPI_2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = tas2781_fixup_spi,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_HP_GPIO_LED,
-       },
-       [ALC287_FIXUP_TXNW2781_I2C] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = tas2781_fixup_txnw_i2c,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
-       },
-       [ALC287_FIXUP_YOGA7_14ARB7_I2C] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = yoga7_14arb7_fixup_i2c,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
-       },
-       [ALC245_FIXUP_HP_MUTE_LED_COEFBIT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc245_fixup_hp_mute_led_coefbit,
-       },
-       [ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc245_fixup_hp_mute_led_v1_coefbit,
-       },
-       [ALC245_FIXUP_HP_X360_MUTE_LEDS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc245_fixup_hp_mute_led_coefbit,
-               .chained = true,
-               .chain_id = ALC245_FIXUP_HP_GPIO_LED
-       },
-       [ALC287_FIXUP_THINKPAD_I2S_SPK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_bind_dacs,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
-       },
-       [ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_bind_dacs,
-               .chained = true,
-               .chain_id = ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
-       },
-       [ALC2XX_FIXUP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mic,
-       },
-       [ALC289_FIXUP_DELL_CS35L41_SPI_2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_spi_two,
-               .chained = true,
-               .chain_id = ALC289_FIXUP_DUAL_SPK
-       },
-       [ALC294_FIXUP_CS35L41_I2C_2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_i2c_two,
-       },
-       [ALC256_FIXUP_ACER_SFG16_MICMUTE_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc256_fixup_acer_sfg16_micmute_led,
-       },
-       [ALC256_FIXUP_HEADPHONE_AMP_VOL] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc256_decrease_headphone_amp_val,
-       },
-       [ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc245_fixup_hp_spectre_x360_eu0xxx,
-       },
-       [ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc245_fixup_hp_spectre_x360_16_aa0xxx,
-       },
-       [ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc245_fixup_hp_zbook_firefly_g12a,
-       },
-       [ALC285_FIXUP_ASUS_GA403U] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_asus_ga403u,
-       },
-       [ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11050 },
-                       { 0x1b, 0x03a11c30 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1
-       },
-       [ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC,
-       },
-       [ALC285_FIXUP_ASUS_GU605_SPI_2_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11050 },
-                       { 0x1b, 0x03a11c30 },
-                       { }
-               },
-       },
-       [ALC285_FIXUP_ASUS_GA403U_I2C_SPEAKER2_TO_DAC1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-               .chained = true,
-               .chain_id = ALC285_FIXUP_ASUS_GA403U,
-       },
-       [ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc287_fixup_lenovo_thinkpad_with_alc1318,
-               .chained = true,
-               .chain_id = ALC269_FIXUP_THINKPAD_ACPI
-       },
-       [ALC256_FIXUP_CHROME_BOOK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc256_fixup_chromebook,
-               .chained = true,
-               .chain_id = ALC225_FIXUP_HEADSET_JACK
-       },
-       [ALC245_FIXUP_CLEVO_NOISY_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE,
-       },
-       [ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-                       { 0x1b, 0x20a11040 }, /* dock mic */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST
-       },
-       [ALC233_FIXUP_MEDION_MTL_SPK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x90170110 },
-                       { }
-               },
-       },
-       [ALC294_FIXUP_BASS_SPEAKER_15] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc294_fixup_bass_speaker_15,
-       },
-       [ALC283_FIXUP_DELL_HP_RESUME] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc283_fixup_dell_hp_resume,
-       },
-       [ALC294_FIXUP_ASUS_CS35L41_SPI_2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = cs35l41_fixup_spi_two,
-               .chained = true,
-               .chain_id = ALC294_FIXUP_ASUS_HEADSET_MIC,
-       },
-       [ALC274_FIXUP_HP_AIO_BIND_DACS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc274_fixup_hp_aio_bind_dacs,
-       },
-       [ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11050 },
-                       { 0x1b, 0x03a11c30 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1
-       },
-       [ALC285_FIXUP_ASUS_GA605K_I2C_SPEAKER2_TO_DAC1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc285_fixup_speaker2_to_dac1,
-       },
-       [ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_limit_int_mic_boost,
-               .chained = true,
-               .chain_id = ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE,
-       },
-};
-
-static const struct hda_quirk alc269_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700),
-       SND_PCI_QUIRK(0x1025, 0x072d, "Acer Aspire V5-571G", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK),
-       SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK),
-       SND_PCI_QUIRK(0x1025, 0x0762, "Acer Aspire E1-472", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
-       SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572),
-       SND_PCI_QUIRK(0x1025, 0x079b, "Acer Aspire V5-573G", ALC282_FIXUP_ASPIRE_V5_PINS),
-       SND_PCI_QUIRK(0x1025, 0x080d, "Acer Aspire V5-122P", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x0840, "Acer Aspire E1", ALC269VB_FIXUP_ASPIRE_E1_COEF),
-       SND_PCI_QUIRK(0x1025, 0x100c, "Acer Aspire E5-574G", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x1025, 0x101c, "Acer Veriton N2510G", ALC269_FIXUP_LIFEBOOK),
-       SND_PCI_QUIRK(0x1025, 0x102b, "Acer Aspire C24-860", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x1065, "Acer Aspire C20-820", ALC269VC_FIXUP_ACER_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x106d, "Acer Cloudbook 14", ALC283_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0x1025, 0x1094, "Acer Aspire E5-575T", ALC255_FIXUP_ACER_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x1025, 0x1099, "Acer Aspire E5-523G", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x110e, "Acer Aspire ES1-432", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x1166, "Acer Veriton N4640G", ALC269_FIXUP_LIFEBOOK),
-       SND_PCI_QUIRK(0x1025, 0x1167, "Acer Veriton N6640G", ALC269_FIXUP_LIFEBOOK),
-       SND_PCI_QUIRK(0x1025, 0x1177, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER),
-       SND_PCI_QUIRK(0x1025, 0x1178, "Acer Predator G9-593", ALC255_FIXUP_PREDATOR_SUBWOOFER),
-       SND_PCI_QUIRK(0x1025, 0x1246, "Acer Predator Helios 500", ALC299_FIXUP_PREDATOR_SPK),
-       SND_PCI_QUIRK(0x1025, 0x1247, "Acer vCopperbox", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
-       SND_PCI_QUIRK(0x1025, 0x1248, "Acer Veriton N4660G", ALC269VC_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x1269, "Acer SWIFT SF314-54", ALC256_FIXUP_ACER_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x126a, "Acer Swift SF114-32", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x128f, "Acer Veriton Z6860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x1290, "Acer Veriton Z4860G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x1291, "Acer Veriton Z4660G", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x129c, "Acer SWIFT SF314-55", ALC256_FIXUP_ACER_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x129d, "Acer SWIFT SF313-51", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x1300, "Acer SWIFT SF314-56", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x1308, "Acer Aspire Z24-890", ALC286_FIXUP_ACER_AIO_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x132a, "Acer TravelMate B114-21", ALC233_FIXUP_ACER_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x1330, "Acer TravelMate X514-51T", ALC255_FIXUP_ACER_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x1360, "Acer Aspire A115", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x141f, "Acer Spin SP513-54N", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x142b, "Acer Swift SF314-42", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x1430, "Acer TravelMate B311R-31", ALC256_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x1466, "Acer Aspire A515-56", ALC255_FIXUP_ACER_HEADPHONE_AND_MIC),
-       SND_PCI_QUIRK(0x1025, 0x1534, "Acer Predator PH315-54", ALC255_FIXUP_ACER_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1025, 0x159c, "Acer Nitro 5 AN515-58", ALC2XX_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1025, 0x169a, "Acer Swift SFG16", ALC256_FIXUP_ACER_SFG16_MICMUTE_LED),
-       SND_PCI_QUIRK(0x1025, 0x1826, "Acer Helios ZPC", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1025, 0x182c, "Acer Helios ZPD", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1025, 0x1844, "Acer Helios ZPS", ALC287_FIXUP_PREDATOR_SPK_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z),
-       SND_PCI_QUIRK(0x1028, 0x053c, "Dell Latitude E5430", ALC292_FIXUP_DELL_E7X),
-       SND_PCI_QUIRK(0x1028, 0x054b, "Dell XPS one 2710", ALC275_FIXUP_DELL_XPS),
-       SND_PCI_QUIRK(0x1028, 0x05bd, "Dell Latitude E6440", ALC292_FIXUP_DELL_E7X),
-       SND_PCI_QUIRK(0x1028, 0x05be, "Dell Latitude E6540", ALC292_FIXUP_DELL_E7X),
-       SND_PCI_QUIRK(0x1028, 0x05ca, "Dell Latitude E7240", ALC292_FIXUP_DELL_E7X),
-       SND_PCI_QUIRK(0x1028, 0x05cb, "Dell Latitude E7440", ALC292_FIXUP_DELL_E7X),
-       SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER),
-       SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0604, "Dell Venue 11 Pro 7130", ALC283_FIXUP_DELL_HP_RESUME),
-       SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
-       SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK),
-       SND_PCI_QUIRK(0x1028, 0x062c, "Dell Latitude E5550", ALC292_FIXUP_DELL_E7X),
-       SND_PCI_QUIRK(0x1028, 0x062e, "Dell Latitude E7450", ALC292_FIXUP_DELL_E7X),
-       SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
-       SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0665, "Dell XPS 13", ALC288_FIXUP_DELL_XPS_13),
-       SND_PCI_QUIRK(0x1028, 0x0669, "Dell Optiplex 9020m", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x069a, "Dell Vostro 5480", ALC290_FIXUP_SUBWOOFER_HSJACK),
-       SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
-       SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
-       SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
-       SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
-       SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK),
-       SND_PCI_QUIRK(0x1028, 0x0706, "Dell Inspiron 7559", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
-       SND_PCI_QUIRK(0x1028, 0x0725, "Dell Inspiron 3162", ALC255_FIXUP_DELL_SPK_NOISE),
-       SND_PCI_QUIRK(0x1028, 0x0738, "Dell Precision 5820", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1028, 0x075c, "Dell XPS 27 7760", ALC298_FIXUP_SPK_VOLUME),
-       SND_PCI_QUIRK(0x1028, 0x075d, "Dell AIO", ALC298_FIXUP_SPK_VOLUME),
-       SND_PCI_QUIRK(0x1028, 0x0798, "Dell Inspiron 17 7000 Gaming", ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER),
-       SND_PCI_QUIRK(0x1028, 0x07b0, "Dell Precision 7520", ALC295_FIXUP_DISABLE_DAC3),
-       SND_PCI_QUIRK(0x1028, 0x080c, "Dell WYSE", ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x084b, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
-       SND_PCI_QUIRK(0x1028, 0x084e, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
-       SND_PCI_QUIRK(0x1028, 0x0871, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0872, "Dell Precision 3630", ALC255_FIXUP_DELL_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0873, "Dell Precision 3930", ALC255_FIXUP_DUMMY_LINEOUT_VERB),
-       SND_PCI_QUIRK(0x1028, 0x0879, "Dell Latitude 5420 Rugged", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x08ad, "Dell WYSE AIO", ALC225_FIXUP_DELL_WYSE_AIO_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x08ae, "Dell WYSE NB", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0935, "Dell", ALC274_FIXUP_DELL_AIO_LINEOUT_VERB),
-       SND_PCI_QUIRK(0x1028, 0x097d, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x097e, "Dell Precision", ALC289_FIXUP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x098d, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x09bf, "Dell Precision", ALC233_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0a2e, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0a30, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0a38, "Dell Latitude 7520", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET),
-       SND_PCI_QUIRK(0x1028, 0x0a58, "Dell", ALC255_FIXUP_DELL_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1028, 0x0a61, "Dell XPS 15 9510", ALC289_FIXUP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x0a62, "Dell Precision 5560", ALC289_FIXUP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x0a9d, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0a9e, "Dell Latitude 5430", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0b19, "Dell XPS 15 9520", ALC289_FIXUP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x0b1a, "Dell Precision 5570", ALC289_FIXUP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x0b27, "Dell", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0b28, "Dell", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0b37, "Dell Inspiron 16 Plus 7620 2-in-1", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
-       SND_PCI_QUIRK(0x1028, 0x0b71, "Dell Inspiron 16 Plus 7620", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
-       SND_PCI_QUIRK(0x1028, 0x0beb, "Dell XPS 15 9530 (2023)", ALC289_FIXUP_DELL_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0c03, "Dell Precision 5340", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0c0b, "Dell Oasis 14 RPL-P", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x0c0d, "Dell Oasis", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x0c0e, "Dell Oasis 16", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x0c19, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
-       SND_PCI_QUIRK(0x1028, 0x0c1a, "Dell Precision 3340", ALC236_FIXUP_DELL_DUAL_CODECS),
-       SND_PCI_QUIRK(0x1028, 0x0c1b, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
-       SND_PCI_QUIRK(0x1028, 0x0c1c, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
-       SND_PCI_QUIRK(0x1028, 0x0c1d, "Dell Precision 3440", ALC236_FIXUP_DELL_DUAL_CODECS),
-       SND_PCI_QUIRK(0x1028, 0x0c1e, "Dell Precision 3540", ALC236_FIXUP_DELL_DUAL_CODECS),
-       SND_PCI_QUIRK(0x1028, 0x0c28, "Dell Inspiron 16 Plus 7630", ALC295_FIXUP_DELL_INSPIRON_TOP_SPEAKERS),
-       SND_PCI_QUIRK(0x1028, 0x0c4d, "Dell", ALC287_FIXUP_CS35L41_I2C_4),
-       SND_PCI_QUIRK(0x1028, 0x0c94, "Dell Polaris 3 metal", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1028, 0x0c96, "Dell Polaris 2in1", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1028, 0x0cbd, "Dell Oasis 13 CS MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0cbe, "Dell Oasis 13 2-IN-1 MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0cbf, "Dell Oasis 13 Low Weight MTU-L", ALC289_FIXUP_DELL_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0cc0, "Dell Oasis 13", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x0cc1, "Dell Oasis 14 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0cc2, "Dell Oasis 14 2-in-1 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0cc3, "Dell Oasis 14 Low Weight MTL-U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0cc4, "Dell Oasis 16 MTL-H/U", ALC289_FIXUP_DELL_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1028, 0x0cc5, "Dell Oasis 14", ALC289_FIXUP_RTK_AMP_DUAL_SPK),
-       SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
-       SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x21f9, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x221b, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x103c, 0x2221, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2225, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2236, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2237, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2238, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2239, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x224b, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2253, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2254, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2255, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2256, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2257, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2259, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x225a, "HP", ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x225f, "HP", ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY),
-       SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2272, "HP", ALC280_FIXUP_HP_DOCK_PINS),
-       SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2273, "HP", ALC280_FIXUP_HP_DOCK_PINS),
-       SND_PCI_QUIRK(0x103c, 0x2278, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x22db, "HP", ALC280_FIXUP_HP_9480M),
-       SND_PCI_QUIRK(0x103c, 0x22dc, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x22fb, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
-       SND_PCI_QUIRK(0x103c, 0x2b5e, "HP 288 Pro G2 MT", ALC221_FIXUP_HP_288PRO_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x802e, "HP Z240 SFF", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x802f, "HP Z240", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x8077, "HP", ALC256_FIXUP_HP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x103c, 0x8158, "HP", ALC256_FIXUP_HP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x103c, 0x820d, "HP Pavilion 15", ALC295_FIXUP_HP_X360),
-       SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC),
-       SND_PCI_QUIRK(0x103c, 0x827e, "HP x360", ALC295_FIXUP_HP_X360),
-       SND_PCI_QUIRK(0x103c, 0x827f, "HP x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
-       SND_PCI_QUIRK(0x103c, 0x82bf, "HP G3 mini", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x82c0, "HP G3 mini premium", ALC221_FIXUP_HP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x83b9, "HP Spectre x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
-       SND_PCI_QUIRK(0x103c, 0x841c, "HP Pavilion 15-CK0xx", ALC269_FIXUP_HP_MUTE_LED_MIC3),
-       SND_PCI_QUIRK(0x103c, 0x8497, "HP Envy x360", ALC269_FIXUP_HP_MUTE_LED_MIC3),
-       SND_PCI_QUIRK(0x103c, 0x84a6, "HP 250 G7 Notebook PC", ALC269_FIXUP_HP_LINE1_MIC1_LED),
-       SND_PCI_QUIRK(0x103c, 0x84ae, "HP 15-db0403ng", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x84da, "HP OMEN dc0019-ur", ALC295_FIXUP_HP_OMEN),
-       SND_PCI_QUIRK(0x103c, 0x84e7, "HP Pavilion 15", ALC269_FIXUP_HP_MUTE_LED_MIC3),
-       SND_PCI_QUIRK(0x103c, 0x8519, "HP Spectre x360 15-df0xxx", ALC285_FIXUP_HP_SPECTRE_X360),
-       SND_PCI_QUIRK(0x103c, 0x8537, "HP ProBook 440 G6", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x85c6, "HP Pavilion x360 Convertible 14-dy1xxx", ALC295_FIXUP_HP_MUTE_LED_COEFBIT11),
-       SND_PCI_QUIRK(0x103c, 0x85de, "HP Envy x360 13-ar0xxx", ALC285_FIXUP_HP_ENVY_X360),
-       SND_PCI_QUIRK(0x103c, 0x860f, "HP ZBook 15 G6", ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x861f, "HP Elite Dragonfly G1", ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x869d, "HP", ALC236_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x86c1, "HP Laptop 15-da3001TU", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x86c7, "HP Envy AiO 32", ALC274_FIXUP_HP_ENVY_GPIO),
-       SND_PCI_QUIRK(0x103c, 0x86e7, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
-       SND_PCI_QUIRK(0x103c, 0x863e, "HP Spectre x360 15-df1xxx", ALC285_FIXUP_HP_SPECTRE_X360_DF1),
-       SND_PCI_QUIRK(0x103c, 0x86e8, "HP Spectre x360 15-eb0xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
-       SND_PCI_QUIRK(0x103c, 0x86f9, "HP Spectre x360 13-aw0xxx", ALC285_FIXUP_HP_SPECTRE_X360_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x8716, "HP Elite Dragonfly G2 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x8720, "HP EliteBook x360 1040 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x8724, "HP EliteBook 850 G7", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8728, "HP EliteBook 840 G7", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8729, "HP", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8730, "HP ProBook 445 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8735, "HP ProBook 435 G7", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8736, "HP", ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x8760, "HP EliteBook 8{4,5}5 G7", ALC285_FIXUP_HP_BEEP_MICMUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x876e, "HP ENVY x360 Convertible 13-ay0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
-       SND_PCI_QUIRK(0x103c, 0x877a, "HP", ALC285_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x877d, "HP", ALC236_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x8780, "HP ZBook Fury 17 G7 Mobile Workstation",
-                     ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x8783, "HP ZBook Fury 15 G7 Mobile Workstation",
-                     ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x8786, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x8787, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x8788, "HP OMEN 15", ALC285_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x87b7, "HP Laptop 14-fq0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x87c8, "HP", ALC287_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x87d3, "HP Laptop 15-gw0xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x87df, "HP ProBook 430 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x87e5, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x87e7, "HP ProBook 450 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x87f1, "HP ProBook 630 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x87f2, "HP ProBook 640 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x87f4, "HP", ALC287_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x87f5, "HP", ALC287_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x87f6, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
-       SND_PCI_QUIRK(0x103c, 0x87f7, "HP Spectre x360 14", ALC245_FIXUP_HP_X360_AMP),
-       SND_PCI_QUIRK(0x103c, 0x87fd, "HP Laptop 14-dq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x87fe, "HP Laptop 15s-fq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x8805, "HP ProBook 650 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x880d, "HP EliteBook 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8811, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
-       SND_PCI_QUIRK(0x103c, 0x8812, "HP Spectre x360 15-eb1xxx", ALC285_FIXUP_HP_SPECTRE_X360_EB1),
-       SND_PCI_QUIRK(0x103c, 0x881d, "HP 250 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x881e, "HP Laptop 15s-du3xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x8846, "HP EliteBook 850 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8847, "HP EliteBook x360 830 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x884b, "HP EliteBook 840 Aero G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x884c, "HP EliteBook 840 G8 Notebook PC", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8862, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x103c, 0x8863, "HP ProBook 445 G8 Notebook PC", ALC236_FIXUP_HP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x103c, 0x886d, "HP ZBook Fury 17.3 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x8870, "HP ZBook Fury 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x8873, "HP ZBook Studio 15.6 Inch G8 Mobile Workstation PC", ALC285_FIXUP_HP_GPIO_AMP_INIT),
-       SND_PCI_QUIRK(0x103c, 0x887a, "HP Laptop 15s-eq2xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x887c, "HP Laptop 14s-fq1xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x888a, "HP ENVY x360 Convertible 15-eu0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
-       SND_PCI_QUIRK(0x103c, 0x888d, "HP ZBook Power 15.6 inch G8 Mobile Workstation PC", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8895, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_SPEAKERS_MICMUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x8896, "HP EliteBook 855 G8 Notebook PC", ALC285_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x8898, "HP EliteBook 845 G8 Notebook PC", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x103c, 0x88d0, "HP Pavilion 15-eh1xxx (mainboard 88D0)", ALC287_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x88dd, "HP Pavilion 15z-ec200", ALC285_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x8902, "HP OMEN 16", ALC285_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK(0x103c, 0x890e, "HP 255 G8 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x8919, "HP Pavilion Aero Laptop 13-be0xxx", ALC287_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x896d, "HP ZBook Firefly 16 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x896e, "HP EliteBook x360 830 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8971, "HP EliteBook 830 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8972, "HP EliteBook 840 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8973, "HP EliteBook 860 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8974, "HP EliteBook 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8975, "HP EliteBook x360 840 Aero G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x897d, "HP mt440 Mobile Thin Client U74", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8981, "HP Elite Dragonfly G3", ALC245_FIXUP_CS35L41_SPI_4),
-       SND_PCI_QUIRK(0x103c, 0x898a, "HP Pavilion 15-eg100", ALC287_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x898e, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x898f, "HP EliteBook 835 G9", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8991, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8992, "HP EliteBook 845 G9", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8994, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8995, "HP EliteBook 855 G9", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x89a4, "HP ProBook 440 G9", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x89a6, "HP ProBook 450 G9", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x89aa, "HP EliteBook 630 G9", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x89ac, "HP EliteBook 640 G9", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x89ae, "HP EliteBook 650 G9", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x89c0, "HP ZBook Power 15.6 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x89c3, "Zbook Studio G9", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x89c6, "Zbook Fury 17 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x89ca, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x89d3, "HP EliteBook 645 G9 (MB 89D2)", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x89e7, "HP Elite x2 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8a0f, "HP Pavilion 14-ec1xxx", ALC287_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8a20, "HP Laptop 15s-fq5xxx", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x8a25, "HP Victus 16-d1xxx (MB 8A25)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
-       SND_PCI_QUIRK(0x103c, 0x8a28, "HP Envy 13", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a29, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a2a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a2b, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a2c, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a2d, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a2e, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a30, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a31, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8a6e, "HP EDNA 360", ALC287_FIXUP_CS35L41_I2C_4),
-       SND_PCI_QUIRK(0x103c, 0x8a74, "HP ProBook 440 G8 Notebook PC", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8a78, "HP Dev One", ALC285_FIXUP_HP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x103c, 0x8aa0, "HP ProBook 440 G9 (MB 8A9E)", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8aa3, "HP ProBook 450 G9 (MB 8AA1)", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8aa8, "HP EliteBook 640 G9 (MB 8AA6)", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8aab, "HP EliteBook 650 G9 (MB 8AA9)", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ab9, "HP EliteBook 840 G8 (MB 8AB8)", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8abb, "HP ZBook Firefly 14 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ad1, "HP EliteBook 840 14 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ad2, "HP EliteBook 860 16 inch G9 Notebook PC", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ad8, "HP 800 G9", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b0f, "HP Elite mt645 G7 Mobile Thin Client U81", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8b2f, "HP 255 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_COEFBIT2),
-       SND_PCI_QUIRK(0x103c, 0x8b3a, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8b3f, "HP mt440 Mobile Thin Client U91", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b42, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b43, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b44, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b45, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b46, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b47, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b59, "HP Elite mt645 G7 Mobile Thin Client U89", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8b5d, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8b5e, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8b5f, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8b63, "HP Elite Dragonfly 13.5 inch G4", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b65, "HP ProBook 455 15.6 inch G10 Notebook PC", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8b66, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8b70, "HP EliteBook 835 G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b72, "HP EliteBook 845 G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b74, "HP EliteBook 845W G10", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b77, "HP ElieBook 865 G10", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8b7a, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b7d, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b87, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b8a, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b8b, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b8d, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b8f, "HP", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b92, "HP", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8b96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8b97, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8bb3, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8bb4, "HP Slim OMEN", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8bbe, "HP Victus 16-r0xxx (MB 8BBE)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
-       SND_PCI_QUIRK(0x103c, 0x8bc8, "HP Victus 15-fa1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
-       SND_PCI_QUIRK(0x103c, 0x8bcd, "HP Omen 16-xd0xxx", ALC245_FIXUP_HP_MUTE_LED_V1_COEFBIT),
-       SND_PCI_QUIRK(0x103c, 0x8bdd, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8bde, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8bdf, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be0, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be1, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be2, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be3, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be5, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be6, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be7, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be8, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8be9, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8bf0, "HP", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c15, "HP Spectre x360 2-in-1 Laptop 14-eu0xxx", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
-       SND_PCI_QUIRK(0x103c, 0x8c16, "HP Spectre x360 2-in-1 Laptop 16-aa0xxx", ALC245_FIXUP_HP_SPECTRE_X360_16_AA0XXX),
-       SND_PCI_QUIRK(0x103c, 0x8c17, "HP Spectre 16", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c21, "HP Pavilion Plus Laptop 14-ey0XXX", ALC245_FIXUP_HP_X360_MUTE_LEDS),
-       SND_PCI_QUIRK(0x103c, 0x8c30, "HP Victus 15-fb1xxx", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
-       SND_PCI_QUIRK(0x103c, 0x8c46, "HP EliteBook 830 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c47, "HP EliteBook 840 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c48, "HP EliteBook 860 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c49, "HP Elite x360 830 2-in-1 G11", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c4d, "HP Omen", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c4e, "HP Omen", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c4f, "HP Envy 15", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c50, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c51, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c52, "HP EliteBook 1040 G11", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c53, "HP Elite x360 1040 2-in-1 G11", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c66, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c67, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c68, "HP Envy 17", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c6a, "HP Envy 16", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8c70, "HP EliteBook 835 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c71, "HP EliteBook 845 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c72, "HP EliteBook 865 G11", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c7b, "HP ProBook 445 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c7c, "HP ProBook 445 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c7d, "HP ProBook 465 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c7e, "HP ProBook 465 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c7f, "HP EliteBook 645 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c80, "HP EliteBook 645 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c81, "HP EliteBook 665 G11", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c89, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c8a, "HP EliteBook 630", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c8c, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c8d, "HP ProBook 440 G11", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c8e, "HP ProBook 460 G11", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c90, "HP EliteBook 640", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c91, "HP EliteBook 660", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8c96, "HP", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c97, "HP ZBook", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8c9c, "HP Victus 16-s1xxx (MB 8C9C)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
-       SND_PCI_QUIRK(0x103c, 0x8ca1, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ca2, "HP ZBook Power", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ca4, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ca7, "HP ZBook Fury", ALC245_FIXUP_CS35L41_SPI_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8caf, "HP Elite mt645 G8 Mobile Thin Client", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8cbd, "HP Pavilion Aero Laptop 13-bg0xxx", ALC245_FIXUP_HP_X360_MUTE_LEDS),
-       SND_PCI_QUIRK(0x103c, 0x8cdd, "HP Spectre", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
-       SND_PCI_QUIRK(0x103c, 0x8cde, "HP OmniBook Ultra Flip Laptop 14t", ALC245_FIXUP_HP_SPECTRE_X360_EU0XXX),
-       SND_PCI_QUIRK(0x103c, 0x8cdf, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ce0, "HP SnowWhite", ALC287_FIXUP_CS35L41_I2C_2_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8cf5, "HP ZBook Studio 16", ALC245_FIXUP_CS35L41_SPI_4_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d01, "HP ZBook Power 14 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d07, "HP Victus 15-fb2xxx (MB 8D07)", ALC245_FIXUP_HP_MUTE_LED_COEFBIT),
-       SND_PCI_QUIRK(0x103c, 0x8d18, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS),
-       SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d85, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d86, "HP Elite X360 14 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d8c, "HP EliteBook 13 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d8d, "HP Elite X360 13 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d8e, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d8f, "HP EliteBook 14 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d90, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8d9b, "HP 17 Turbine OmniBook 7 UMA", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8d9c, "HP 17 Turbine OmniBook 7 DIS", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8d9d, "HP 17 Turbine OmniBook X UMA", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8d9e, "HP 17 Turbine OmniBook X DIS", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8d9f, "HP 14 Cadet (x360)", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8da0, "HP 16 Clipper OmniBook 7(X360)", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8da1, "HP 16 Clipper OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8da7, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8da8, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8dd4, "HP EliteStudio 8 AIO", ALC274_FIXUP_HP_AIO_BIND_DACS),
-       SND_PCI_QUIRK(0x103c, 0x8de8, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
-       SND_PCI_QUIRK(0x103c, 0x8de9, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
-       SND_PCI_QUIRK(0x103c, 0x8dec, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8ded, "HP EliteBook 640 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8dee, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8def, "HP EliteBook 660 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8df0, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8df1, "HP EliteBook 630 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8dfb, "HP EliteBook 6 G1a 14", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8dfc, "HP EliteBook 645 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8dfd, "HP EliteBook 6 G1a 16", ALC236_FIXUP_HP_MUTE_LED_MICMUTE_VREF),
-       SND_PCI_QUIRK(0x103c, 0x8dfe, "HP EliteBook 665 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8e11, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e12, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e13, "HP Trekker", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e14, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e15, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e16, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e17, "HP ZBook Firefly 14 G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e1b, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e1c, "HP EliteBook G12", ALC245_FIXUP_HP_ZBOOK_FIREFLY_G12A),
-       SND_PCI_QUIRK(0x103c, 0x8e1d, "HP ZBook X Gli 16 G12", ALC236_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8e2c, "HP EliteBook 16 G12", ALC285_FIXUP_HP_GPIO_LED),
-       SND_PCI_QUIRK(0x103c, 0x8e36, "HP 14 Enstrom OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e37, "HP 16 Piston OmniBook X", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e3a, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e3b, "HP Agusta", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e60, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e61, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x103c, 0x8e62, "HP Trekker ", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1032, "ASUS VivoBook X513EA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1034, "ASUS GU605C", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
-       SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
-       SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300),
-       SND_PCI_QUIRK(0x1043, 0x1054, "ASUS G614FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x1043, 0x106f, "ASUS VivoBook X515UA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1074, "ASUS G614PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x10a1, "ASUS UX391UA", ALC294_FIXUP_ASUS_SPK),
-       SND_PCI_QUIRK(0x1043, 0x10a4, "ASUS TP3407SA", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x10c0, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC),
-       SND_PCI_QUIRK(0x1043, 0x10d0, "ASUS X540LA/X540LJ", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x10d3, "ASUS K6500ZC", ALC294_FIXUP_ASUS_SPK),
-       SND_PCI_QUIRK(0x1043, 0x1154, "ASUS TP3607SH", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x1043, 0x1194, "ASUS UM3406KA", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x11c0, "ASUS X556UR", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1204, "ASUS Strix G615JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x1214, "ASUS Strix G615LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x125e, "ASUS Q524UQK", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1271, "ASUS X430UN", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1290, "ASUS X441SA", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1294, "ASUS B3405CVA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x12a0, "ASUS X441UV", ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x12a3, "Asus N7691ZM", ALC269_FIXUP_ASUS_N7601ZM),
-       SND_PCI_QUIRK(0x1043, 0x12af, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x12b4, "ASUS B3405CCA / P3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x12e0, "ASUS X541SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x12f0, "ASUS X541UV", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1313, "Asus K42JZ", ALC269VB_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1314, "ASUS GA605K", ALC285_FIXUP_ASUS_GA605K_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x13b0, "ASUS Z550SA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
-       SND_PCI_QUIRK(0x1043, 0x1433, "ASUS GX650PY/PZ/PV/PU/PYV/PZV/PIV/PVV", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1460, "Asus VivoBook 15", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1463, "Asus GA402X/GA402N", ALC285_FIXUP_ASUS_I2C_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1473, "ASUS GU604VI/VC/VE/VG/VJ/VQ/VU/VV/VY/VZ", ALC285_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS GU603VQ/VU/VV/VJ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1493, "ASUS GV601VV/VU/VJ/VQ/VI", ALC285_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G614JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS G513PI/PU/PV", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x14f2, "ASUS VivoBook X515JA", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1503, "ASUS G733PY/PZ/PZV/PYV", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
-       SND_PCI_QUIRK(0x1043, 0x1533, "ASUS GV302XA/XJ/XQ/XU/XV/XI", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1573, "ASUS GZ301VV/VQ/VU/VJ/VA/VC/VE/VVC/VQC/VUC/VJC/VEC/VCC", ALC285_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1662, "ASUS GV301QH", ALC294_FIXUP_ASUS_DUAL_SPK),
-       SND_PCI_QUIRK(0x1043, 0x1663, "ASUS GU603ZI/ZJ/ZQ/ZU/ZV", ALC285_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1683, "ASUS UM3402YAR", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS UX3402VA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x16b2, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x16d3, "ASUS UX5304VA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS UX7602VI/BZ", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1740, "ASUS UX430UA", ALC295_FIXUP_ASUS_DACS),
-       SND_PCI_QUIRK(0x1043, 0x17d1, "ASUS UX431FL", ALC294_FIXUP_ASUS_DUAL_SPK),
-       SND_PCI_QUIRK(0x1043, 0x17f3, "ROG Ally NR2301L/X", ALC294_FIXUP_ASUS_ALLY),
-       SND_PCI_QUIRK(0x1043, 0x1863, "ASUS UX6404VI/VV", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1881, "ASUS Zephyrus S/M", ALC294_FIXUP_ASUS_GX502_PINS),
-       SND_PCI_QUIRK(0x1043, 0x18b1, "Asus MJ401TA", ALC256_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS UM3504DA", ALC294_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x18f1, "Asus FX505DT", ALC256_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x194e, "ASUS UX563FD", ALC294_FIXUP_ASUS_HPE),
-       SND_PCI_QUIRK(0x1043, 0x1970, "ASUS UX550VE", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1982, "ASUS B1400CEPE", ALC256_FIXUP_ASUS_HPE),
-       SND_PCI_QUIRK(0x1043, 0x19ce, "ASUS B9450FA", ALC294_FIXUP_ASUS_HPE),
-       SND_PCI_QUIRK(0x1043, 0x19e1, "ASUS UX581LV", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
-       SND_PCI_QUIRK(0x1043, 0x1a63, "ASUS UX3405MA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1a83, "ASUS UM5302LA", ALC294_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1a8f, "ASUS UX582ZS", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1b11, "ASUS UX431DA", ALC294_FIXUP_ASUS_COEF_1B),
-       SND_PCI_QUIRK(0x1043, 0x1b13, "ASUS U41SV/GA403U", ALC285_FIXUP_ASUS_GA403U_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1b93, "ASUS G614JVR/JIR", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1bbd, "ASUS Z550MA", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1c03, "ASUS UM3406HA", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x1043, 0x1c33, "ASUS UX5304MA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1c43, "ASUS UX8406MA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1c62, "ASUS GU603", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1c63, "ASUS GU605M", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
-       SND_PCI_QUIRK(0x1043, 0x1c80, "ASUS VivoBook TP401", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1c92, "ASUS ROG Strix G15", ALC285_FIXUP_ASUS_G533Z_PINS),
-       SND_PCI_QUIRK(0x1043, 0x1c9f, "ASUS G614JU/JV/JI", ALC285_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1caf, "ASUS G634JY/JZ/JI/JG", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
-       SND_PCI_QUIRK(0x1043, 0x1ccd, "ASUS X555UB", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1ccf, "ASUS G814JU/JV/JI", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1cdf, "ASUS G814JY/JZ/JG", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1cef, "ASUS G834JY/JZ/JI/JG", ALC285_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1d1f, "ASUS G713PI/PU/PV/PVN", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1d42, "ASUS Zephyrus G14 2022", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1d4e, "ASUS TM420", ALC256_FIXUP_ASUS_HPE),
-       SND_PCI_QUIRK(0x1043, 0x1da2, "ASUS UP6502ZA/ZD", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1df3, "ASUS UM5606WA", ALC294_FIXUP_BASS_SPEAKER_15),
-       SND_PCI_QUIRK(0x1043, 0x1264, "ASUS UM5606KA", ALC294_FIXUP_BASS_SPEAKER_15),
-       SND_PCI_QUIRK(0x1043, 0x1e02, "ASUS UX3402ZA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1e10, "ASUS VivoBook X507UAR", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1043, 0x1e11, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA502),
-       SND_PCI_QUIRK(0x1043, 0x1e12, "ASUS UM3402", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1e1f, "ASUS Vivobook 15 X1504VAP", ALC2XX_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1e51, "ASUS Zephyrus M15", ALC294_FIXUP_ASUS_GU502_PINS),
-       SND_PCI_QUIRK(0x1043, 0x1e5e, "ASUS ROG Strix G513", ALC294_FIXUP_ASUS_G513_PINS),
-       SND_PCI_QUIRK(0x1043, 0x1e63, "ASUS H7606W", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
-       SND_PCI_QUIRK(0x1043, 0x1e83, "ASUS GA605W", ALC285_FIXUP_ASUS_GU605_SPI_SPEAKER2_TO_DAC1),
-       SND_PCI_QUIRK(0x1043, 0x1e8e, "ASUS Zephyrus G15", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1e93, "ASUS ExpertBook B9403CVAR", ALC294_FIXUP_ASUS_HPE),
-       SND_PCI_QUIRK(0x1043, 0x1eb3, "ASUS Ally RCLA72", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x1ed3, "ASUS HN7306W", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1ee2, "ASUS UM6702RA/RC", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1c52, "ASUS Zephyrus G15 2022", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1f11, "ASUS Zephyrus G14", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1f12, "ASUS UM5302", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x1f1f, "ASUS H7604JI/JV/J3D", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1f62, "ASUS UX7602ZM", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1f63, "ASUS P5405CSA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x1f92, "ASUS ROG Flow X16", ALC289_FIXUP_ASUS_GA401),
-       SND_PCI_QUIRK(0x1043, 0x1fb3, "ASUS ROG Flow Z13 GZ302EA", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x3011, "ASUS B5605CVA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x3030, "ASUS ZN270IE", ALC256_FIXUP_ASUS_AIO_GPIO2),
-       SND_PCI_QUIRK(0x1043, 0x3061, "ASUS B3405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x3071, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x30c1, "ASUS B3605CCA / P3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x30d1, "ASUS B5405CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x30e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x31d0, "ASUS Zen AIO 27 Z272SD_A272SD", ALC274_FIXUP_ASUS_ZEN_AIO_27),
-       SND_PCI_QUIRK(0x1043, 0x31e1, "ASUS B5605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x31f1, "ASUS B3605CCA", ALC294_FIXUP_ASUS_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x3a20, "ASUS G614JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
-       SND_PCI_QUIRK(0x1043, 0x3a30, "ASUS G814JVR/JIR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
-       SND_PCI_QUIRK(0x1043, 0x3a40, "ASUS G814JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
-       SND_PCI_QUIRK(0x1043, 0x3a50, "ASUS G834JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
-       SND_PCI_QUIRK(0x1043, 0x3a60, "ASUS G634JYR/JZR", ALC285_FIXUP_ASUS_SPI_REAR_SPEAKERS),
-       SND_PCI_QUIRK(0x1043, 0x3d78, "ASUS GA603KH", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x3d88, "ASUS GA603KM", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x3e00, "ASUS G814FH/FM/FP", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x3e20, "ASUS G814PH/PM/PP", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x1043, 0x3e30, "ASUS TP3607SA", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x3ee0, "ASUS Strix G815_JHR_JMR_JPR", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x3ef0, "ASUS Strix G635LR_LW_LX", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x3f00, "ASUS Strix G815LH_LM_LP", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x3f10, "ASUS Strix G835LR_LW_LX", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x3f20, "ASUS Strix G615LR_LW", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x3f30, "ASUS Strix G815LR_LW", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x1043, 0x3fd0, "ASUS B3605CVA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x3ff0, "ASUS B5405CVA", ALC245_FIXUP_CS35L41_SPI_2),
-       SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC),
-       SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101),
-       SND_PCI_QUIRK(0x1043, 0x88f4, "ASUS NUC14LNS", ALC245_FIXUP_CS35L41_SPI_1),
-       SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2),
-       SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
-       SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ),
-       SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX),
-       SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK),
-       SND_PCI_QUIRK(0x10cf, 0x159f, "Lifebook E780", ALC269_FIXUP_LIFEBOOK_NO_HP_TO_LINEOUT),
-       SND_PCI_QUIRK(0x10cf, 0x15dc, "Lifebook T731", ALC269_FIXUP_LIFEBOOK_HP_PIN),
-       SND_PCI_QUIRK(0x10cf, 0x1629, "Lifebook U7x7", ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC),
-       SND_PCI_QUIRK(0x10cf, 0x1757, "Lifebook E752", ALC269_FIXUP_LIFEBOOK_HP_PIN),
-       SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC),
-       SND_PCI_QUIRK(0x10ec, 0x10f2, "Intel Reference board", ALC700_FIXUP_INTEL_REFERENCE),
-       SND_PCI_QUIRK(0x10ec, 0x118c, "Medion EE4254 MD62100", ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE),
-       SND_PCI_QUIRK(0x10ec, 0x119e, "Positivo SU C1400", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
-       SND_PCI_QUIRK(0x10ec, 0x11bc, "VAIO VJFE-IL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x10ec, 0x1230, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0x10ec, 0x124c, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0x10ec, 0x1252, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0x10ec, 0x1254, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0x10ec, 0x12cc, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0x10ec, 0x12f6, "Intel Reference board", ALC295_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-SZ6", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
-       SND_PCI_QUIRK(0x144d, 0xc109, "Samsung Ativ book 9 (NP900X3G)", ALC269_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x144d, 0xc169, "Samsung Notebook 9 Pen (NP930SBE-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc176, "Samsung Notebook 9 Pro (NP930MBE-K04US)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc189, "Samsung Galaxy Flex Book (NT950QCG-X716)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc18a, "Samsung Galaxy Book Ion (NP930XCJ-K01US)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc1a3, "Samsung Galaxy Book Pro (NP935XDB-KC1SE)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc1a4, "Samsung Galaxy Book Pro 360 (NT935QBD)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc1a6, "Samsung Galaxy Book Pro 360 (NP930QBD)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc740, "Samsung Ativ book 8 (NP870Z5G)", ALC269_FIXUP_ATIV_BOOK_8),
-       SND_PCI_QUIRK(0x144d, 0xc812, "Samsung Notebook Pen S (NT950SBE-X58)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc830, "Samsung Galaxy Book Ion (NT950XCJ-X716A)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc832, "Samsung Galaxy Book Flex Alpha (NP730QCJ)", ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
-       SND_PCI_QUIRK(0x144d, 0xca03, "Samsung Galaxy Book2 Pro 360 (NP930QED)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xca06, "Samsung Galaxy Book3 360 (NP730QFG)", ALC298_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET),
-       SND_PCI_QUIRK(0x144d, 0xc868, "Samsung Galaxy Book2 Pro (NP930XED)", ALC298_FIXUP_SAMSUNG_AMP),
-       SND_PCI_QUIRK(0x144d, 0xc870, "Samsung Galaxy Book2 Pro (NP950XED)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
-       SND_PCI_QUIRK(0x144d, 0xc872, "Samsung Galaxy Book2 Pro (NP950XEE)", ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS),
-       SND_PCI_QUIRK(0x144d, 0xc886, "Samsung Galaxy Book3 Pro (NP964XFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
-       SND_PCI_QUIRK(0x144d, 0xc1ca, "Samsung Galaxy Book3 Pro 360 (NP960QFG)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
-       SND_PCI_QUIRK(0x144d, 0xc1cc, "Samsung Galaxy Book3 Ultra (NT960XFH)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
-       SND_PCI_QUIRK(0x1458, 0xfa53, "Gigabyte BXBT-2807", ALC283_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1462, 0xb120, "MSI Cubi MS-B120", ALC283_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1462, 0xb171, "Cubi N 8GL (MS-B171)", ALC283_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x152d, 0x1082, "Quanta NL3", ALC269_FIXUP_LIFEBOOK),
-       SND_PCI_QUIRK(0x152d, 0x1262, "Huawei NBLB-WAX9N", ALC2XX_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1558, 0x0353, "Clevo V35[05]SN[CDE]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x1323, "Clevo N130ZU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x1325, "Clevo N15[01][CW]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x1401, "Clevo L140[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x1403, "Clevo N140CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x1404, "Clevo N150CU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x14a1, "Clevo L141MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x2624, "Clevo L240TU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x28c1, "Clevo V370VND", ALC2XX_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1558, 0x35a1, "Clevo V3[56]0EN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x35b1, "Clevo V3[57]0WN[MNP]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x4018, "Clevo NV40M[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x4019, "Clevo NV40MZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x4020, "Clevo NV40MB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x4041, "Clevo NV4[15]PZ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x40a1, "Clevo NL40GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x40c1, "Clevo NL40[CZ]U", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x40d1, "Clevo NL41DU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x5015, "Clevo NH5[58]H[HJK]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x5017, "Clevo NH7[79]H[HJK]Q", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50a3, "Clevo NJ51GU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50b3, "Clevo NK50S[BEZ]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50b6, "Clevo NK50S5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50b8, "Clevo NK50SZ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50d5, "Clevo NP50D5", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50e1, "Clevo NH5[58]HPQ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50e2, "Clevo NH7[79]HPQ", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50f0, "Clevo NH50A[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50f2, "Clevo NH50E[PR]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50f3, "Clevo NH58DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50f5, "Clevo NH55EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x50f6, "Clevo NH55DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x5101, "Clevo S510WU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x5157, "Clevo W517GU1", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x51a1, "Clevo NS50MU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x51b1, "Clevo NS50AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x51b3, "Clevo NS70AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x5630, "Clevo NP50RNJS", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x5700, "Clevo X560WN[RST]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x70a1, "Clevo NB70T[HJK]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x70b3, "Clevo NK70SB", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x70f2, "Clevo NH79EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x70f3, "Clevo NH77DPQ", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x70f4, "Clevo NH77EPY", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x70f6, "Clevo NH77DPQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x7716, "Clevo NS50PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x7717, "Clevo NS70PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x7718, "Clevo L140PU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x7724, "Clevo L140AU", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8228, "Clevo NR40BU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8520, "Clevo NH50D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8521, "Clevo NH77D[CD]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8535, "Clevo NH50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8536, "Clevo NH79D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8550, "Clevo NH[57][0-9][ER][ACDH]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8551, "Clevo NH[57][0-9][ER][ACDH]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8560, "Clevo NH[57][0-9][ER][ACDH]Q", ALC269_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1558, 0x8561, "Clevo NH[57][0-9][ER][ACDH]Q", ALC269_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1558, 0x8562, "Clevo NH[57][0-9]RZ[Q]", ALC269_FIXUP_DMIC),
-       SND_PCI_QUIRK(0x1558, 0x8668, "Clevo NP50B[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x866d, "Clevo NP5[05]PN[HJK]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x867c, "Clevo NP7[01]PNP", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x867d, "Clevo NP7[01]PN[HJK]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8680, "Clevo NJ50LU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8686, "Clevo NH50[CZ]U", ALC256_FIXUP_MIC_NO_PRESENCE_AND_RESUME),
-       SND_PCI_QUIRK(0x1558, 0x8a20, "Clevo NH55DCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8a51, "Clevo NH70RCQ-Y", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x8d50, "Clevo NH55RCQ-M", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x951d, "Clevo N950T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x9600, "Clevo N960K[PR]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x961d, "Clevo N960S[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0x971d, "Clevo N970T[CDF]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xa500, "Clevo NL5[03]RU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xa554, "VAIO VJFH52", ALC269_FIXUP_VAIO_VJFH52_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xa600, "Clevo NL50NU", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xa650, "Clevo NP[567]0SN[CD]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xa671, "Clevo NP70SN[CDE]", ALC256_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xa741, "Clevo V54x_6x_TNE", ALC245_FIXUP_CLEVO_NOISY_MIC),
-       SND_PCI_QUIRK(0x1558, 0xa743, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC),
-       SND_PCI_QUIRK(0x1558, 0xa763, "Clevo V54x_6x_TU", ALC245_FIXUP_CLEVO_NOISY_MIC),
-       SND_PCI_QUIRK(0x1558, 0xb018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xb019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xb022, "Clevo NH77D[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xc018, "Clevo NP50D[BE]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xc019, "Clevo NH77D[BE]Q", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1558, 0xc022, "Clevo NH77[DC][QW]", ALC293_FIXUP_SYSTEM76_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC233_FIXUP_LENOVO_MULTI_CODECS),
-       SND_PCI_QUIRK(0x17aa, 0x1048, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
-       SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x21ca, "Thinkpad L412", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440),
-       SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2211, "Thinkpad W541", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x2218, "Thinkpad X1 Carbon 2nd", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2223, "ThinkPad T550", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2226, "ThinkPad X250", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x222d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x222e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2231, "Thinkpad T560", ALC292_FIXUP_TPT460),
-       SND_PCI_QUIRK(0x17aa, 0x2233, "Thinkpad", ALC292_FIXUP_TPT460),
-       SND_PCI_QUIRK(0x17aa, 0x2234, "Thinkpad ICE-1", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x2245, "Thinkpad T470", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2246, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2247, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x2249, "Thinkpad", ALC292_FIXUP_TPT460),
-       SND_PCI_QUIRK(0x17aa, 0x224b, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x224c, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x224d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x225d, "Thinkpad T480", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x2292, "Thinkpad X1 Carbon 7th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
-       SND_PCI_QUIRK(0x17aa, 0x22be, "Thinkpad X1 Carbon 8th", ALC285_FIXUP_THINKPAD_HEADSET_JACK),
-       SND_PCI_QUIRK(0x17aa, 0x22c1, "Thinkpad P1 Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
-       SND_PCI_QUIRK(0x17aa, 0x22c2, "Thinkpad X1 Extreme Gen 3", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK),
-       SND_PCI_QUIRK(0x17aa, 0x22f1, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x22f2, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x22f3, "Thinkpad", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x2316, "Thinkpad P1 Gen 6", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x2317, "Thinkpad P1 Gen 6", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x2318, "Thinkpad Z13 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x2319, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x231a, "Thinkpad Z16 Gen2", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x231e, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
-       SND_PCI_QUIRK(0x17aa, 0x231f, "Thinkpad", ALC287_FIXUP_LENOVO_THKPAD_WH_ALC1318),
-       SND_PCI_QUIRK(0x17aa, 0x2326, "Hera2", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x30bb, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
-       SND_PCI_QUIRK(0x17aa, 0x30e2, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY),
-       SND_PCI_QUIRK(0x17aa, 0x310c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
-       SND_PCI_QUIRK(0x17aa, 0x3111, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
-       SND_PCI_QUIRK(0x17aa, 0x312a, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
-       SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
-       SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION),
-       SND_PCI_QUIRK(0x17aa, 0x3151, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x17aa, 0x3176, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x17aa, 0x3178, "ThinkCentre Station", ALC283_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x17aa, 0x31af, "ThinkCentre Station", ALC623_FIXUP_LENOVO_THINKSTATION_P340),
-       SND_PCI_QUIRK(0x17aa, 0x334b, "Lenovo ThinkCentre M70 Gen5", ALC283_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x17aa, 0x3384, "ThinkCentre M90a PRO", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
-       SND_PCI_QUIRK(0x17aa, 0x3386, "ThinkCentre M90a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
-       SND_PCI_QUIRK(0x17aa, 0x3387, "ThinkCentre M70a Gen6", ALC233_FIXUP_LENOVO_L2MH_LOW_ENLED),
-       SND_PCI_QUIRK(0x17aa, 0x3801, "Lenovo Yoga9 14IAP7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
-       HDA_CODEC_QUIRK(0x17aa, 0x3802, "DuetITL 2021", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x3802, "Lenovo Yoga Pro 9 14IRP8", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3813, "Legion 7i 15IMHG05", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x3818, "Lenovo C940 / Yoga Duet 7", ALC298_FIXUP_LENOVO_C940_DUET7),
-       SND_PCI_QUIRK(0x17aa, 0x3819, "Lenovo 13s Gen2 ITL", ALC287_FIXUP_13S_GEN2_SPEAKERS),
-       HDA_CODEC_QUIRK(0x17aa, 0x3820, "IdeaPad 330-17IKB 81DM", ALC269_FIXUP_ASPIRE_HEADSET_MIC),
-       SND_PCI_QUIRK(0x17aa, 0x3820, "Yoga Duet 7 13ITL6", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x3824, "Legion Y9000X 2020", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x3827, "Ideapad S740", ALC285_FIXUP_IDEAPAD_S740_COEF),
-       SND_PCI_QUIRK(0x17aa, 0x3834, "Lenovo IdeaPad Slim 9i 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x383d, "Legion Y9000X 2019", ALC285_FIXUP_LEGION_Y9000X_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x3843, "Yoga 9i", ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP),
-       SND_PCI_QUIRK(0x17aa, 0x3847, "Legion 7 16ACHG6", ALC287_FIXUP_LEGION_16ACHG6),
-       SND_PCI_QUIRK(0x17aa, 0x384a, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x3852, "Lenovo Yoga 7 14ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x3853, "Lenovo Yoga 7 15ITL5", ALC287_FIXUP_YOGA7_14ITL_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x3855, "Legion 7 16ITHG6", ALC287_FIXUP_LEGION_16ITHG6),
-       SND_PCI_QUIRK(0x17aa, 0x3865, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x3866, "Lenovo 13X", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x3869, "Lenovo Yoga7 14IAL7", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
-       HDA_CODEC_QUIRK(0x17aa, 0x386e, "Legion Y9000X 2022 IAH7", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x386e, "Yoga Pro 7 14ARP8", ALC285_FIXUP_SPEAKER2_TO_DAC1),
-       HDA_CODEC_QUIRK(0x17aa, 0x38a8, "Legion Pro 7 16ARX8H", ALC287_FIXUP_TAS2781_I2C), /* this must match before PCI SSID 17aa:386f below */
-       SND_PCI_QUIRK(0x17aa, 0x386f, "Legion Pro 7i 16IAX7", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x3870, "Lenovo Yoga 7 14ARB7", ALC287_FIXUP_YOGA7_14ARB7_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3877, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x3878, "Lenovo Legion 7 Slim 16ARHA7", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x387d, "Yoga S780-16 pro Quad AAC", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x387e, "Yoga S780-16 pro Quad YC", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x387f, "Yoga S780-16 pro dual LX", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3880, "Yoga S780-16 pro dual YC", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3881, "YB9 dual power mode2 YC", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3882, "Lenovo Yoga Pro 7 14APH8", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x3884, "Y780 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3886, "Y780 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3891, "Lenovo Yoga Pro 7 14AHP9", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x38a5, "Y580P AMD dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38a7, "Y780P AMD YG dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38a8, "Y780P AMD VECO dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38a9, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x38ab, "Thinkbook 16P", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x38b4, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x38b5, "Legion Slim 7 16IRH8", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x38b6, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x38b7, "Legion Slim 7 16APH8", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x17aa, 0x38b8, "Yoga S780-14.5 proX AMD YC Dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38b9, "Yoga S780-14.5 proX AMD LX Dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38ba, "Yoga S780-14.5 Air AMD quad YC", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38bb, "Yoga S780-14.5 Air AMD quad AAC", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38be, "Yoga S980-14.5 proX YC Dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38bf, "Yoga S980-14.5 proX LX Dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38c3, "Y980 DUAL", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38c7, "Thinkbook 13x Gen 4", ALC287_FIXUP_CS35L41_I2C_4),
-       SND_PCI_QUIRK(0x17aa, 0x38c8, "Thinkbook 13x Gen 4", ALC287_FIXUP_CS35L41_I2C_4),
-       SND_PCI_QUIRK(0x17aa, 0x38cb, "Y790 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38cd, "Y790 VECO DUAL", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38d2, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x38d3, "Yoga S990-16 Pro IMH YC Dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38d4, "Yoga S990-16 Pro IMH VECO Dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38d5, "Yoga S990-16 Pro IMH YC Quad", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38d6, "Yoga S990-16 Pro IMH VECO Quad", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38d7, "Lenovo Yoga 9 14IMH9", ALC287_FIXUP_YOGA9_14IMH9_BASS_SPK_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x38df, "Yoga Y990 Intel YC Dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38e0, "Yoga Y990 Intel VECO Dual", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38f8, "Yoga Book 9i", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38df, "Y990 YG DUAL", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x38f9, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x38fa, "Thinkbook 16P Gen5", ALC287_FIXUP_MG_RTKC_CSAMP_CS35L41_I2C_THINKPAD),
-       SND_PCI_QUIRK(0x17aa, 0x38fd, "ThinkBook plus Gen5 Hybrid", ALC287_FIXUP_TAS2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x390d, "Lenovo Yoga Pro 7 14ASP10", ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x3913, "Lenovo 145", ALC236_FIXUP_LENOVO_INV_DMIC),
-       SND_PCI_QUIRK(0x17aa, 0x391f, "Yoga S990-16 pro Quad YC Quad", ALC287_FIXUP_TXNW2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3920, "Yoga S990-16 pro Quad VECO Quad", ALC287_FIXUP_TXNW2781_I2C),
-       SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
-       SND_PCI_QUIRK(0x17aa, 0x3978, "Lenovo B50-70", ALC269_FIXUP_DMIC_THINKPAD_ACPI),
-       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K),
-       SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
-       SND_PCI_QUIRK(0x17aa, 0x501e, "Thinkpad L440", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x5034, "Thinkpad T450", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x5036, "Thinkpad T450s", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x503c, "Thinkpad L450", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x504a, "ThinkPad X260", ALC292_FIXUP_TPT440_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x504b, "Thinkpad", ALC293_FIXUP_LENOVO_SPK_NOISE),
-       SND_PCI_QUIRK(0x17aa, 0x5050, "Thinkpad T560p", ALC292_FIXUP_TPT460),
-       SND_PCI_QUIRK(0x17aa, 0x5051, "Thinkpad L460", ALC292_FIXUP_TPT460),
-       SND_PCI_QUIRK(0x17aa, 0x5053, "Thinkpad T460", ALC292_FIXUP_TPT460),
-       SND_PCI_QUIRK(0x17aa, 0x505d, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x505f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x5062, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x508b, "Thinkpad X12 Gen 1", ALC287_FIXUP_LEGION_15IMHG05_SPEAKERS),
-       SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x17aa, 0x511e, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x511f, "Thinkpad", ALC298_FIXUP_TPT470_DOCK),
-       SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD),
-       SND_PCI_QUIRK(0x17aa, 0x9e56, "Lenovo ZhaoYang CF4620Z", ALC286_FIXUP_SONY_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1849, 0x0269, "Positivo Master C6400", ALC269VB_FIXUP_ASUS_ZENBOOK),
-       SND_PCI_QUIRK(0x1849, 0x1233, "ASRock NUC Box 1100", ALC233_FIXUP_NO_AUDIO_JACK),
-       SND_PCI_QUIRK(0x1849, 0xa233, "Positivo Master C6300", ALC269_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1854, 0x0440, "LG CQ6", ALC256_FIXUP_HEADPHONE_AMP_VOL),
-       SND_PCI_QUIRK(0x1854, 0x0441, "LG CQ6 AIO", ALC256_FIXUP_HEADPHONE_AMP_VOL),
-       SND_PCI_QUIRK(0x1854, 0x0488, "LG gram 16 (16Z90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
-       SND_PCI_QUIRK(0x1854, 0x048a, "LG gram 17 (17ZD90R)", ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS),
-       SND_PCI_QUIRK(0x19e5, 0x3204, "Huawei MACH-WX9", ALC256_FIXUP_HUAWEI_MACH_WX9_PINS),
-       SND_PCI_QUIRK(0x19e5, 0x320f, "Huawei WRT-WX9 ", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x19e5, 0x3212, "Huawei KLV-WX9 ", ALC256_FIXUP_ACER_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1b35, 0x1235, "CZC B20", ALC269_FIXUP_CZC_B20),
-       SND_PCI_QUIRK(0x1b35, 0x1236, "CZC TMI", ALC269_FIXUP_CZC_TMI),
-       SND_PCI_QUIRK(0x1b35, 0x1237, "CZC L101", ALC269_FIXUP_CZC_L101),
-       SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */
-       SND_PCI_QUIRK(0x1c06, 0x2013, "Lemote A1802", ALC269_FIXUP_LEMOTE_A1802),
-       SND_PCI_QUIRK(0x1c06, 0x2015, "Lemote A190X", ALC269_FIXUP_LEMOTE_A190X),
-       SND_PCI_QUIRK(0x1c6c, 0x122a, "Positivo N14AP7", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x1c6c, 0x1251, "Positivo N14KP6-TG", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1d05, 0x1132, "TongFang PHxTxX1", ALC256_FIXUP_SET_COEF_DEFAULTS),
-       SND_PCI_QUIRK(0x1d05, 0x1096, "TongFang GMxMRxx", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1d05, 0x1100, "TongFang GKxNRxx", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1d05, 0x1111, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1d05, 0x1119, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1d05, 0x1129, "TongFang GMxZGxx", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1d05, 0x1147, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1d05, 0x115c, "TongFang GMxTGxx", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1d05, 0x121b, "TongFang GMxAGxx", ALC269_FIXUP_NO_SHUTUP),
-       SND_PCI_QUIRK(0x1d05, 0x1387, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1d05, 0x1409, "TongFang GMxIXxx", ALC2XX_FIXUP_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1d17, 0x3288, "Haier Boyue G42", ALC269VC_FIXUP_ACER_VCOPPERBOX_PINS),
-       SND_PCI_QUIRK(0x1d72, 0x1602, "RedmiBook", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1d72, 0x1701, "XiaomiNotebook Pro", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1d72, 0x1901, "RedmiBook 14", ALC256_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1d72, 0x1945, "Redmi G", ALC256_FIXUP_ASUS_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1d72, 0x1947, "RedmiBook Air", ALC255_FIXUP_XIAOMI_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1f66, 0x0105, "Ayaneo Portable Game Player", ALC287_FIXUP_CS35L41_I2C_2),
-       SND_PCI_QUIRK(0x2014, 0x800a, "Positivo ARN50", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x2782, 0x0214, "VAIO VJFE-CL", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
-       SND_PCI_QUIRK(0x2782, 0x0228, "Infinix ZERO BOOK 13", ALC269VB_FIXUP_INFINIX_ZERO_BOOK_13),
-       SND_PCI_QUIRK(0x2782, 0x0232, "CHUWI CoreBook XPro", ALC269VB_FIXUP_CHUWI_COREBOOK_XPRO),
-       SND_PCI_QUIRK(0x2782, 0x1407, "Positivo P15X", ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC),
-       SND_PCI_QUIRK(0x2782, 0x1409, "Positivo K116J", ALC269_FIXUP_POSITIVO_P15X_HEADSET_MIC),
-       SND_PCI_QUIRK(0x2782, 0x1701, "Infinix Y4 Max", ALC269VC_FIXUP_INFINIX_Y4_MAX),
-       SND_PCI_QUIRK(0x2782, 0x1705, "MEDION E15433", ALC269VC_FIXUP_INFINIX_Y4_MAX),
-       SND_PCI_QUIRK(0x2782, 0x1707, "Vaio VJFE-ADL", ALC298_FIXUP_SPK_VOLUME),
-       SND_PCI_QUIRK(0x2782, 0x4900, "MEDION E15443", ALC233_FIXUP_MEDION_MTL_SPK),
-       SND_PCI_QUIRK(0x8086, 0x2074, "Intel NUC 8", ALC233_FIXUP_INTEL_NUC8_DMIC),
-       SND_PCI_QUIRK(0x8086, 0x2080, "Intel NUC 8 Rugged", ALC256_FIXUP_INTEL_NUC8_RUGGED),
-       SND_PCI_QUIRK(0x8086, 0x2081, "Intel NUC 10", ALC256_FIXUP_INTEL_NUC10),
-       SND_PCI_QUIRK(0x8086, 0x3038, "Intel NUC 13", ALC295_FIXUP_CHROME_BOOK),
-       SND_PCI_QUIRK(0xf111, 0x0001, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0xf111, 0x0006, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0xf111, 0x0009, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0xf111, 0x000c, "Framework Laptop", ALC295_FIXUP_FRAMEWORK_LAPTOP_MIC_NO_PRESENCE),
-
-#if 0
-       /* Below is a quirk table taken from the old code.
-        * Basically the device should work as is without the fixup table.
-        * If BIOS doesn't give a proper info, enable the corresponding
-        * fixup entry.
-        */
-       SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A",
-                     ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1013, "ASUS N61Da", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1143, "ASUS B53f", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1183, "ASUS K72DR", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x11b3, "ASUS K52DR", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x11e3, "ASUS U33Jc", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80Jt", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82JV", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x12d3, "ASUS N61Jv", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1593, "ASUS N51Vn", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x152d, 0x1778, "Quanta ON1", ALC269_FIXUP_DMIC),
-       SND_PCI_QUIRK(0x17aa, 0x3be9, "Quanta Wistron", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_AMIC),
-       SND_PCI_QUIRK(0x17ff, 0x059a, "Quanta EL3", ALC269_FIXUP_DMIC),
-       SND_PCI_QUIRK(0x17ff, 0x059b, "Quanta JR1", ALC269_FIXUP_DMIC),
-#endif
-       {}
-};
-
-static const struct hda_quirk alc269_fixup_vendor_tbl[] = {
-       SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC),
-       SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED),
-       SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO),
-       SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo XPAD", ALC269_FIXUP_LENOVO_XPAD_ACPI),
-       SND_PCI_QUIRK_VENDOR(0x19e5, "Huawei Matebook", ALC255_FIXUP_MIC_MUTE_LED),
-       {}
-};
-
-static const struct hda_model_fixup alc269_fixup_models[] = {
-       {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"},
-       {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"},
-       {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"},
-       {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"},
-       {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"},
-       {.id = ALC269_FIXUP_HEADSET_MIC, .name = "headset-mic"},
-       {.id = ALC269_FIXUP_HEADSET_MODE, .name = "headset-mode"},
-       {.id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC, .name = "headset-mode-no-hp-mic"},
-       {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"},
-       {.id = ALC269_FIXUP_LENOVO_DOCK_LIMIT_BOOST, .name = "lenovo-dock-limit-boost"},
-       {.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
-       {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic1-led"},
-       {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
-       {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"},
-       {.id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, .name = "dell-headset3"},
-       {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE, .name = "dell-headset4"},
-       {.id = ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET, .name = "dell-headset4-quiet"},
-       {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
-       {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
-       {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"},
-       {.id = ALC292_FIXUP_TPT440, .name = "tpt440"},
-       {.id = ALC292_FIXUP_TPT460, .name = "tpt460"},
-       {.id = ALC298_FIXUP_TPT470_DOCK_FIX, .name = "tpt470-dock-fix"},
-       {.id = ALC298_FIXUP_TPT470_DOCK, .name = "tpt470-dock"},
-       {.id = ALC233_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
-       {.id = ALC700_FIXUP_INTEL_REFERENCE, .name = "alc700-ref"},
-       {.id = ALC269_FIXUP_SONY_VAIO, .name = "vaio"},
-       {.id = ALC269_FIXUP_DELL_M101Z, .name = "dell-m101z"},
-       {.id = ALC269_FIXUP_ASUS_G73JW, .name = "asus-g73jw"},
-       {.id = ALC269_FIXUP_LENOVO_EAPD, .name = "lenovo-eapd"},
-       {.id = ALC275_FIXUP_SONY_HWEQ, .name = "sony-hweq"},
-       {.id = ALC269_FIXUP_PCM_44K, .name = "pcm44k"},
-       {.id = ALC269_FIXUP_LIFEBOOK, .name = "lifebook"},
-       {.id = ALC269_FIXUP_LIFEBOOK_EXTMIC, .name = "lifebook-extmic"},
-       {.id = ALC269_FIXUP_LIFEBOOK_HP_PIN, .name = "lifebook-hp-pin"},
-       {.id = ALC255_FIXUP_LIFEBOOK_U7x7_HEADSET_MIC, .name = "lifebook-u7x7"},
-       {.id = ALC269VB_FIXUP_AMIC, .name = "alc269vb-amic"},
-       {.id = ALC269VB_FIXUP_DMIC, .name = "alc269vb-dmic"},
-       {.id = ALC269_FIXUP_HP_MUTE_LED_MIC1, .name = "hp-mute-led-mic1"},
-       {.id = ALC269_FIXUP_HP_MUTE_LED_MIC2, .name = "hp-mute-led-mic2"},
-       {.id = ALC269_FIXUP_HP_MUTE_LED_MIC3, .name = "hp-mute-led-mic3"},
-       {.id = ALC269_FIXUP_HP_GPIO_MIC1_LED, .name = "hp-gpio-mic1"},
-       {.id = ALC269_FIXUP_HP_LINE1_MIC1_LED, .name = "hp-line1-mic1"},
-       {.id = ALC269_FIXUP_NO_SHUTUP, .name = "noshutup"},
-       {.id = ALC286_FIXUP_SONY_MIC_NO_PRESENCE, .name = "sony-nomic"},
-       {.id = ALC269_FIXUP_ASPIRE_HEADSET_MIC, .name = "aspire-headset-mic"},
-       {.id = ALC269_FIXUP_ASUS_X101, .name = "asus-x101"},
-       {.id = ALC271_FIXUP_HP_GATE_MIC_JACK, .name = "acer-ao7xx"},
-       {.id = ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572, .name = "acer-aspire-e1"},
-       {.id = ALC269_FIXUP_ACER_AC700, .name = "acer-ac700"},
-       {.id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST, .name = "limit-mic-boost"},
-       {.id = ALC269VB_FIXUP_ASUS_ZENBOOK, .name = "asus-zenbook"},
-       {.id = ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A, .name = "asus-zenbook-ux31a"},
-       {.id = ALC269VB_FIXUP_ORDISSIMO_EVE2, .name = "ordissimo"},
-       {.id = ALC282_FIXUP_ASUS_TX300, .name = "asus-tx300"},
-       {.id = ALC283_FIXUP_INT_MIC, .name = "alc283-int-mic"},
-       {.id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK, .name = "mono-speakers"},
-       {.id = ALC290_FIXUP_SUBWOOFER_HSJACK, .name = "alc290-subwoofer"},
-       {.id = ALC269_FIXUP_THINKPAD_ACPI, .name = "thinkpad"},
-       {.id = ALC269_FIXUP_LENOVO_XPAD_ACPI, .name = "lenovo-xpad-led"},
-       {.id = ALC269_FIXUP_DMIC_THINKPAD_ACPI, .name = "dmic-thinkpad"},
-       {.id = ALC255_FIXUP_ACER_MIC_NO_PRESENCE, .name = "alc255-acer"},
-       {.id = ALC255_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc255-asus"},
-       {.id = ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc255-dell1"},
-       {.id = ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "alc255-dell2"},
-       {.id = ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc293-dell1"},
-       {.id = ALC283_FIXUP_HEADSET_MIC, .name = "alc283-headset"},
-       {.id = ALC255_FIXUP_MIC_MUTE_LED, .name = "alc255-dell-mute"},
-       {.id = ALC282_FIXUP_ASPIRE_V5_PINS, .name = "aspire-v5"},
-       {.id = ALC269VB_FIXUP_ASPIRE_E1_COEF, .name = "aspire-e1-coef"},
-       {.id = ALC280_FIXUP_HP_GPIO4, .name = "hp-gpio4"},
-       {.id = ALC286_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
-       {.id = ALC280_FIXUP_HP_GPIO2_MIC_HOTKEY, .name = "hp-gpio2-hotkey"},
-       {.id = ALC280_FIXUP_HP_DOCK_PINS, .name = "hp-dock-pins"},
-       {.id = ALC269_FIXUP_HP_DOCK_GPIO_MIC1_LED, .name = "hp-dock-gpio-mic"},
-       {.id = ALC280_FIXUP_HP_9480M, .name = "hp-9480m"},
-       {.id = ALC288_FIXUP_DELL_HEADSET_MODE, .name = "alc288-dell-headset"},
-       {.id = ALC288_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc288-dell1"},
-       {.id = ALC288_FIXUP_DELL_XPS_13, .name = "alc288-dell-xps13"},
-       {.id = ALC292_FIXUP_DELL_E7X, .name = "dell-e7x"},
-       {.id = ALC293_FIXUP_DISABLE_AAMIX_MULTIJACK, .name = "alc293-dell"},
-       {.id = ALC298_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc298-dell1"},
-       {.id = ALC298_FIXUP_DELL_AIO_MIC_NO_PRESENCE, .name = "alc298-dell-aio"},
-       {.id = ALC275_FIXUP_DELL_XPS, .name = "alc275-dell-xps"},
-       {.id = ALC293_FIXUP_LENOVO_SPK_NOISE, .name = "lenovo-spk-noise"},
-       {.id = ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, .name = "lenovo-hotkey"},
-       {.id = ALC255_FIXUP_DELL_SPK_NOISE, .name = "dell-spk-noise"},
-       {.id = ALC225_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "alc225-dell1"},
-       {.id = ALC295_FIXUP_DISABLE_DAC3, .name = "alc295-disable-dac3"},
-       {.id = ALC285_FIXUP_SPEAKER2_TO_DAC1, .name = "alc285-speaker2-to-dac1"},
-       {.id = ALC280_FIXUP_HP_HEADSET_MIC, .name = "alc280-hp-headset"},
-       {.id = ALC221_FIXUP_HP_FRONT_MIC, .name = "alc221-hp-mic"},
-       {.id = ALC298_FIXUP_SPK_VOLUME, .name = "alc298-spk-volume"},
-       {.id = ALC256_FIXUP_DELL_INSPIRON_7559_SUBWOOFER, .name = "dell-inspiron-7559"},
-       {.id = ALC269_FIXUP_ATIV_BOOK_8, .name = "ativ-book"},
-       {.id = ALC221_FIXUP_HP_MIC_NO_PRESENCE, .name = "alc221-hp-mic"},
-       {.id = ALC256_FIXUP_ASUS_HEADSET_MODE, .name = "alc256-asus-headset"},
-       {.id = ALC256_FIXUP_ASUS_MIC, .name = "alc256-asus-mic"},
-       {.id = ALC256_FIXUP_ASUS_AIO_GPIO2, .name = "alc256-asus-aio"},
-       {.id = ALC233_FIXUP_ASUS_MIC_NO_PRESENCE, .name = "alc233-asus"},
-       {.id = ALC233_FIXUP_EAPD_COEF_AND_MIC_NO_PRESENCE, .name = "alc233-eapd"},
-       {.id = ALC294_FIXUP_LENOVO_MIC_LOCATION, .name = "alc294-lenovo-mic"},
-       {.id = ALC225_FIXUP_DELL_WYSE_MIC_NO_PRESENCE, .name = "alc225-wyse"},
-       {.id = ALC274_FIXUP_DELL_AIO_LINEOUT_VERB, .name = "alc274-dell-aio"},
-       {.id = ALC255_FIXUP_DUMMY_LINEOUT_VERB, .name = "alc255-dummy-lineout"},
-       {.id = ALC255_FIXUP_DELL_HEADSET_MIC, .name = "alc255-dell-headset"},
-       {.id = ALC295_FIXUP_HP_X360, .name = "alc295-hp-x360"},
-       {.id = ALC225_FIXUP_HEADSET_JACK, .name = "alc-headset-jack"},
-       {.id = ALC295_FIXUP_CHROME_BOOK, .name = "alc-chrome-book"},
-       {.id = ALC256_FIXUP_CHROME_BOOK, .name = "alc-2024y-chromebook"},
-       {.id = ALC299_FIXUP_PREDATOR_SPK, .name = "predator-spk"},
-       {.id = ALC298_FIXUP_HUAWEI_MBX_STEREO, .name = "huawei-mbx-stereo"},
-       {.id = ALC256_FIXUP_MEDION_HEADSET_NO_PRESENCE, .name = "alc256-medion-headset"},
-       {.id = ALC298_FIXUP_SAMSUNG_AMP, .name = "alc298-samsung-amp"},
-       {.id = ALC298_FIXUP_SAMSUNG_AMP_V2_2_AMPS, .name = "alc298-samsung-amp-v2-2-amps"},
-       {.id = ALC298_FIXUP_SAMSUNG_AMP_V2_4_AMPS, .name = "alc298-samsung-amp-v2-4-amps"},
-       {.id = ALC256_FIXUP_SAMSUNG_HEADPHONE_VERY_QUIET, .name = "alc256-samsung-headphone"},
-       {.id = ALC255_FIXUP_XIAOMI_HEADSET_MIC, .name = "alc255-xiaomi-headset"},
-       {.id = ALC274_FIXUP_HP_MIC, .name = "alc274-hp-mic-detect"},
-       {.id = ALC245_FIXUP_HP_X360_AMP, .name = "alc245-hp-x360-amp"},
-       {.id = ALC295_FIXUP_HP_OMEN, .name = "alc295-hp-omen"},
-       {.id = ALC285_FIXUP_HP_SPECTRE_X360, .name = "alc285-hp-spectre-x360"},
-       {.id = ALC285_FIXUP_HP_SPECTRE_X360_EB1, .name = "alc285-hp-spectre-x360-eb1"},
-       {.id = ALC285_FIXUP_HP_SPECTRE_X360_DF1, .name = "alc285-hp-spectre-x360-df1"},
-       {.id = ALC285_FIXUP_HP_ENVY_X360, .name = "alc285-hp-envy-x360"},
-       {.id = ALC287_FIXUP_IDEAPAD_BASS_SPK_AMP, .name = "alc287-ideapad-bass-spk-amp"},
-       {.id = ALC287_FIXUP_YOGA9_14IAP7_BASS_SPK_PIN, .name = "alc287-yoga9-bass-spk-pin"},
-       {.id = ALC623_FIXUP_LENOVO_THINKSTATION_P340, .name = "alc623-lenovo-thinkstation-p340"},
-       {.id = ALC255_FIXUP_ACER_HEADPHONE_AND_MIC, .name = "alc255-acer-headphone-and-mic"},
-       {.id = ALC285_FIXUP_HP_GPIO_AMP_INIT, .name = "alc285-hp-amp-init"},
-       {.id = ALC236_FIXUP_LENOVO_INV_DMIC, .name = "alc236-fixup-lenovo-inv-mic"},
-       {.id = ALC2XX_FIXUP_HEADSET_MIC, .name = "alc2xx-fixup-headset-mic"},
-       {}
-};
-#define ALC225_STANDARD_PINS \
-       {0x21, 0x04211020}
-
-#define ALC256_STANDARD_PINS \
-       {0x12, 0x90a60140}, \
-       {0x14, 0x90170110}, \
-       {0x21, 0x02211020}
-
-#define ALC282_STANDARD_PINS \
-       {0x14, 0x90170110}
-
-#define ALC290_STANDARD_PINS \
-       {0x12, 0x99a30130}
-
-#define ALC292_STANDARD_PINS \
-       {0x14, 0x90170110}, \
-       {0x15, 0x0221401f}
-
-#define ALC295_STANDARD_PINS \
-       {0x12, 0xb7a60130}, \
-       {0x14, 0x90170110}, \
-       {0x21, 0x04211020}
-
-#define ALC298_STANDARD_PINS \
-       {0x12, 0x90a60130}, \
-       {0x21, 0x03211020}
-
-static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = {
-       SND_HDA_PIN_QUIRK(0x10ec0221, 0x103c, "HP Workstation", ALC221_FIXUP_HP_HEADSET_MIC,
-               {0x14, 0x01014020},
-               {0x17, 0x90170110},
-               {0x18, 0x02a11030},
-               {0x19, 0x0181303F},
-               {0x21, 0x0221102f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1025, "Acer", ALC255_FIXUP_ACER_MIC_NO_PRESENCE,
-               {0x12, 0x90a601c0},
-               {0x14, 0x90171120},
-               {0x21, 0x02211030}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
-               {0x14, 0x90170110},
-               {0x1b, 0x90a70130},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1043, "ASUS", ALC255_FIXUP_ASUS_MIC_NO_PRESENCE,
-               {0x1a, 0x90a70130},
-               {0x1b, 0x90170110},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC225_STANDARD_PINS,
-               {0x12, 0xb7a60130},
-               {0x14, 0x901701a0}),
-       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC225_STANDARD_PINS,
-               {0x12, 0xb7a60130},
-               {0x14, 0x901701b0}),
-       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC225_STANDARD_PINS,
-               {0x12, 0xb7a60150},
-               {0x14, 0x901701a0}),
-       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC225_STANDARD_PINS,
-               {0x12, 0xb7a60150},
-               {0x14, 0x901701b0}),
-       SND_HDA_PIN_QUIRK(0x10ec0225, 0x1028, "Dell", ALC225_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC225_STANDARD_PINS,
-               {0x12, 0xb7a60130},
-               {0x1b, 0x90170110}),
-       SND_HDA_PIN_QUIRK(0x10ec0233, 0x8086, "Intel NUC Skull Canyon", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x1b, 0x01111010},
-               {0x1e, 0x01451130},
-               {0x21, 0x02211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY,
-               {0x12, 0x90a60140},
-               {0x14, 0x90170110},
-               {0x19, 0x02a11030},
-               {0x21, 0x02211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
-               {0x14, 0x90170110},
-               {0x19, 0x02a11030},
-               {0x1a, 0x02a11040},
-               {0x1b, 0x01014020},
-               {0x21, 0x0221101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
-               {0x14, 0x90170110},
-               {0x19, 0x02a11030},
-               {0x1a, 0x02a11040},
-               {0x1b, 0x01011020},
-               {0x21, 0x0221101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC294_FIXUP_LENOVO_MIC_LOCATION,
-               {0x14, 0x90170110},
-               {0x19, 0x02a11020},
-               {0x1a, 0x02a11030},
-               {0x21, 0x0221101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC236_FIXUP_DELL_AIO_HEADSET_MIC,
-               {0x21, 0x02211010}),
-       SND_HDA_PIN_QUIRK(0x10ec0236, 0x103c, "HP", ALC256_FIXUP_HP_HEADSET_MIC,
-               {0x14, 0x90170110},
-               {0x19, 0x02a11020},
-               {0x21, 0x02211030}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE,
-               {0x14, 0x90170110},
-               {0x21, 0x02211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x14, 0x90170130},
-               {0x21, 0x02211040}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60140},
-               {0x14, 0x90170110},
-               {0x21, 0x02211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60160},
-               {0x14, 0x90170120},
-               {0x21, 0x02211030}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x14, 0x90170110},
-               {0x1b, 0x02011020},
-               {0x21, 0x0221101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x14, 0x90170110},
-               {0x1b, 0x01011020},
-               {0x21, 0x0221101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x14, 0x90170130},
-               {0x1b, 0x01014020},
-               {0x21, 0x0221103f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x14, 0x90170130},
-               {0x1b, 0x01011020},
-               {0x21, 0x0221103f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x14, 0x90170130},
-               {0x1b, 0x02011020},
-               {0x21, 0x0221103f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x14, 0x90170150},
-               {0x1b, 0x02011020},
-               {0x21, 0x0221105f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x14, 0x90170110},
-               {0x1b, 0x01014020},
-               {0x21, 0x0221101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60160},
-               {0x14, 0x90170120},
-               {0x17, 0x90170140},
-               {0x21, 0x0321102f}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60160},
-               {0x14, 0x90170130},
-               {0x21, 0x02211040}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60160},
-               {0x14, 0x90170140},
-               {0x21, 0x02211050}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60170},
-               {0x14, 0x90170120},
-               {0x21, 0x02211030}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60170},
-               {0x14, 0x90170130},
-               {0x21, 0x02211040}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60170},
-               {0x14, 0x90171130},
-               {0x21, 0x02211040}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60170},
-               {0x14, 0x90170140},
-               {0x21, 0x02211050}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5548", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60180},
-               {0x14, 0x90170130},
-               {0x21, 0x02211040}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell Inspiron 5565", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60180},
-               {0x14, 0x90170120},
-               {0x21, 0x02211030}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x1b, 0x01011020},
-               {0x21, 0x02211010}),
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
-               {0x14, 0x90170110},
-               {0x1b, 0x90a70130},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC,
-               {0x14, 0x90170110},
-               {0x1b, 0x90a70130},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
-               {0x12, 0x90a60130},
-               {0x14, 0x90170110},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
-               {0x12, 0x90a60130},
-               {0x14, 0x90170110},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC256_FIXUP_ASUS_MIC_NO_PRESENCE,
-               {0x1a, 0x90a70130},
-               {0x1b, 0x90170110},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x103c, "HP", ALC256_FIXUP_HP_HEADSET_MIC,
-               {0x14, 0x90170110},
-               {0x19, 0x02a11020},
-               {0x21, 0x0221101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0274, 0x103c, "HP", ALC274_FIXUP_HP_HEADSET_MIC,
-               {0x17, 0x90170110},
-               {0x19, 0x03a11030},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC280_FIXUP_HP_GPIO4,
-               {0x12, 0x90a60130},
-               {0x14, 0x90170110},
-               {0x15, 0x0421101f},
-               {0x1a, 0x04a11020}),
-       SND_HDA_PIN_QUIRK(0x10ec0280, 0x103c, "HP", ALC269_FIXUP_HP_GPIO_MIC1_LED,
-               {0x12, 0x90a60140},
-               {0x14, 0x90170110},
-               {0x15, 0x0421101f},
-               {0x18, 0x02811030},
-               {0x1a, 0x04a1103f},
-               {0x1b, 0x02011020}),
-       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP 15 Touchsmart", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x99a30130},
-               {0x19, 0x03a11020},
-               {0x21, 0x0321101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x99a30130},
-               {0x19, 0x03a11020},
-               {0x21, 0x03211040}),
-       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x99a30130},
-               {0x19, 0x03a11030},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x99a30130},
-               {0x19, 0x04a11020},
-               {0x21, 0x0421101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0282, 0x103c, "HP", ALC269_FIXUP_HP_LINE1_MIC1_LED,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x90a60140},
-               {0x19, 0x04a11030},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0282, 0x1025, "Acer", ALC282_FIXUP_ACER_DISABLE_LINEOUT,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x90a609c0},
-               {0x18, 0x03a11830},
-               {0x19, 0x04a19831},
-               {0x1a, 0x0481303f},
-               {0x1b, 0x04211020},
-               {0x21, 0x0321101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0282, 0x1025, "Acer", ALC282_FIXUP_ACER_DISABLE_LINEOUT,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x90a60940},
-               {0x18, 0x03a11830},
-               {0x19, 0x04a19831},
-               {0x1a, 0x0481303f},
-               {0x1b, 0x04211020},
-               {0x21, 0x0321101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x90a60130},
-               {0x21, 0x0321101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60160},
-               {0x14, 0x90170120},
-               {0x21, 0x02211030}),
-       SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC282_STANDARD_PINS,
-               {0x12, 0x90a60130},
-               {0x19, 0x03a11020},
-               {0x21, 0x0321101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE,
-               {0x12, 0x90a60130},
-               {0x14, 0x90170110},
-               {0x19, 0x04a11040},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_LENOVO_PC_BEEP_IN_NOISE,
-               {0x14, 0x90170110},
-               {0x19, 0x04a11040},
-               {0x1d, 0x40600001},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0285, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_NO_BASS_SPK_HEADSET_JACK,
-               {0x14, 0x90170110},
-               {0x19, 0x04a11040},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC285_FIXUP_THINKPAD_HEADSET_JACK,
-               {0x14, 0x90170110},
-               {0x17, 0x90170111},
-               {0x19, 0x03a11030},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC287_FIXUP_THINKPAD_I2S_SPK,
-               {0x17, 0x90170110},
-               {0x19, 0x03a11030},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0287, 0x17aa, "Lenovo", ALC287_FIXUP_THINKPAD_I2S_SPK,
-               {0x17, 0x90170110}, /* 0x231f with RTK I2S AMP */
-               {0x19, 0x04a11040},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0286, 0x1025, "Acer", ALC286_FIXUP_ACER_AIO_MIC_NO_PRESENCE,
-               {0x12, 0x90a60130},
-               {0x17, 0x90170110},
-               {0x21, 0x02211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0288, 0x1028, "Dell", ALC288_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x12, 0x90a60120},
-               {0x14, 0x90170110},
-               {0x21, 0x0321101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC290_STANDARD_PINS,
-               {0x15, 0x04211040},
-               {0x18, 0x90170112},
-               {0x1a, 0x04a11020}),
-       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC290_STANDARD_PINS,
-               {0x15, 0x04211040},
-               {0x18, 0x90170110},
-               {0x1a, 0x04a11020}),
-       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC290_STANDARD_PINS,
-               {0x15, 0x0421101f},
-               {0x1a, 0x04a11020}),
-       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC290_STANDARD_PINS,
-               {0x15, 0x04211020},
-               {0x1a, 0x04a11040}),
-       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC290_STANDARD_PINS,
-               {0x14, 0x90170110},
-               {0x15, 0x04211020},
-               {0x1a, 0x04a11040}),
-       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC290_STANDARD_PINS,
-               {0x14, 0x90170110},
-               {0x15, 0x04211020},
-               {0x1a, 0x04a11020}),
-       SND_HDA_PIN_QUIRK(0x10ec0290, 0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1,
-               ALC290_STANDARD_PINS,
-               {0x14, 0x90170110},
-               {0x15, 0x0421101f},
-               {0x1a, 0x04a11020}),
-       SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
-               ALC292_STANDARD_PINS,
-               {0x12, 0x90a60140},
-               {0x16, 0x01014020},
-               {0x19, 0x01a19030}),
-       SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE,
-               ALC292_STANDARD_PINS,
-               {0x12, 0x90a60140},
-               {0x16, 0x01014020},
-               {0x18, 0x02a19031},
-               {0x19, 0x01a1903e}),
-       SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE,
-               ALC292_STANDARD_PINS,
-               {0x12, 0x90a60140}),
-       SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC292_STANDARD_PINS,
-               {0x13, 0x90a60140},
-               {0x16, 0x21014020},
-               {0x19, 0x21a19030}),
-       SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC292_STANDARD_PINS,
-               {0x13, 0x90a60140}),
-       SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_HPE,
-               {0x17, 0x90170110},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_MIC,
-               {0x14, 0x90170110},
-               {0x1b, 0x90a70130},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_SPK,
-               {0x12, 0x90a60130},
-               {0x17, 0x90170110},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0294, 0x1043, "ASUS", ALC294_FIXUP_ASUS_SPK,
-               {0x12, 0x90a60130},
-               {0x17, 0x90170110},
-               {0x21, 0x04211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1043, "ASUS", ALC294_FIXUP_ASUS_SPK,
-               {0x12, 0x90a60130},
-               {0x17, 0x90170110},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1043, "ASUS", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
-               {0x12, 0x90a60120},
-               {0x17, 0x90170110},
-               {0x21, 0x04211030}),
-       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1043, "ASUS", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
-               {0x12, 0x90a60130},
-               {0x17, 0x90170110},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1043, "ASUS", ALC295_FIXUP_ASUS_MIC_NO_PRESENCE,
-               {0x12, 0x90a60130},
-               {0x17, 0x90170110},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC298_STANDARD_PINS,
-               {0x17, 0x90170110}),
-       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC298_STANDARD_PINS,
-               {0x17, 0x90170140}),
-       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_DELL1_MIC_NO_PRESENCE,
-               ALC298_STANDARD_PINS,
-               {0x17, 0x90170150}),
-       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_SPK_VOLUME,
-               {0x12, 0xb7a60140},
-               {0x13, 0xb7a60150},
-               {0x17, 0x90170110},
-               {0x1a, 0x03011020},
-               {0x21, 0x03211030}),
-       SND_HDA_PIN_QUIRK(0x10ec0298, 0x1028, "Dell", ALC298_FIXUP_ALIENWARE_MIC_NO_PRESENCE,
-               {0x12, 0xb7a60140},
-               {0x17, 0x90170110},
-               {0x1a, 0x03a11030},
-               {0x21, 0x03211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0299, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
-               ALC225_STANDARD_PINS,
-               {0x12, 0xb7a60130},
-               {0x17, 0x90170110}),
-       SND_HDA_PIN_QUIRK(0x10ec0623, 0x17aa, "Lenovo", ALC283_FIXUP_HEADSET_MIC,
-               {0x14, 0x01014010},
-               {0x17, 0x90170120},
-               {0x18, 0x02a11030},
-               {0x19, 0x02a1103f},
-               {0x21, 0x0221101f}),
-       {}
-};
-
-/* This is the fallback pin_fixup_tbl for alc269 family, to make the tbl match
- * more machines, don't need to match all valid pins, just need to match
- * all the pins defined in the tbl. Just because of this reason, it is possible
- * that a single machine matches multiple tbls, so there is one limitation:
- *   at most one tbl is allowed to define for the same vendor and same codec
- */
-static const struct snd_hda_pin_quirk alc269_fallback_pin_fixup_tbl[] = {
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1025, "Acer", ALC2XX_FIXUP_HEADSET_MIC,
-               {0x19, 0x40000000}),
-       SND_HDA_PIN_QUIRK(0x10ec0289, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE,
-               {0x19, 0x40000000},
-               {0x1b, 0x40000000}),
-       SND_HDA_PIN_QUIRK(0x10ec0295, 0x1028, "Dell", ALC269_FIXUP_DELL4_MIC_NO_PRESENCE_QUIET,
-               {0x19, 0x40000000},
-               {0x1b, 0x40000000}),
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE,
-               {0x19, 0x40000000},
-               {0x1a, 0x40000000}),
-       SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
-               {0x19, 0x40000000},
-               {0x1a, 0x40000000}),
-       SND_HDA_PIN_QUIRK(0x10ec0274, 0x1028, "Dell", ALC269_FIXUP_DELL1_LIMIT_INT_MIC_BOOST,
-               {0x19, 0x40000000},
-               {0x1a, 0x40000000}),
-       SND_HDA_PIN_QUIRK(0x10ec0256, 0x1043, "ASUS", ALC2XX_FIXUP_HEADSET_MIC,
-               {0x19, 0x40000000}),
-       SND_HDA_PIN_QUIRK(0x10ec0255, 0x1558, "Clevo", ALC2XX_FIXUP_HEADSET_MIC,
-               {0x19, 0x40000000}),
-       {}
-};
-
-static void alc269_fill_coef(struct hda_codec *codec)
-{
-       struct alc_spec *spec = codec->spec;
-       int val;
-
-       if (spec->codec_variant != ALC269_TYPE_ALC269VB)
-               return;
-
-       if ((alc_get_coef0(codec) & 0x00ff) < 0x015) {
-               alc_write_coef_idx(codec, 0xf, 0x960b);
-               alc_write_coef_idx(codec, 0xe, 0x8817);
-       }
-
-       if ((alc_get_coef0(codec) & 0x00ff) == 0x016) {
-               alc_write_coef_idx(codec, 0xf, 0x960b);
-               alc_write_coef_idx(codec, 0xe, 0x8814);
-       }
-
-       if ((alc_get_coef0(codec) & 0x00ff) == 0x017) {
-               /* Power up output pin */
-               alc_update_coef_idx(codec, 0x04, 0, 1<<11);
-       }
-
-       if ((alc_get_coef0(codec) & 0x00ff) == 0x018) {
-               val = alc_read_coef_idx(codec, 0xd);
-               if (val != -1 && (val & 0x0c00) >> 10 != 0x1) {
-                       /* Capless ramp up clock control */
-                       alc_write_coef_idx(codec, 0xd, val | (1<<10));
-               }
-               val = alc_read_coef_idx(codec, 0x17);
-               if (val != -1 && (val & 0x01c0) >> 6 != 0x4) {
-                       /* Class D power on reset */
-                       alc_write_coef_idx(codec, 0x17, val | (1<<7));
-               }
-       }
-
-       /* HP */
-       alc_update_coef_idx(codec, 0x4, 0, 1<<11);
-}
-
-/*
- */
-static int patch_alc269(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err;
-
-       err = alc_alloc_spec(codec, 0x0b);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->gen.shared_mic_vref_pin = 0x18;
-       codec->power_save_node = 0;
-       spec->en_3kpull_low = true;
-
-       codec->patch_ops.suspend = alc269_suspend;
-       codec->patch_ops.resume = alc269_resume;
-       spec->shutup = alc_default_shutup;
-       spec->init_hook = alc_default_init;
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0269:
-               spec->codec_variant = ALC269_TYPE_ALC269VA;
-               switch (alc_get_coef0(codec) & 0x00f0) {
-               case 0x0010:
-                       if (codec->bus->pci &&
-                           codec->bus->pci->subsystem_vendor == 0x1025 &&
-                           spec->cdefine.platform_type == 1)
-                               err = alc_codec_rename(codec, "ALC271X");
-                       spec->codec_variant = ALC269_TYPE_ALC269VB;
-                       break;
-               case 0x0020:
-                       if (codec->bus->pci &&
-                           codec->bus->pci->subsystem_vendor == 0x17aa &&
-                           codec->bus->pci->subsystem_device == 0x21f3)
-                               err = alc_codec_rename(codec, "ALC3202");
-                       spec->codec_variant = ALC269_TYPE_ALC269VC;
-                       break;
-               case 0x0030:
-                       spec->codec_variant = ALC269_TYPE_ALC269VD;
-                       break;
-               default:
-                       alc_fix_pll_init(codec, 0x20, 0x04, 15);
-               }
-               if (err < 0)
-                       goto error;
-               spec->shutup = alc269_shutup;
-               spec->init_hook = alc269_fill_coef;
-               alc269_fill_coef(codec);
-               break;
-
-       case 0x10ec0280:
-       case 0x10ec0290:
-               spec->codec_variant = ALC269_TYPE_ALC280;
-               break;
-       case 0x10ec0282:
-               spec->codec_variant = ALC269_TYPE_ALC282;
-               spec->shutup = alc282_shutup;
-               spec->init_hook = alc282_init;
-               break;
-       case 0x10ec0233:
-       case 0x10ec0283:
-               spec->codec_variant = ALC269_TYPE_ALC283;
-               spec->shutup = alc283_shutup;
-               spec->init_hook = alc283_init;
-               break;
-       case 0x10ec0284:
-       case 0x10ec0292:
-               spec->codec_variant = ALC269_TYPE_ALC284;
-               break;
-       case 0x10ec0293:
-               spec->codec_variant = ALC269_TYPE_ALC293;
-               break;
-       case 0x10ec0286:
-       case 0x10ec0288:
-               spec->codec_variant = ALC269_TYPE_ALC286;
-               break;
-       case 0x10ec0298:
-               spec->codec_variant = ALC269_TYPE_ALC298;
-               break;
-       case 0x10ec0235:
-       case 0x10ec0255:
-               spec->codec_variant = ALC269_TYPE_ALC255;
-               spec->shutup = alc256_shutup;
-               spec->init_hook = alc256_init;
-               break;
-       case 0x10ec0230:
-       case 0x10ec0236:
-       case 0x10ec0256:
-       case 0x19e58326:
-               spec->codec_variant = ALC269_TYPE_ALC256;
-               spec->shutup = alc256_shutup;
-               spec->init_hook = alc256_init;
-               spec->gen.mixer_nid = 0; /* ALC256 does not have any loopback mixer path */
-               if (codec->core.vendor_id == 0x10ec0236 &&
-                   codec->bus->pci->vendor != PCI_VENDOR_ID_AMD)
-                       spec->en_3kpull_low = false;
-               break;
-       case 0x10ec0257:
-               spec->codec_variant = ALC269_TYPE_ALC257;
-               spec->shutup = alc256_shutup;
-               spec->init_hook = alc256_init;
-               spec->gen.mixer_nid = 0;
-               spec->en_3kpull_low = false;
-               break;
-       case 0x10ec0215:
-       case 0x10ec0245:
-       case 0x10ec0285:
-       case 0x10ec0289:
-               if (alc_get_coef0(codec) & 0x0010)
-                       spec->codec_variant = ALC269_TYPE_ALC245;
-               else
-                       spec->codec_variant = ALC269_TYPE_ALC215;
-               spec->shutup = alc225_shutup;
-               spec->init_hook = alc225_init;
-               spec->gen.mixer_nid = 0;
-               break;
-       case 0x10ec0225:
-       case 0x10ec0295:
-       case 0x10ec0299:
-               spec->codec_variant = ALC269_TYPE_ALC225;
-               spec->shutup = alc225_shutup;
-               spec->init_hook = alc225_init;
-               spec->gen.mixer_nid = 0; /* no loopback on ALC225, ALC295 and ALC299 */
-               break;
-       case 0x10ec0287:
-               spec->codec_variant = ALC269_TYPE_ALC287;
-               spec->shutup = alc225_shutup;
-               spec->init_hook = alc225_init;
-               spec->gen.mixer_nid = 0; /* no loopback on ALC287 */
-               break;
-       case 0x10ec0234:
-       case 0x10ec0274:
-       case 0x10ec0294:
-               spec->codec_variant = ALC269_TYPE_ALC294;
-               spec->gen.mixer_nid = 0; /* ALC2x4 does not have any loopback mixer path */
-               alc_update_coef_idx(codec, 0x6b, 0x0018, (1<<4) | (1<<3)); /* UAJ MIC Vref control by verb */
-               spec->init_hook = alc294_init;
-               break;
-       case 0x10ec0300:
-               spec->codec_variant = ALC269_TYPE_ALC300;
-               spec->gen.mixer_nid = 0; /* no loopback on ALC300 */
-               break;
-       case 0x10ec0222:
-       case 0x10ec0623:
-               spec->codec_variant = ALC269_TYPE_ALC623;
-               spec->shutup = alc222_shutup;
-               spec->init_hook = alc222_init;
-               break;
-       case 0x10ec0700:
-       case 0x10ec0701:
-       case 0x10ec0703:
-       case 0x10ec0711:
-               spec->codec_variant = ALC269_TYPE_ALC700;
-               spec->gen.mixer_nid = 0; /* ALC700 does not have any loopback mixer path */
-               alc_update_coef_idx(codec, 0x4a, 1 << 15, 0); /* Combo jack auto trigger control */
-               spec->init_hook = alc294_init;
-               break;
-
-       }
-
-       if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) {
-               spec->has_alc5505_dsp = 1;
-               spec->init_hook = alc5505_dsp_init;
-       }
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, alc269_fixup_models,
-                      alc269_fixup_tbl, alc269_fixups);
-       /* FIXME: both TX300 and ROG Strix G17 have the same SSID, and
-        * the quirk breaks the latter (bko#214101).
-        * Clear the wrong entry.
-        */
-       if (codec->fixup_id == ALC282_FIXUP_ASUS_TX300 &&
-           codec->core.vendor_id == 0x10ec0294) {
-               codec_dbg(codec, "Clear wrong fixup for ASUS ROG Strix G17\n");
-               codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
-       }
-
-       snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups, true);
-       snd_hda_pick_pin_fixup(codec, alc269_fallback_pin_fixup_tbl, alc269_fixups, false);
-       snd_hda_pick_fixup(codec, NULL, alc269_fixup_vendor_tbl,
-                          alc269_fixups);
-
-       /*
-        * Check whether ACPI describes companion amplifiers that require
-        * component binding
-        */
-       find_cirrus_companion_amps(codec);
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       alc_auto_parse_customize_define(codec);
-
-       if (has_cdefine_beep(codec))
-               spec->gen.beep_nid = 0x01;
-
-       /* automatic parse from the BIOS config */
-       err = alc269_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!spec->gen.no_analog && spec->gen.beep_nid && spec->gen.mixer_nid) {
-               err = set_beep_amp(spec, spec->gen.mixer_nid, 0x04, HDA_INPUT);
-               if (err < 0)
-                       goto error;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-/*
- * ALC861
- */
-
-static int alc861_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc861_ignore[] = { 0x1d, 0 };
-       static const hda_nid_t alc861_ssids[] = { 0x0e, 0x0f, 0x0b, 0 };
-       return alc_parse_auto_config(codec, alc861_ignore, alc861_ssids);
-}
-
-/* Pin config fixes */
-enum {
-       ALC861_FIXUP_FSC_AMILO_PI1505,
-       ALC861_FIXUP_AMP_VREF_0F,
-       ALC861_FIXUP_NO_JACK_DETECT,
-       ALC861_FIXUP_ASUS_A6RP,
-       ALC660_FIXUP_ASUS_W7J,
-};
-
-/* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */
-static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec,
-                       const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       unsigned int val;
-
-       if (action != HDA_FIXUP_ACT_INIT)
-               return;
-       val = snd_hda_codec_get_pin_target(codec, 0x0f);
-       if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)))
-               val |= AC_PINCTL_IN_EN;
-       val |= AC_PINCTL_VREF_50;
-       snd_hda_set_pin_ctl(codec, 0x0f, val);
-       spec->gen.keep_vref_in_automute = 1;
-}
-
-/* suppress the jack-detection */
-static void alc_fixup_no_jack_detect(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               codec->no_jack_detect = 1;
-}
-
-static const struct hda_fixup alc861_fixups[] = {
-       [ALC861_FIXUP_FSC_AMILO_PI1505] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x0b, 0x0221101f }, /* HP */
-                       { 0x0f, 0x90170310 }, /* speaker */
-                       { }
-               }
-       },
-       [ALC861_FIXUP_AMP_VREF_0F] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc861_fixup_asus_amp_vref_0f,
-       },
-       [ALC861_FIXUP_NO_JACK_DETECT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_no_jack_detect,
-       },
-       [ALC861_FIXUP_ASUS_A6RP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc861_fixup_asus_amp_vref_0f,
-               .chained = true,
-               .chain_id = ALC861_FIXUP_NO_JACK_DETECT,
-       },
-       [ALC660_FIXUP_ASUS_W7J] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       /* ASUS W7J needs a magic pin setup on unused NID 0x10
-                        * for enabling outputs
-                        */
-                       {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24},
-                       { }
-               },
-       }
-};
-
-static const struct hda_quirk alc861_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J),
-       SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J),
-       SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP),
-       SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F),
-       SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT),
-       SND_PCI_QUIRK_VENDOR(0x1584, "Haier/Uniwill", ALC861_FIXUP_AMP_VREF_0F),
-       SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", ALC861_FIXUP_FSC_AMILO_PI1505),
-       {}
-};
-
-/*
- */
-static int patch_alc861(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err;
-
-       err = alc_alloc_spec(codec, 0x15);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       if (has_cdefine_beep(codec))
-               spec->gen.beep_nid = 0x23;
-
-       spec->power_hook = alc_power_eapd;
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       /* automatic parse from the BIOS config */
-       err = alc861_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!spec->gen.no_analog) {
-               err = set_beep_amp(spec, 0x23, 0, HDA_OUTPUT);
-               if (err < 0)
-                       goto error;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-/*
- * ALC861-VD support
- *
- * Based on ALC882
- *
- * In addition, an independent DAC
- */
-static int alc861vd_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc861vd_ignore[] = { 0x1d, 0 };
-       static const hda_nid_t alc861vd_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-       return alc_parse_auto_config(codec, alc861vd_ignore, alc861vd_ssids);
-}
-
-enum {
-       ALC660VD_FIX_ASUS_GPIO1,
-       ALC861VD_FIX_DALLAS,
-};
-
-/* exclude VREF80 */
-static void alc861vd_fixup_dallas(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               snd_hda_override_pin_caps(codec, 0x18, 0x00000734);
-               snd_hda_override_pin_caps(codec, 0x19, 0x0000073c);
-       }
-}
-
-/* reset GPIO1 */
-static void alc660vd_fixup_asus_gpio1(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->gpio_mask |= 0x02;
-       alc_fixup_gpio(codec, action, 0x01);
-}
-
-static const struct hda_fixup alc861vd_fixups[] = {
-       [ALC660VD_FIX_ASUS_GPIO1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc660vd_fixup_asus_gpio1,
-       },
-       [ALC861VD_FIX_DALLAS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc861vd_fixup_dallas,
-       },
-};
-
-static const struct hda_quirk alc861vd_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x103c, 0x30bf, "HP TX1000", ALC861VD_FIX_DALLAS),
-       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS A7-K", ALC660VD_FIX_ASUS_GPIO1),
-       SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba L30-149", ALC861VD_FIX_DALLAS),
-       {}
-};
-
-/*
- */
-static int patch_alc861vd(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err;
-
-       err = alc_alloc_spec(codec, 0x0b);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       if (has_cdefine_beep(codec))
-               spec->gen.beep_nid = 0x23;
-
-       spec->shutup = alc_eapd_shutup;
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       /* automatic parse from the BIOS config */
-       err = alc861vd_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!spec->gen.no_analog) {
-               err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-               if (err < 0)
-                       goto error;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-/*
- * ALC662 support
- *
- * ALC662 is almost identical with ALC880 but has cleaner and more flexible
- * configuration.  Each pin widget can choose any input DACs and a mixer.
- * Each ADC is connected from a mixer of all inputs.  This makes possible
- * 6-channel independent captures.
- *
- * In addition, an independent DAC for the multi-playback (not used in this
- * driver yet).
- */
-
-/*
- * BIOS auto configuration
- */
-
-static int alc662_parse_auto_config(struct hda_codec *codec)
-{
-       static const hda_nid_t alc662_ignore[] = { 0x1d, 0 };
-       static const hda_nid_t alc663_ssids[] = { 0x15, 0x1b, 0x14, 0x21 };
-       static const hda_nid_t alc662_ssids[] = { 0x15, 0x1b, 0x14, 0 };
-       const hda_nid_t *ssids;
-
-       if (codec->core.vendor_id == 0x10ec0272 || codec->core.vendor_id == 0x10ec0663 ||
-           codec->core.vendor_id == 0x10ec0665 || codec->core.vendor_id == 0x10ec0670 ||
-           codec->core.vendor_id == 0x10ec0671)
-               ssids = alc663_ssids;
-       else
-               ssids = alc662_ssids;
-       return alc_parse_auto_config(codec, alc662_ignore, ssids);
-}
-
-static void alc272_fixup_mario(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-       if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT,
-                                     (0x3b << AC_AMPCAP_OFFSET_SHIFT) |
-                                     (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                     (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                     (0 << AC_AMPCAP_MUTE_SHIFT)))
-               codec_warn(codec, "failed to override amp caps for NID 0x2\n");
-}
-
-static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = {
-       { .channels = 2,
-         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
-       { .channels = 4,
-         .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
-                  SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */
-       { }
-};
-
-/* override the 2.1 chmap */
-static void alc_fixup_bass_chmap(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_BUILD) {
-               struct alc_spec *spec = codec->spec;
-               spec->gen.pcm_rec[0]->stream[0].chmap = asus_pcm_2_1_chmaps;
-       }
-}
-
-/* avoid D3 for keeping GPIO up */
-static unsigned int gpio_led_power_filter(struct hda_codec *codec,
-                                         hda_nid_t nid,
-                                         unsigned int power_state)
-{
-       struct alc_spec *spec = codec->spec;
-       if (nid == codec->core.afg && power_state == AC_PWRST_D3 && spec->gpio_data)
-               return AC_PWRST_D0;
-       return power_state;
-}
-
-static void alc662_fixup_led_gpio1(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       alc_fixup_hp_gpio_led(codec, action, 0x01, 0);
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mute_led_polarity = 1;
-               codec->power_filter = gpio_led_power_filter;
-       }
-}
-
-static void alc662_usi_automute_hook(struct hda_codec *codec,
-                                        struct hda_jack_callback *jack)
-{
-       struct alc_spec *spec = codec->spec;
-       int vref;
-       msleep(200);
-       snd_hda_gen_hp_automute(codec, jack);
-
-       vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0;
-       msleep(100);
-       snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL,
-                           vref);
-}
-
-static void alc662_fixup_usi_headset_mic(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-               spec->gen.hp_automute_hook = alc662_usi_automute_hook;
-       }
-}
-
-static void alc662_aspire_ethos_mute_speakers(struct hda_codec *codec,
-                                       struct hda_jack_callback *cb)
-{
-       /* surround speakers at 0x1b already get muted automatically when
-        * headphones are plugged in, but we have to mute/unmute the remaining
-        * channels manually:
-        * 0x15 - front left/front right
-        * 0x18 - front center/ LFE
-        */
-       if (snd_hda_jack_detect_state(codec, 0x1b) == HDA_JACK_PRESENT) {
-               snd_hda_set_pin_ctl_cache(codec, 0x15, 0);
-               snd_hda_set_pin_ctl_cache(codec, 0x18, 0);
-       } else {
-               snd_hda_set_pin_ctl_cache(codec, 0x15, PIN_OUT);
-               snd_hda_set_pin_ctl_cache(codec, 0x18, PIN_OUT);
-       }
-}
-
-static void alc662_fixup_aspire_ethos_hp(struct hda_codec *codec,
-                                       const struct hda_fixup *fix, int action)
-{
-    /* Pin 0x1b: shared headphones jack and surround speakers */
-       if (!is_jack_detectable(codec, 0x1b))
-               return;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_jack_detect_enable_callback(codec, 0x1b,
-                               alc662_aspire_ethos_mute_speakers);
-               /* subwoofer needs an extra GPIO setting to become audible */
-               alc_setup_gpio(codec, 0x02);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               /* Make sure to start in a correct state, i.e. if
-                * headphones have been plugged in before powering up the system
-                */
-               alc662_aspire_ethos_mute_speakers(codec, NULL);
-               break;
-       }
-}
-
-static void alc671_fixup_hp_headset_mic2(struct hda_codec *codec,
-                                            const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       static const struct hda_pintbl pincfgs[] = {
-               { 0x19, 0x02a11040 }, /* use as headset mic, with its own jack detect */
-               { 0x1b, 0x0181304f },
-               { }
-       };
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               spec->gen.mixer_nid = 0;
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-               snd_hda_apply_pincfgs(codec, pincfgs);
-               break;
-       case HDA_FIXUP_ACT_INIT:
-               alc_write_coef_idx(codec, 0x19, 0xa054);
-               break;
-       }
-}
-
-static void alc897_hp_automute_hook(struct hda_codec *codec,
-                                        struct hda_jack_callback *jack)
-{
-       struct alc_spec *spec = codec->spec;
-       int vref;
-
-       snd_hda_gen_hp_automute(codec, jack);
-       vref = spec->gen.hp_jack_present ? (PIN_HP | AC_PINCTL_VREF_100) : PIN_HP;
-       snd_hda_set_pin_ctl(codec, 0x1b, vref);
-}
-
-static void alc897_fixup_lenovo_headset_mic(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gen.hp_automute_hook = alc897_hp_automute_hook;
-               spec->no_shutup_pins = 1;
-       }
-       if (action == HDA_FIXUP_ACT_PROBE) {
-               snd_hda_set_pin_ctl_cache(codec, 0x1a, PIN_IN | AC_PINCTL_VREF_100);
-       }
-}
-
-static void alc897_fixup_lenovo_headset_mode(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct alc_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->parse_flags |= HDA_PINCFG_HEADSET_MIC;
-               spec->gen.hp_automute_hook = alc897_hp_automute_hook;
-       }
-}
-
-static const struct coef_fw alc668_coefs[] = {
-       WRITE_COEF(0x01, 0xbebe), WRITE_COEF(0x02, 0xaaaa), WRITE_COEF(0x03,    0x0),
-       WRITE_COEF(0x04, 0x0180), WRITE_COEF(0x06,    0x0), WRITE_COEF(0x07, 0x0f80),
-       WRITE_COEF(0x08, 0x0031), WRITE_COEF(0x0a, 0x0060), WRITE_COEF(0x0b,    0x0),
-       WRITE_COEF(0x0c, 0x7cf7), WRITE_COEF(0x0d, 0x1080), WRITE_COEF(0x0e, 0x7f7f),
-       WRITE_COEF(0x0f, 0xcccc), WRITE_COEF(0x10, 0xddcc), WRITE_COEF(0x11, 0x0001),
-       WRITE_COEF(0x13,    0x0), WRITE_COEF(0x14, 0x2aa0), WRITE_COEF(0x17, 0xa940),
-       WRITE_COEF(0x19,    0x0), WRITE_COEF(0x1a,    0x0), WRITE_COEF(0x1b,    0x0),
-       WRITE_COEF(0x1c,    0x0), WRITE_COEF(0x1d,    0x0), WRITE_COEF(0x1e, 0x7418),
-       WRITE_COEF(0x1f, 0x0804), WRITE_COEF(0x20, 0x4200), WRITE_COEF(0x21, 0x0468),
-       WRITE_COEF(0x22, 0x8ccc), WRITE_COEF(0x23, 0x0250), WRITE_COEF(0x24, 0x7418),
-       WRITE_COEF(0x27,    0x0), WRITE_COEF(0x28, 0x8ccc), WRITE_COEF(0x2a, 0xff00),
-       WRITE_COEF(0x2b, 0x8000), WRITE_COEF(0xa7, 0xff00), WRITE_COEF(0xa8, 0x8000),
-       WRITE_COEF(0xaa, 0x2e17), WRITE_COEF(0xab, 0xa0c0), WRITE_COEF(0xac,    0x0),
-       WRITE_COEF(0xad,    0x0), WRITE_COEF(0xae, 0x2ac6), WRITE_COEF(0xaf, 0xa480),
-       WRITE_COEF(0xb0,    0x0), WRITE_COEF(0xb1,    0x0), WRITE_COEF(0xb2,    0x0),
-       WRITE_COEF(0xb3,    0x0), WRITE_COEF(0xb4,    0x0), WRITE_COEF(0xb5, 0x1040),
-       WRITE_COEF(0xb6, 0xd697), WRITE_COEF(0xb7, 0x902b), WRITE_COEF(0xb8, 0xd697),
-       WRITE_COEF(0xb9, 0x902b), WRITE_COEF(0xba, 0xb8ba), WRITE_COEF(0xbb, 0xaaab),
-       WRITE_COEF(0xbc, 0xaaaf), WRITE_COEF(0xbd, 0x6aaa), WRITE_COEF(0xbe, 0x1c02),
-       WRITE_COEF(0xc0, 0x00ff), WRITE_COEF(0xc1, 0x0fa6),
-       {}
-};
-
-static void alc668_restore_default_value(struct hda_codec *codec)
-{
-       alc_process_coef_fw(codec, alc668_coefs);
-}
-
-enum {
-       ALC662_FIXUP_ASPIRE,
-       ALC662_FIXUP_LED_GPIO1,
-       ALC662_FIXUP_IDEAPAD,
-       ALC272_FIXUP_MARIO,
-       ALC662_FIXUP_CZC_ET26,
-       ALC662_FIXUP_CZC_P10T,
-       ALC662_FIXUP_SKU_IGNORE,
-       ALC662_FIXUP_HP_RP5800,
-       ALC662_FIXUP_ASUS_MODE1,
-       ALC662_FIXUP_ASUS_MODE2,
-       ALC662_FIXUP_ASUS_MODE3,
-       ALC662_FIXUP_ASUS_MODE4,
-       ALC662_FIXUP_ASUS_MODE5,
-       ALC662_FIXUP_ASUS_MODE6,
-       ALC662_FIXUP_ASUS_MODE7,
-       ALC662_FIXUP_ASUS_MODE8,
-       ALC662_FIXUP_NO_JACK_DETECT,
-       ALC662_FIXUP_ZOTAC_Z68,
-       ALC662_FIXUP_INV_DMIC,
-       ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
-       ALC668_FIXUP_DELL_MIC_NO_PRESENCE,
-       ALC662_FIXUP_HEADSET_MODE,
-       ALC668_FIXUP_HEADSET_MODE,
-       ALC662_FIXUP_BASS_MODE4_CHMAP,
-       ALC662_FIXUP_BASS_16,
-       ALC662_FIXUP_BASS_1A,
-       ALC662_FIXUP_BASS_CHMAP,
-       ALC668_FIXUP_AUTO_MUTE,
-       ALC668_FIXUP_DELL_DISABLE_AAMIX,
-       ALC668_FIXUP_DELL_XPS13,
-       ALC662_FIXUP_ASUS_Nx50,
-       ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
-       ALC668_FIXUP_ASUS_Nx51,
-       ALC668_FIXUP_MIC_COEF,
-       ALC668_FIXUP_ASUS_G751,
-       ALC891_FIXUP_HEADSET_MODE,
-       ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
-       ALC662_FIXUP_ACER_VERITON,
-       ALC892_FIXUP_ASROCK_MOBO,
-       ALC662_FIXUP_USI_FUNC,
-       ALC662_FIXUP_USI_HEADSET_MODE,
-       ALC662_FIXUP_LENOVO_MULTI_CODECS,
-       ALC669_FIXUP_ACER_ASPIRE_ETHOS,
-       ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET,
-       ALC671_FIXUP_HP_HEADSET_MIC2,
-       ALC662_FIXUP_ACER_X2660G_HEADSET_MODE,
-       ALC662_FIXUP_ACER_NITRO_HEADSET_MODE,
-       ALC668_FIXUP_ASUS_NO_HEADSET_MIC,
-       ALC668_FIXUP_HEADSET_MIC,
-       ALC668_FIXUP_MIC_DET_COEF,
-       ALC897_FIXUP_LENOVO_HEADSET_MIC,
-       ALC897_FIXUP_HEADSET_MIC_PIN,
-       ALC897_FIXUP_HP_HSMIC_VERB,
-       ALC897_FIXUP_LENOVO_HEADSET_MODE,
-       ALC897_FIXUP_HEADSET_MIC_PIN2,
-       ALC897_FIXUP_UNIS_H3C_X500S,
-       ALC897_FIXUP_HEADSET_MIC_PIN3,
-};
-
-static const struct hda_fixup alc662_fixups[] = {
-       [ALC662_FIXUP_ASPIRE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x15, 0x99130112 }, /* subwoofer */
-                       { }
-               }
-       },
-       [ALC662_FIXUP_LED_GPIO1] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc662_fixup_led_gpio1,
-       },
-       [ALC662_FIXUP_IDEAPAD] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x17, 0x99130112 }, /* subwoofer */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_LED_GPIO1,
-       },
-       [ALC272_FIXUP_MARIO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc272_fixup_mario,
-       },
-       [ALC662_FIXUP_CZC_ET26] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       {0x12, 0x403cc000},
-                       {0x14, 0x90170110}, /* speaker */
-                       {0x15, 0x411111f0},
-                       {0x16, 0x411111f0},
-                       {0x18, 0x01a19030}, /* mic */
-                       {0x19, 0x90a7013f}, /* int-mic */
-                       {0x1a, 0x01014020},
-                       {0x1b, 0x0121401f},
-                       {0x1c, 0x411111f0},
-                       {0x1d, 0x411111f0},
-                       {0x1e, 0x40478e35},
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_CZC_P10T] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0},
-                       {}
-               }
-       },
-       [ALC662_FIXUP_SKU_IGNORE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_sku_ignore,
-       },
-       [ALC662_FIXUP_HP_RP5800] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x0221201f }, /* HP out */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_ASUS_MODE1] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x18, 0x01a19c20 }, /* mic */
-                       { 0x19, 0x99a3092f }, /* int-mic */
-                       { 0x21, 0x0121401f }, /* HP out */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_ASUS_MODE2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x18, 0x01a19820 }, /* mic */
-                       { 0x19, 0x99a3092f }, /* int-mic */
-                       { 0x1b, 0x0121401f }, /* HP out */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_ASUS_MODE3] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x0121441f }, /* HP */
-                       { 0x18, 0x01a19840 }, /* mic */
-                       { 0x19, 0x99a3094f }, /* int-mic */
-                       { 0x21, 0x01211420 }, /* HP2 */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_ASUS_MODE4] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x16, 0x99130111 }, /* speaker */
-                       { 0x18, 0x01a19840 }, /* mic */
-                       { 0x19, 0x99a3094f }, /* int-mic */
-                       { 0x21, 0x0121441f }, /* HP */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_ASUS_MODE5] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x0121441f }, /* HP */
-                       { 0x16, 0x99130111 }, /* speaker */
-                       { 0x18, 0x01a19840 }, /* mic */
-                       { 0x19, 0x99a3094f }, /* int-mic */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_ASUS_MODE6] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x15, 0x01211420 }, /* HP2 */
-                       { 0x18, 0x01a19840 }, /* mic */
-                       { 0x19, 0x99a3094f }, /* int-mic */
-                       { 0x1b, 0x0121441f }, /* HP */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_ASUS_MODE7] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x17, 0x99130111 }, /* speaker */
-                       { 0x18, 0x01a19840 }, /* mic */
-                       { 0x19, 0x99a3094f }, /* int-mic */
-                       { 0x1b, 0x01214020 }, /* HP */
-                       { 0x21, 0x0121401f }, /* HP */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_ASUS_MODE8] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x14, 0x99130110 }, /* speaker */
-                       { 0x12, 0x99a30970 }, /* int-mic */
-                       { 0x15, 0x01214020 }, /* HP */
-                       { 0x17, 0x99130111 }, /* speaker */
-                       { 0x18, 0x01a19840 }, /* mic */
-                       { 0x21, 0x0121401f }, /* HP */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_SKU_IGNORE
-       },
-       [ALC662_FIXUP_NO_JACK_DETECT] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_no_jack_detect,
-       },
-       [ALC662_FIXUP_ZOTAC_Z68] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x02214020 }, /* Front HP */
-                       { }
-               }
-       },
-       [ALC662_FIXUP_INV_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_inv_dmic,
-       },
-       [ALC668_FIXUP_DELL_XPS13] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_dell_xps13,
-               .chained = true,
-               .chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX
-       },
-       [ALC668_FIXUP_DELL_DISABLE_AAMIX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_disable_aamix,
-               .chained = true,
-               .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
-       },
-       [ALC668_FIXUP_AUTO_MUTE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_auto_mute_via_amp,
-               .chained = true,
-               .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE
-       },
-       [ALC662_FIXUP_DELL_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-                       /* headphone mic by setting pin control of 0x1b (headphone out) to in + vref_50 */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_HEADSET_MODE
-       },
-       [ALC662_FIXUP_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode_alc662,
-       },
-       [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
-                       { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC668_FIXUP_HEADSET_MODE
-       },
-       [ALC668_FIXUP_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode_alc668,
-       },
-       [ALC662_FIXUP_BASS_MODE4_CHMAP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_bass_chmap,
-               .chained = true,
-               .chain_id = ALC662_FIXUP_ASUS_MODE4
-       },
-       [ALC662_FIXUP_BASS_16] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       {0x16, 0x80106111}, /* bass speaker */
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_BASS_CHMAP,
-       },
-       [ALC662_FIXUP_BASS_1A] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       {0x1a, 0x80106111}, /* bass speaker */
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_BASS_CHMAP,
-       },
-       [ALC662_FIXUP_BASS_CHMAP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_bass_chmap,
-       },
-       [ALC662_FIXUP_ASUS_Nx50] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_auto_mute_via_amp,
-               .chained = true,
-               .chain_id = ALC662_FIXUP_BASS_1A
-       },
-       [ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode_alc668,
-               .chain_id = ALC662_FIXUP_BASS_CHMAP
-       },
-       [ALC668_FIXUP_ASUS_Nx51] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
-                       { 0x1a, 0x90170151 }, /* bass speaker */
-                       { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC668_FIXUP_ASUS_Nx51_HEADSET_MODE,
-       },
-       [ALC668_FIXUP_MIC_COEF] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0xc3 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x4000 },
-                       {}
-               },
-       },
-       [ALC668_FIXUP_ASUS_G751] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x16, 0x0421101f }, /* HP */
-                       {}
-               },
-               .chained = true,
-               .chain_id = ALC668_FIXUP_MIC_COEF
-       },
-       [ALC891_FIXUP_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc_fixup_headset_mode,
-       },
-       [ALC891_FIXUP_DELL_MIC_NO_PRESENCE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */
-                       { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC891_FIXUP_HEADSET_MODE
-       },
-       [ALC662_FIXUP_ACER_VERITON] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x15, 0x50170120 }, /* no internal speaker */
-                       { }
-               }
-       },
-       [ALC892_FIXUP_ASROCK_MOBO] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x15, 0x40f000f0 }, /* disabled */
-                       { 0x16, 0x40f000f0 }, /* disabled */
-                       { }
-               }
-       },
-       [ALC662_FIXUP_USI_FUNC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc662_fixup_usi_headset_mic,
-       },
-       [ALC662_FIXUP_USI_HEADSET_MODE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x02a1913c }, /* use as headset mic, without its own jack detect */
-                       { 0x18, 0x01a1903d },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_USI_FUNC
-       },
-       [ALC662_FIXUP_LENOVO_MULTI_CODECS] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc233_alc662_fixup_lenovo_dual_codecs,
-       },
-       [ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc662_fixup_aspire_ethos_hp,
-       },
-       [ALC669_FIXUP_ACER_ASPIRE_ETHOS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x15, 0x92130110 }, /* front speakers */
-                       { 0x18, 0x99130111 }, /* center/subwoofer */
-                       { 0x1b, 0x11130012 }, /* surround plus jack for HP */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC669_FIXUP_ACER_ASPIRE_ETHOS_HEADSET
-       },
-       [ALC671_FIXUP_HP_HEADSET_MIC2] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc671_fixup_hp_headset_mic2,
-       },
-       [ALC662_FIXUP_ACER_X2660G_HEADSET_MODE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x02a1113c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_USI_FUNC
-       },
-       [ALC662_FIXUP_ACER_NITRO_HEADSET_MODE] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
-                       { 0x1b, 0x0221144f },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC662_FIXUP_USI_FUNC
-       },
-       [ALC668_FIXUP_ASUS_NO_HEADSET_MIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1b, 0x04a1112c },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC668_FIXUP_HEADSET_MIC
-       },
-       [ALC668_FIXUP_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc269_fixup_headset_mic,
-               .chained = true,
-               .chain_id = ALC668_FIXUP_MIC_DET_COEF
-       },
-       [ALC668_FIXUP_MIC_DET_COEF] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x15 },
-                       { 0x20, AC_VERB_SET_PROC_COEF, 0x0d60 },
-                       {}
-               },
-       },
-       [ALC897_FIXUP_LENOVO_HEADSET_MIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc897_fixup_lenovo_headset_mic,
-       },
-       [ALC897_FIXUP_HEADSET_MIC_PIN] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x03a11050 },
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MIC
-       },
-       [ALC897_FIXUP_HP_HSMIC_VERB] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-       },
-       [ALC897_FIXUP_LENOVO_HEADSET_MODE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = alc897_fixup_lenovo_headset_mode,
-       },
-       [ALC897_FIXUP_HEADSET_MIC_PIN2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x1a, 0x01a11140 }, /* use as headset mic, without its own jack detect */
-                       { }
-               },
-               .chained = true,
-               .chain_id = ALC897_FIXUP_LENOVO_HEADSET_MODE
-       },
-       [ALC897_FIXUP_UNIS_H3C_X500S] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       { 0x14, AC_VERB_SET_EAPD_BTLENABLE, 0 },
-                       {}
-               },
-       },
-       [ALC897_FIXUP_HEADSET_MIC_PIN3] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x19, 0x03a11050 }, /* use as headset mic */
-                       { }
-               },
-       },
-};
-
-static const struct hda_quirk alc662_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1019, 0x9859, "JP-IK LEAP W502", ALC897_FIXUP_HEADSET_MIC_PIN3),
-       SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x0241, "Packard Bell DOTS", ALC662_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE),
-       SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC),
-       SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE),
-       SND_PCI_QUIRK(0x1025, 0x0566, "Acer Aspire Ethos 8951G", ALC669_FIXUP_ACER_ASPIRE_ETHOS),
-       SND_PCI_QUIRK(0x1025, 0x123c, "Acer Nitro N50-600", ALC662_FIXUP_ACER_NITRO_HEADSET_MODE),
-       SND_PCI_QUIRK(0x1025, 0x124e, "Acer 2660G", ALC662_FIXUP_ACER_X2660G_HEADSET_MODE),
-       SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13),
-       SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13),
-       SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13),
-       SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x1028, 0x069f, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE),
-       SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800),
-       SND_PCI_QUIRK(0x103c, 0x870c, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
-       SND_PCI_QUIRK(0x103c, 0x8719, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
-       SND_PCI_QUIRK(0x103c, 0x872b, "HP", ALC897_FIXUP_HP_HSMIC_VERB),
-       SND_PCI_QUIRK(0x103c, 0x873e, "HP", ALC671_FIXUP_HP_HEADSET_MIC2),
-       SND_PCI_QUIRK(0x103c, 0x8768, "HP Slim Desktop S01", ALC671_FIXUP_HP_HEADSET_MIC2),
-       SND_PCI_QUIRK(0x103c, 0x877e, "HP 288 Pro G6", ALC671_FIXUP_HP_HEADSET_MIC2),
-       SND_PCI_QUIRK(0x103c, 0x885f, "HP 288 Pro G8", ALC671_FIXUP_HP_HEADSET_MIC2),
-       SND_PCI_QUIRK(0x1043, 0x1080, "Asus UX501VW", ALC668_FIXUP_HEADSET_MODE),
-       SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_ASUS_Nx50),
-       SND_PCI_QUIRK(0x1043, 0x129d, "Asus N750", ALC662_FIXUP_ASUS_Nx50),
-       SND_PCI_QUIRK(0x1043, 0x12ff, "ASUS G751", ALC668_FIXUP_ASUS_G751),
-       SND_PCI_QUIRK(0x1043, 0x13df, "Asus N550JX", ALC662_FIXUP_BASS_1A),
-       SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
-       SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16),
-       SND_PCI_QUIRK(0x1043, 0x177d, "ASUS N551", ALC668_FIXUP_ASUS_Nx51),
-       SND_PCI_QUIRK(0x1043, 0x17bd, "ASUS N751", ALC668_FIXUP_ASUS_Nx51),
-       SND_PCI_QUIRK(0x1043, 0x185d, "ASUS G551JW", ALC668_FIXUP_ASUS_NO_HEADSET_MIC),
-       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71SL", ALC662_FIXUP_ASUS_MODE8),
-       SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16),
-       SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP),
-       SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT),
-       SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD),
-       SND_PCI_QUIRK(0x14cd, 0x5003, "USI", ALC662_FIXUP_USI_HEADSET_MODE),
-       SND_PCI_QUIRK(0x17aa, 0x1036, "Lenovo P520", ALC662_FIXUP_LENOVO_MULTI_CODECS),
-       SND_PCI_QUIRK(0x17aa, 0x1057, "Lenovo P360", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x1064, "Lenovo P3 Tower", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x32ca, "Lenovo ThinkCentre M80", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x32cb, "Lenovo ThinkCentre M70", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x32cf, "Lenovo ThinkCentre M950", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x32f7, "Lenovo ThinkCentre M90", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x3321, "Lenovo ThinkCentre M70 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x331b, "Lenovo ThinkCentre M90 Gen4", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x3364, "Lenovo ThinkCentre M90 Gen5", ALC897_FIXUP_HEADSET_MIC_PIN),
-       SND_PCI_QUIRK(0x17aa, 0x3742, "Lenovo TianYi510Pro-14IOB", ALC897_FIXUP_HEADSET_MIC_PIN2),
-       SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo Ideapad Y550P", ALC662_FIXUP_IDEAPAD),
-       SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo Ideapad Y550", ALC662_FIXUP_IDEAPAD),
-       SND_PCI_QUIRK(0x1849, 0x5892, "ASRock B150M", ALC892_FIXUP_ASROCK_MOBO),
-       SND_PCI_QUIRK(0x19da, 0xa130, "Zotac Z68", ALC662_FIXUP_ZOTAC_Z68),
-       SND_PCI_QUIRK(0x1b0a, 0x01b8, "ACER Veriton", ALC662_FIXUP_ACER_VERITON),
-       SND_PCI_QUIRK(0x1b35, 0x1234, "CZC ET26", ALC662_FIXUP_CZC_ET26),
-       SND_PCI_QUIRK(0x1b35, 0x2206, "CZC P10T", ALC662_FIXUP_CZC_P10T),
-       SND_PCI_QUIRK(0x1c6c, 0x1239, "Compaq N14JP6-V2", ALC897_FIXUP_HP_HSMIC_VERB),
-
-#if 0
-       /* Below is a quirk table taken from the old code.
-        * Basically the device should work as is without the fixup table.
-        * If BIOS doesn't give a proper info, enable the corresponding
-        * fixup entry.
-        */
-       SND_PCI_QUIRK(0x1043, 0x1000, "ASUS N50Vm", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1092, "ASUS NB", ALC662_FIXUP_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1173, "ASUS K73Jn", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x11c3, "ASUS M70V", ALC662_FIXUP_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC662_FIXUP_ASUS_MODE7),
-       SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC662_FIXUP_ASUS_MODE7),
-       SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC662_FIXUP_ASUS_MODE8),
-       SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC662_FIXUP_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC662_FIXUP_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1813, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1823, "ASUS NB", ALC662_FIXUP_ASUS_MODE5),
-       SND_PCI_QUIRK(0x1043, 0x1833, "ASUS NB", ALC662_FIXUP_ASUS_MODE6),
-       SND_PCI_QUIRK(0x1043, 0x1843, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1853, "ASUS F50Z", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1864, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1876, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1893, "ASUS M50Vm", ALC662_FIXUP_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1894, "ASUS X55", ALC662_FIXUP_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x18b3, "ASUS N80Vc", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x18c3, "ASUS VX5", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x18d3, "ASUS N81Te", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x18f3, "ASUS N505Tp", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1903, "ASUS F5GL", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1913, "ASUS NB", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1933, "ASUS F80Q", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x1943, "ASUS Vx3V", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1953, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1963, "ASUS X71C", ALC662_FIXUP_ASUS_MODE3),
-       SND_PCI_QUIRK(0x1043, 0x1983, "ASUS N5051A", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x1993, "ASUS N20", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19b3, "ASUS F7Z", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19c3, "ASUS F5Z/F6x", ALC662_FIXUP_ASUS_MODE2),
-       SND_PCI_QUIRK(0x1043, 0x19e3, "ASUS NB", ALC662_FIXUP_ASUS_MODE1),
-       SND_PCI_QUIRK(0x1043, 0x19f3, "ASUS NB", ALC662_FIXUP_ASUS_MODE4),
-#endif
-       {}
-};
-
-static const struct hda_model_fixup alc662_fixup_models[] = {
-       {.id = ALC662_FIXUP_ASPIRE, .name = "aspire"},
-       {.id = ALC662_FIXUP_IDEAPAD, .name = "ideapad"},
-       {.id = ALC272_FIXUP_MARIO, .name = "mario"},
-       {.id = ALC662_FIXUP_HP_RP5800, .name = "hp-rp5800"},
-       {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"},
-       {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"},
-       {.id = ALC662_FIXUP_ASUS_MODE3, .name = "asus-mode3"},
-       {.id = ALC662_FIXUP_ASUS_MODE4, .name = "asus-mode4"},
-       {.id = ALC662_FIXUP_ASUS_MODE5, .name = "asus-mode5"},
-       {.id = ALC662_FIXUP_ASUS_MODE6, .name = "asus-mode6"},
-       {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"},
-       {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"},
-       {.id = ALC662_FIXUP_ZOTAC_Z68, .name = "zotac-z68"},
-       {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"},
-       {.id = ALC662_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc662-headset-multi"},
-       {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
-       {.id = ALC662_FIXUP_HEADSET_MODE, .name = "alc662-headset"},
-       {.id = ALC668_FIXUP_HEADSET_MODE, .name = "alc668-headset"},
-       {.id = ALC662_FIXUP_BASS_16, .name = "bass16"},
-       {.id = ALC662_FIXUP_BASS_1A, .name = "bass1a"},
-       {.id = ALC668_FIXUP_AUTO_MUTE, .name = "automute"},
-       {.id = ALC668_FIXUP_DELL_XPS13, .name = "dell-xps13"},
-       {.id = ALC662_FIXUP_ASUS_Nx50, .name = "asus-nx50"},
-       {.id = ALC668_FIXUP_ASUS_Nx51, .name = "asus-nx51"},
-       {.id = ALC668_FIXUP_ASUS_G751, .name = "asus-g751"},
-       {.id = ALC891_FIXUP_HEADSET_MODE, .name = "alc891-headset"},
-       {.id = ALC891_FIXUP_DELL_MIC_NO_PRESENCE, .name = "alc891-headset-multi"},
-       {.id = ALC662_FIXUP_ACER_VERITON, .name = "acer-veriton"},
-       {.id = ALC892_FIXUP_ASROCK_MOBO, .name = "asrock-mobo"},
-       {.id = ALC662_FIXUP_USI_HEADSET_MODE, .name = "usi-headset"},
-       {.id = ALC662_FIXUP_LENOVO_MULTI_CODECS, .name = "dual-codecs"},
-       {.id = ALC669_FIXUP_ACER_ASPIRE_ETHOS, .name = "aspire-ethos"},
-       {.id = ALC897_FIXUP_UNIS_H3C_X500S, .name = "unis-h3c-x500s"},
-       {}
-};
-
-static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = {
-       SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
-               {0x17, 0x02211010},
-               {0x18, 0x01a19030},
-               {0x1a, 0x01813040},
-               {0x21, 0x01014020}),
-       SND_HDA_PIN_QUIRK(0x10ec0867, 0x1028, "Dell", ALC891_FIXUP_DELL_MIC_NO_PRESENCE,
-               {0x16, 0x01813030},
-               {0x17, 0x02211010},
-               {0x18, 0x01a19040},
-               {0x21, 0x01014020}),
-       SND_HDA_PIN_QUIRK(0x10ec0662, 0x1028, "Dell", ALC662_FIXUP_DELL_MIC_NO_PRESENCE,
-               {0x14, 0x01014010},
-               {0x18, 0x01a19020},
-               {0x1a, 0x0181302f},
-               {0x1b, 0x0221401f}),
-       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
-               {0x12, 0x99a30130},
-               {0x14, 0x90170110},
-               {0x15, 0x0321101f},
-               {0x16, 0x03011020}),
-       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
-               {0x12, 0x99a30140},
-               {0x14, 0x90170110},
-               {0x15, 0x0321101f},
-               {0x16, 0x03011020}),
-       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
-               {0x12, 0x99a30150},
-               {0x14, 0x90170110},
-               {0x15, 0x0321101f},
-               {0x16, 0x03011020}),
-       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE,
-               {0x14, 0x90170110},
-               {0x15, 0x0321101f},
-               {0x16, 0x03011020}),
-       SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE,
-               {0x12, 0x90a60130},
-               {0x14, 0x90170110},
-               {0x15, 0x0321101f}),
-       SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
-               {0x14, 0x01014010},
-               {0x17, 0x90170150},
-               {0x19, 0x02a11060},
-               {0x1b, 0x01813030},
-               {0x21, 0x02211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
-               {0x14, 0x01014010},
-               {0x18, 0x01a19040},
-               {0x1b, 0x01813030},
-               {0x21, 0x02211020}),
-       SND_HDA_PIN_QUIRK(0x10ec0671, 0x103c, "HP cPC", ALC671_FIXUP_HP_HEADSET_MIC2,
-               {0x14, 0x01014020},
-               {0x17, 0x90170110},
-               {0x18, 0x01a19050},
-               {0x1b, 0x01813040},
-               {0x21, 0x02211030}),
-       {}
-};
-
-/*
- */
-static int patch_alc662(struct hda_codec *codec)
-{
-       struct alc_spec *spec;
-       int err;
-
-       err = alc_alloc_spec(codec, 0x0b);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-
-       spec->shutup = alc_eapd_shutup;
-
-       /* handle multiple HPs as is */
-       spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP;
-
-       alc_fix_pll_init(codec, 0x20, 0x04, 15);
-
-       switch (codec->core.vendor_id) {
-       case 0x10ec0668:
-               spec->init_hook = alc668_restore_default_value;
-               break;
-       }
-
-       alc_pre_init(codec);
-
-       snd_hda_pick_fixup(codec, alc662_fixup_models,
-                      alc662_fixup_tbl, alc662_fixups);
-       snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups, true);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       alc_auto_parse_customize_define(codec);
-
-       if (has_cdefine_beep(codec))
-               spec->gen.beep_nid = 0x01;
-
-       if ((alc_get_coef0(codec) & (1 << 14)) &&
-           codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 &&
-           spec->cdefine.platform_type == 1) {
-               err = alc_codec_rename(codec, "ALC272X");
-               if (err < 0)
-                       goto error;
-       }
-
-       /* automatic parse from the BIOS config */
-       err = alc662_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!spec->gen.no_analog && spec->gen.beep_nid) {
-               switch (codec->core.vendor_id) {
-               case 0x10ec0662:
-                       err = set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT);
-                       break;
-               case 0x10ec0272:
-               case 0x10ec0663:
-               case 0x10ec0665:
-               case 0x10ec0668:
-                       err = set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT);
-                       break;
-               case 0x10ec0273:
-                       err = set_beep_amp(spec, 0x0b, 0x03, HDA_INPUT);
-                       break;
-               }
-               if (err < 0)
-                       goto error;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       alc_free(codec);
-       return err;
-}
-
-/*
- * ALC680 support
- */
-
-static int alc680_parse_auto_config(struct hda_codec *codec)
-{
-       return alc_parse_auto_config(codec, NULL, NULL);
-}
-
-/*
- */
-static int patch_alc680(struct hda_codec *codec)
-{
-       int err;
-
-       /* ALC680 has no aa-loopback mixer */
-       err = alc_alloc_spec(codec, 0);
-       if (err < 0)
-               return err;
-
-       /* automatic parse from the BIOS config */
-       err = alc680_parse_auto_config(codec);
-       if (err < 0) {
-               alc_free(codec);
-               return err;
-       }
-
-       return 0;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_realtek[] = {
-       HDA_CODEC_ENTRY(0x10ec0215, "ALC215", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0221, "ALC221", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0222, "ALC222", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0225, "ALC225", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0230, "ALC236", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0231, "ALC231", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0233, "ALC233", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0234, "ALC234", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0235, "ALC233", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0236, "ALC236", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0245, "ALC245", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0255, "ALC255", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0256, "ALC256", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0257, "ALC257", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0260, "ALC260", patch_alc260),
-       HDA_CODEC_ENTRY(0x10ec0262, "ALC262", patch_alc262),
-       HDA_CODEC_ENTRY(0x10ec0267, "ALC267", patch_alc268),
-       HDA_CODEC_ENTRY(0x10ec0268, "ALC268", patch_alc268),
-       HDA_CODEC_ENTRY(0x10ec0269, "ALC269", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0270, "ALC270", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0272, "ALC272", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0274, "ALC274", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0275, "ALC275", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0276, "ALC276", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0280, "ALC280", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0282, "ALC282", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0283, "ALC283", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0284, "ALC284", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0285, "ALC285", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0286, "ALC286", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0287, "ALC287", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0288, "ALC288", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0289, "ALC289", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0290, "ALC290", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0292, "ALC292", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0293, "ALC293", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0294, "ALC294", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0295, "ALC295", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0298, "ALC298", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0299, "ALC299", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0300, "ALC300", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0623, "ALC623", patch_alc269),
-       HDA_CODEC_REV_ENTRY(0x10ec0861, 0x100340, "ALC660", patch_alc861),
-       HDA_CODEC_ENTRY(0x10ec0660, "ALC660-VD", patch_alc861vd),
-       HDA_CODEC_ENTRY(0x10ec0861, "ALC861", patch_alc861),
-       HDA_CODEC_ENTRY(0x10ec0862, "ALC861-VD", patch_alc861vd),
-       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100002, "ALC662 rev2", patch_alc882),
-       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100101, "ALC662 rev1", patch_alc662),
-       HDA_CODEC_REV_ENTRY(0x10ec0662, 0x100300, "ALC662 rev3", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0663, "ALC663", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0665, "ALC665", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0667, "ALC667", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0668, "ALC668", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0670, "ALC670", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0671, "ALC671", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0680, "ALC680", patch_alc680),
-       HDA_CODEC_ENTRY(0x10ec0700, "ALC700", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0701, "ALC701", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0703, "ALC703", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0711, "ALC711", patch_alc269),
-       HDA_CODEC_ENTRY(0x10ec0867, "ALC891", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0880, "ALC880", patch_alc880),
-       HDA_CODEC_ENTRY(0x10ec0882, "ALC882", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec0883, "ALC883", patch_alc882),
-       HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100101, "ALC889A", patch_alc882),
-       HDA_CODEC_REV_ENTRY(0x10ec0885, 0x100103, "ALC889A", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec0885, "ALC885", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec0887, "ALC887", patch_alc882),
-       HDA_CODEC_REV_ENTRY(0x10ec0888, 0x100101, "ALC1200", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec0888, "ALC888", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec0889, "ALC889", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec0892, "ALC892", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0897, "ALC897", patch_alc662),
-       HDA_CODEC_ENTRY(0x10ec0899, "ALC898", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec0900, "ALC1150", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec0b00, "ALCS1200A", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec1168, "ALC1220", patch_alc882),
-       HDA_CODEC_ENTRY(0x10ec1220, "ALC1220", patch_alc882),
-       HDA_CODEC_ENTRY(0x19e58326, "HW8326", patch_alc269),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_realtek);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Realtek HD-audio codec");
-MODULE_IMPORT_NS("SND_HDA_SCODEC_COMPONENT");
-
-static struct hda_codec_driver realtek_driver = {
-       .id = snd_hda_id_realtek,
-};
-
-module_hda_codec_driver(realtek_driver);
diff --git a/sound/pci/hda/patch_senarytech.c b/sound/pci/hda/patch_senarytech.c
deleted file mode 100644 (file)
index 0691996..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * HD audio interface patch for Senary HDA audio codec
- *
- * Initially based on sound/pci/hda/patch_conexant.c
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_beep.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-struct senary_spec {
-       struct hda_gen_spec gen;
-
-       /* extra EAPD pins */
-       unsigned int num_eapds;
-       hda_nid_t eapds[4];
-       hda_nid_t mute_led_eapd;
-
-       unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */
-
-       int mute_led_polarity;
-       unsigned int gpio_led;
-       unsigned int gpio_mute_led_mask;
-       unsigned int gpio_mic_led_mask;
-};
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-/* additional beep mixers; private_value will be overwritten */
-static const struct snd_kcontrol_new senary_beep_mixer[] = {
-       HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
-};
-
-static int set_beep_amp(struct senary_spec *spec, hda_nid_t nid,
-                       int idx, int dir)
-{
-       struct snd_kcontrol_new *knew;
-       unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
-       int i;
-
-       spec->gen.beep_nid = nid;
-       for (i = 0; i < ARRAY_SIZE(senary_beep_mixer); i++) {
-               knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
-                                           &senary_beep_mixer[i]);
-               if (!knew)
-                       return -ENOMEM;
-               knew->private_value = beep_amp;
-       }
-       return 0;
-}
-
-static int senary_auto_parse_beep(struct hda_codec *codec)
-{
-       struct senary_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       for_each_hda_codec_node(nid, codec)
-               if ((get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) &&
-                       (get_wcaps(codec, nid) & (AC_WCAP_OUT_AMP | AC_WCAP_AMP_OVRD)))
-                       return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
-       return 0;
-}
-#else
-#define senary_auto_parse_beep(codec)  0
-#endif
-
-/* parse EAPDs */
-static void senary_auto_parse_eapd(struct hda_codec *codec)
-{
-       struct senary_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       for_each_hda_codec_node(nid, codec) {
-               if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN)
-                       continue;
-               if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD))
-                       continue;
-               spec->eapds[spec->num_eapds++] = nid;
-               if (spec->num_eapds >= ARRAY_SIZE(spec->eapds))
-                       break;
-       }
-}
-
-static void senary_auto_turn_eapd(struct hda_codec *codec, int num_pins,
-                             const hda_nid_t *pins, bool on)
-{
-       int i;
-
-       for (i = 0; i < num_pins; i++) {
-               if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD)
-                       snd_hda_codec_write(codec, pins[i], 0,
-                                           AC_VERB_SET_EAPD_BTLENABLE,
-                                           on ? 0x02 : 0);
-       }
-}
-
-/* turn on/off EAPD according to Master switch */
-static void senary_auto_vmaster_hook(void *private_data, int enabled)
-{
-       struct hda_codec *codec = private_data;
-       struct senary_spec *spec = codec->spec;
-
-       senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled);
-}
-
-static void senary_init_gpio_led(struct hda_codec *codec)
-{
-       struct senary_spec *spec = codec->spec;
-       unsigned int mask = spec->gpio_mute_led_mask | spec->gpio_mic_led_mask;
-
-       if (mask) {
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK,
-                                   mask);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION,
-                                   mask);
-               snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
-                                   spec->gpio_led);
-       }
-}
-
-static int senary_auto_init(struct hda_codec *codec)
-{
-       snd_hda_gen_init(codec);
-       senary_init_gpio_led(codec);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT);
-
-       return 0;
-}
-
-static void senary_auto_shutdown(struct hda_codec *codec)
-{
-       struct senary_spec *spec = codec->spec;
-
-       /* Turn the problematic codec into D3 to avoid spurious noises
-        * from the internal speaker during (and after) reboot
-        */
-       senary_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, false);
-}
-
-static void senary_auto_free(struct hda_codec *codec)
-{
-       senary_auto_shutdown(codec);
-       snd_hda_gen_free(codec);
-}
-
-static int senary_auto_suspend(struct hda_codec *codec)
-{
-       senary_auto_shutdown(codec);
-       return 0;
-}
-
-static const struct hda_codec_ops senary_auto_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = senary_auto_init,
-       .free = senary_auto_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .suspend = senary_auto_suspend,
-       .check_power_status = snd_hda_gen_check_power_status,
-};
-
-static int patch_senary_auto(struct hda_codec *codec)
-{
-       struct senary_spec *spec;
-       int err;
-
-       codec_info(codec, "%s: BIOS auto-probing.\n", codec->core.chip_name);
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       snd_hda_gen_spec_init(&spec->gen);
-       codec->spec = spec;
-       codec->patch_ops = senary_auto_patch_ops;
-
-       senary_auto_parse_eapd(codec);
-       spec->gen.own_eapd_ctl = 1;
-
-       if (!spec->gen.vmaster_mute.hook)
-               spec->gen.vmaster_mute.hook = senary_auto_vmaster_hook;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL,
-                                      spec->parse_flags);
-       if (err < 0)
-               goto error;
-
-       err = senary_auto_parse_beep(codec);
-       if (err < 0)
-               goto error;
-
-       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
-       if (err < 0)
-               goto error;
-
-       /* Some laptops with Senary chips show stalls in S3 resume,
-        * which falls into the single-cmd mode.
-        * Better to make reset, then.
-        */
-       if (!codec->bus->core.sync_write) {
-               codec_info(codec,
-                          "Enable sync_write for stable communication\n");
-               codec->bus->core.sync_write = 1;
-               codec->bus->allow_bus_reset = 1;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-
- error:
-       senary_auto_free(codec);
-       return err;
-}
-
-/*
- */
-
-static const struct hda_device_id snd_hda_id_senary[] = {
-       HDA_CODEC_ENTRY(0x1fa86186, "SN6186", patch_senary_auto),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_senary);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Senarytech HD-audio codec");
-
-static struct hda_codec_driver senary_driver = {
-       .id = snd_hda_id_senary,
-};
-
-module_hda_codec_driver(senary_driver);
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c
deleted file mode 100644 (file)
index 763eae8..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for Silicon Labs 3054/5 modem codec
- *
- * Copyright (c) 2005 Sasha Khapyorsky <sashak@alsa-project.org>
- *                    Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-
-/* si3054 verbs */
-#define SI3054_VERB_READ_NODE  0x900
-#define SI3054_VERB_WRITE_NODE 0x100
-
-/* si3054 nodes (registers) */
-#define SI3054_EXTENDED_MID    2
-#define SI3054_LINE_RATE       3
-#define SI3054_LINE_LEVEL      4
-#define SI3054_GPIO_CFG        5
-#define SI3054_GPIO_POLARITY   6
-#define SI3054_GPIO_STICKY     7
-#define SI3054_GPIO_WAKEUP     8
-#define SI3054_GPIO_STATUS     9
-#define SI3054_GPIO_CONTROL   10
-#define SI3054_MISC_AFE       11
-#define SI3054_CHIPID         12
-#define SI3054_LINE_CFG1      13
-#define SI3054_LINE_STATUS    14
-#define SI3054_DC_TERMINATION 15
-#define SI3054_LINE_CONFIG    16
-#define SI3054_CALLPROG_ATT   17
-#define SI3054_SQ_CONTROL     18
-#define SI3054_MISC_CONTROL   19
-#define SI3054_RING_CTRL1     20
-#define SI3054_RING_CTRL2     21
-
-/* extended MID */
-#define SI3054_MEI_READY 0xf
-
-/* line level */
-#define SI3054_ATAG_MASK 0x00f0
-#define SI3054_DTAG_MASK 0xf000
-
-/* GPIO bits */
-#define SI3054_GPIO_OH    0x0001
-#define SI3054_GPIO_CID   0x0002
-
-/* chipid and revisions */
-#define SI3054_CHIPID_CODEC_REV_MASK 0x000f
-#define SI3054_CHIPID_DAA_REV_MASK   0x00f0
-#define SI3054_CHIPID_INTERNATIONAL  0x0100
-#define SI3054_CHIPID_DAA_ID         0x0f00
-#define SI3054_CHIPID_CODEC_ID      (1<<12)
-
-/* si3054 codec registers (nodes) access macros */
-#define GET_REG(codec,reg) (snd_hda_codec_read(codec,reg,0,SI3054_VERB_READ_NODE,0))
-#define SET_REG(codec,reg,val) (snd_hda_codec_write(codec,reg,0,SI3054_VERB_WRITE_NODE,val))
-#define SET_REG_CACHE(codec,reg,val) \
-       snd_hda_codec_write_cache(codec,reg,0,SI3054_VERB_WRITE_NODE,val)
-
-
-struct si3054_spec {
-       unsigned international;
-};
-
-
-/*
- * Modem mixer
- */
-
-#define PRIVATE_VALUE(reg,mask) ((reg<<16)|(mask&0xffff))
-#define PRIVATE_REG(val) ((val>>16)&0xffff)
-#define PRIVATE_MASK(val) (val&0xffff)
-
-#define si3054_switch_info     snd_ctl_boolean_mono_info
-
-static int si3054_switch_get(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *uvalue)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       u16 reg  = PRIVATE_REG(kcontrol->private_value);
-       u16 mask = PRIVATE_MASK(kcontrol->private_value);
-       uvalue->value.integer.value[0] = (GET_REG(codec, reg)) & mask ? 1 : 0 ;
-       return 0;
-}
-
-static int si3054_switch_put(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_value *uvalue)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       u16 reg  = PRIVATE_REG(kcontrol->private_value);
-       u16 mask = PRIVATE_MASK(kcontrol->private_value);
-       if (uvalue->value.integer.value[0])
-               SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) | mask);
-       else
-               SET_REG_CACHE(codec, reg, (GET_REG(codec, reg)) & ~mask);
-       return 0;
-}
-
-#define SI3054_KCONTROL(kname,reg,mask) { \
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-       .name = kname, \
-       .subdevice = HDA_SUBDEV_NID_FLAG | reg, \
-       .info = si3054_switch_info, \
-       .get  = si3054_switch_get, \
-       .put  = si3054_switch_put, \
-       .private_value = PRIVATE_VALUE(reg,mask), \
-}
-               
-
-static const struct snd_kcontrol_new si3054_modem_mixer[] = {
-       SI3054_KCONTROL("Off-hook Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_OH),
-       SI3054_KCONTROL("Caller ID Switch", SI3054_GPIO_CONTROL, SI3054_GPIO_CID),
-       {}
-};
-
-static int si3054_build_controls(struct hda_codec *codec)
-{
-       return snd_hda_add_new_ctls(codec, si3054_modem_mixer);
-}
-
-
-/*
- * PCM callbacks
- */
-
-static int si3054_pcm_prepare(struct hda_pcm_stream *hinfo,
-                             struct hda_codec *codec,
-                             unsigned int stream_tag,
-                             unsigned int format,
-                             struct snd_pcm_substream *substream)
-{
-       u16 val;
-
-       SET_REG(codec, SI3054_LINE_RATE, substream->runtime->rate);
-       val = GET_REG(codec, SI3054_LINE_LEVEL);
-       val &= 0xff << (8 * (substream->stream != SNDRV_PCM_STREAM_PLAYBACK));
-       val |= ((stream_tag & 0xf) << 4) << (8 * (substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
-       SET_REG(codec, SI3054_LINE_LEVEL, val);
-
-       snd_hda_codec_setup_stream(codec, hinfo->nid,
-                                  stream_tag, 0, format);
-       return 0;
-}
-
-static int si3054_pcm_open(struct hda_pcm_stream *hinfo,
-                          struct hda_codec *codec,
-                           struct snd_pcm_substream *substream)
-{
-       static const unsigned int rates[] = { 8000, 9600, 16000 };
-       static const struct snd_pcm_hw_constraint_list hw_constraints_rates = {
-               .count = ARRAY_SIZE(rates),
-               .list = rates,
-               .mask = 0,
-       };
-       substream->runtime->hw.period_bytes_min = 80;
-       return snd_pcm_hw_constraint_list(substream->runtime, 0,
-                       SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates);
-}
-
-
-static const struct hda_pcm_stream si3054_pcm = {
-       .substreams = 1,
-       .channels_min = 1,
-       .channels_max = 1,
-       .nid = 0x1,
-       .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_KNOT,
-       .formats = SNDRV_PCM_FMTBIT_S16_LE,
-       .maxbps = 16,
-       .ops = {
-               .open = si3054_pcm_open,
-               .prepare = si3054_pcm_prepare,
-       },
-};
-
-
-static int si3054_build_pcms(struct hda_codec *codec)
-{
-       struct hda_pcm *info;
-
-       info = snd_hda_codec_pcm_new(codec, "Si3054 Modem");
-       if (!info)
-               return -ENOMEM;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK] = si3054_pcm;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE]  = si3054_pcm;
-       info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = codec->core.mfg;
-       info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = codec->core.mfg;
-       info->pcm_type = HDA_PCM_TYPE_MODEM;
-       return 0;
-}
-
-
-/*
- * Init part
- */
-
-static int si3054_init(struct hda_codec *codec)
-{
-       struct si3054_spec *spec = codec->spec;
-       unsigned wait_count;
-       u16 val;
-
-       if (snd_hdac_regmap_add_vendor_verb(&codec->core,
-                                           SI3054_VERB_WRITE_NODE))
-               return -ENOMEM;
-
-       snd_hda_codec_write(codec, AC_NODE_ROOT, 0, AC_VERB_SET_CODEC_RESET, 0);
-       snd_hda_codec_write(codec, codec->core.mfg, 0, AC_VERB_SET_STREAM_FORMAT, 0);
-       SET_REG(codec, SI3054_LINE_RATE, 9600);
-       SET_REG(codec, SI3054_LINE_LEVEL, SI3054_DTAG_MASK|SI3054_ATAG_MASK);
-       SET_REG(codec, SI3054_EXTENDED_MID, 0);
-
-       wait_count = 10;
-       do {
-               msleep(2);
-               val = GET_REG(codec, SI3054_EXTENDED_MID);
-       } while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--);
-
-       if((val&SI3054_MEI_READY) != SI3054_MEI_READY) {
-               codec_err(codec, "si3054: cannot initialize. EXT MID = %04x\n", val);
-               /* let's pray that this is no fatal error */
-               /* return -EACCES; */
-       }
-
-       SET_REG(codec, SI3054_GPIO_POLARITY, 0xffff);
-       SET_REG(codec, SI3054_GPIO_CFG, 0x0);
-       SET_REG(codec, SI3054_MISC_AFE, 0);
-       SET_REG(codec, SI3054_LINE_CFG1,0x200);
-
-       if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) {
-               codec_dbg(codec,
-                         "Link Frame Detect(FDT) is not ready (line status: %04x)\n",
-                               GET_REG(codec,SI3054_LINE_STATUS));
-       }
-
-       spec->international = GET_REG(codec, SI3054_CHIPID) & SI3054_CHIPID_INTERNATIONAL;
-
-       return 0;
-}
-
-static void si3054_free(struct hda_codec *codec)
-{
-       kfree(codec->spec);
-}
-
-
-/*
- */
-
-static const struct hda_codec_ops si3054_patch_ops = {
-       .build_controls = si3054_build_controls,
-       .build_pcms = si3054_build_pcms,
-       .init = si3054_init,
-       .free = si3054_free,
-};
-
-static int patch_si3054(struct hda_codec *codec)
-{
-       struct si3054_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return -ENOMEM;
-       codec->spec = spec;
-       codec->patch_ops = si3054_patch_ops;
-       return 0;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_si3054[] = {
-       HDA_CODEC_ENTRY(0x163c3055, "Si3054", patch_si3054),
-       HDA_CODEC_ENTRY(0x163c3155, "Si3054", patch_si3054),
-       HDA_CODEC_ENTRY(0x11c13026, "Si3054", patch_si3054),
-       HDA_CODEC_ENTRY(0x11c13055, "Si3054", patch_si3054),
-       HDA_CODEC_ENTRY(0x11c13155, "Si3054", patch_si3054),
-       HDA_CODEC_ENTRY(0x10573055, "Si3054", patch_si3054),
-       HDA_CODEC_ENTRY(0x10573057, "Si3054", patch_si3054),
-       HDA_CODEC_ENTRY(0x10573155, "Si3054", patch_si3054),
-       /* VIA HDA on Clevo m540 */
-       HDA_CODEC_ENTRY(0x11063288, "Si3054", patch_si3054),
-       /* Asus A8J Modem (SM56) */
-       HDA_CODEC_ENTRY(0x15433155, "Si3054", patch_si3054),
-       /* LG LW20 modem */
-       HDA_CODEC_ENTRY(0x18540018, "Si3054", patch_si3054),
-       {}
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_si3054);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("Si3054 HD-audio modem codec");
-
-static struct hda_codec_driver si3054_driver = {
-       .id = snd_hda_id_si3054,
-};
-
-module_hda_codec_driver(si3054_driver);
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c
deleted file mode 100644 (file)
index bde6b73..0000000
+++ /dev/null
@@ -1,5161 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for SigmaTel STAC92xx
- *
- * Copyright (c) 2005 Embedded Alley Solutions, Inc.
- * Matt Porter <mporter@embeddedalley.com>
- *
- * Based on patch_cmedia.c and patch_realtek.c
- * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de>
- */
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-#include <linux/dmi.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/jack.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_beep.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-enum {
-       STAC_REF,
-       STAC_9200_OQO,
-       STAC_9200_DELL_D21,
-       STAC_9200_DELL_D22,
-       STAC_9200_DELL_D23,
-       STAC_9200_DELL_M21,
-       STAC_9200_DELL_M22,
-       STAC_9200_DELL_M23,
-       STAC_9200_DELL_M24,
-       STAC_9200_DELL_M25,
-       STAC_9200_DELL_M26,
-       STAC_9200_DELL_M27,
-       STAC_9200_M4,
-       STAC_9200_M4_2,
-       STAC_9200_PANASONIC,
-       STAC_9200_EAPD_INIT,
-       STAC_9200_MODELS
-};
-
-enum {
-       STAC_9205_REF,
-       STAC_9205_DELL_M42,
-       STAC_9205_DELL_M43,
-       STAC_9205_DELL_M44,
-       STAC_9205_EAPD,
-       STAC_9205_MODELS
-};
-
-enum {
-       STAC_92HD73XX_NO_JD, /* no jack-detection */
-       STAC_92HD73XX_REF,
-       STAC_92HD73XX_INTEL,
-       STAC_DELL_M6_AMIC,
-       STAC_DELL_M6_DMIC,
-       STAC_DELL_M6_BOTH,
-       STAC_DELL_EQ,
-       STAC_ALIENWARE_M17X,
-       STAC_ELO_VUPOINT_15MX,
-       STAC_92HD89XX_HP_FRONT_JACK,
-       STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK,
-       STAC_92HD73XX_ASUS_MOBO,
-       STAC_92HD73XX_MODELS
-};
-
-enum {
-       STAC_92HD83XXX_REF,
-       STAC_92HD83XXX_PWR_REF,
-       STAC_DELL_S14,
-       STAC_DELL_VOSTRO_3500,
-       STAC_92HD83XXX_HP_cNB11_INTQUAD,
-       STAC_HP_DV7_4000,
-       STAC_HP_ZEPHYR,
-       STAC_92HD83XXX_HP_LED,
-       STAC_92HD83XXX_HP_INV_LED,
-       STAC_92HD83XXX_HP_MIC_LED,
-       STAC_HP_LED_GPIO10,
-       STAC_92HD83XXX_HEADSET_JACK,
-       STAC_92HD83XXX_HP,
-       STAC_HP_ENVY_BASS,
-       STAC_HP_BNB13_EQ,
-       STAC_HP_ENVY_TS_BASS,
-       STAC_HP_ENVY_TS_DAC_BIND,
-       STAC_92HD83XXX_GPIO10_EAPD,
-       STAC_92HD83XXX_MODELS
-};
-
-enum {
-       STAC_92HD71BXX_REF,
-       STAC_DELL_M4_1,
-       STAC_DELL_M4_2,
-       STAC_DELL_M4_3,
-       STAC_HP_M4,
-       STAC_HP_DV4,
-       STAC_HP_DV5,
-       STAC_HP_HDX,
-       STAC_92HD71BXX_HP,
-       STAC_92HD71BXX_NO_DMIC,
-       STAC_92HD71BXX_NO_SMUX,
-       STAC_92HD71BXX_MODELS
-};
-
-enum {
-       STAC_92HD95_HP_LED,
-       STAC_92HD95_HP_BASS,
-       STAC_92HD95_MODELS
-};
-
-enum {
-       STAC_925x_REF,
-       STAC_M1,
-       STAC_M1_2,
-       STAC_M2,
-       STAC_M2_2,
-       STAC_M3,
-       STAC_M5,
-       STAC_M6,
-       STAC_925x_MODELS
-};
-
-enum {
-       STAC_D945_REF,
-       STAC_D945GTP3,
-       STAC_D945GTP5,
-       STAC_INTEL_MAC_V1,
-       STAC_INTEL_MAC_V2,
-       STAC_INTEL_MAC_V3,
-       STAC_INTEL_MAC_V4,
-       STAC_INTEL_MAC_V5,
-       STAC_INTEL_MAC_AUTO,
-       STAC_ECS_202,
-       STAC_922X_DELL_D81,
-       STAC_922X_DELL_D82,
-       STAC_922X_DELL_M81,
-       STAC_922X_DELL_M82,
-       STAC_922X_INTEL_MAC_GPIO,
-       STAC_922X_MODELS
-};
-
-enum {
-       STAC_D965_REF_NO_JD, /* no jack-detection */
-       STAC_D965_REF,
-       STAC_D965_3ST,
-       STAC_D965_5ST,
-       STAC_D965_5ST_NO_FP,
-       STAC_D965_VERBS,
-       STAC_DELL_3ST,
-       STAC_DELL_BIOS,
-       STAC_NEMO_DEFAULT,
-       STAC_DELL_BIOS_AMIC,
-       STAC_DELL_BIOS_SPDIF,
-       STAC_927X_DELL_DMIC,
-       STAC_927X_VOLKNOB,
-       STAC_927X_MODELS
-};
-
-enum {
-       STAC_9872_VAIO,
-       STAC_9872_MODELS
-};
-
-struct sigmatel_spec {
-       struct hda_gen_spec gen;
-
-       unsigned int eapd_switch: 1;
-       unsigned int linear_tone_beep:1;
-       unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */
-       unsigned int volknob_init:1; /* special volume-knob initialization */
-       unsigned int powerdown_adcs:1;
-       unsigned int have_spdif_mux:1;
-
-       /* gpio lines */
-       unsigned int eapd_mask;
-       unsigned int gpio_mask;
-       unsigned int gpio_dir;
-       unsigned int gpio_data;
-       unsigned int gpio_mute;
-       unsigned int gpio_led;
-       unsigned int gpio_led_polarity;
-       unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */
-       unsigned int vref_led;
-       int default_polarity;
-
-       unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */
-       unsigned int mic_enabled; /* current mic mute state (bitmask) */
-
-       /* stream */
-       unsigned int stream_delay;
-
-       /* analog loopback */
-       const struct snd_kcontrol_new *aloopback_ctl;
-       unsigned int aloopback;
-       unsigned char aloopback_mask;
-       unsigned char aloopback_shift;
-
-       /* power management */
-       unsigned int power_map_bits;
-       unsigned int num_pwrs;
-       const hda_nid_t *pwr_nids;
-       unsigned int active_adcs;
-
-       /* beep widgets */
-       hda_nid_t anabeep_nid;
-       bool beep_power_on;
-
-       /* SPDIF-out mux */
-       const char * const *spdif_labels;
-       struct hda_input_mux spdif_mux;
-       unsigned int cur_smux[2];
-};
-
-#define AC_VERB_IDT_SET_POWER_MAP      0x7ec
-#define AC_VERB_IDT_GET_POWER_MAP      0xfec
-
-static const hda_nid_t stac92hd73xx_pwr_nids[8] = {
-       0x0a, 0x0b, 0x0c, 0xd, 0x0e,
-       0x0f, 0x10, 0x11
-};
-
-static const hda_nid_t stac92hd83xxx_pwr_nids[7] = {
-       0x0a, 0x0b, 0x0c, 0xd, 0x0e,
-       0x0f, 0x10
-};
-
-static const hda_nid_t stac92hd71bxx_pwr_nids[3] = {
-       0x0a, 0x0d, 0x0f
-};
-
-
-/*
- * PCM hooks
- */
-static void stac_playback_pcm_hook(struct hda_pcm_stream *hinfo,
-                                  struct hda_codec *codec,
-                                  struct snd_pcm_substream *substream,
-                                  int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       if (action == HDA_GEN_PCM_ACT_OPEN && spec->stream_delay)
-               msleep(spec->stream_delay);
-}
-
-static void stac_capture_pcm_hook(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 struct snd_pcm_substream *substream,
-                                 int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int i, idx = 0;
-
-       if (!spec->powerdown_adcs)
-               return;
-
-       for (i = 0; i < spec->gen.num_all_adcs; i++) {
-               if (spec->gen.all_adcs[i] == hinfo->nid) {
-                       idx = i;
-                       break;
-               }
-       }
-
-       switch (action) {
-       case HDA_GEN_PCM_ACT_OPEN:
-               msleep(40);
-               snd_hda_codec_write(codec, hinfo->nid, 0,
-                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
-               spec->active_adcs |= (1 << idx);
-               break;
-       case HDA_GEN_PCM_ACT_CLOSE:
-               snd_hda_codec_write(codec, hinfo->nid, 0,
-                                   AC_VERB_SET_POWER_STATE, AC_PWRST_D3);
-               spec->active_adcs &= ~(1 << idx);
-               break;
-       }
-}
-
-/*
- * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a
- * funky external mute control using GPIO pins.
- */
-
-static void stac_gpio_set(struct hda_codec *codec, unsigned int mask,
-                         unsigned int dir_mask, unsigned int data)
-{
-       unsigned int gpiostate, gpiomask, gpiodir;
-       hda_nid_t fg = codec->core.afg;
-
-       codec_dbg(codec, "%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data);
-
-       gpiostate = snd_hda_codec_read(codec, fg, 0,
-                                      AC_VERB_GET_GPIO_DATA, 0);
-       gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask);
-
-       gpiomask = snd_hda_codec_read(codec, fg, 0,
-                                     AC_VERB_GET_GPIO_MASK, 0);
-       gpiomask |= mask;
-
-       gpiodir = snd_hda_codec_read(codec, fg, 0,
-                                    AC_VERB_GET_GPIO_DIRECTION, 0);
-       gpiodir |= dir_mask;
-
-       /* Configure GPIOx as CMOS */
-       snd_hda_codec_write(codec, fg, 0, 0x7e7, 0);
-
-       snd_hda_codec_write(codec, fg, 0,
-                           AC_VERB_SET_GPIO_MASK, gpiomask);
-       snd_hda_codec_read(codec, fg, 0,
-                          AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */
-
-       msleep(1);
-
-       snd_hda_codec_read(codec, fg, 0,
-                          AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */
-}
-
-/* hook for controlling mic-mute LED GPIO */
-static int stac_capture_led_update(struct led_classdev *led_cdev,
-                                  enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (brightness)
-               spec->gpio_data |= spec->mic_mute_led_gpio;
-       else
-               spec->gpio_data &= ~spec->mic_mute_led_gpio;
-       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
-       return 0;
-}
-
-static int stac_vrefout_set(struct hda_codec *codec,
-                                       hda_nid_t nid, unsigned int new_vref)
-{
-       int error, pinctl;
-
-       codec_dbg(codec, "%s, nid %x ctl %x\n", __func__, nid, new_vref);
-       pinctl = snd_hda_codec_read(codec, nid, 0,
-                               AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
-
-       if (pinctl < 0)
-               return pinctl;
-
-       pinctl &= 0xff;
-       pinctl &= ~AC_PINCTL_VREFEN;
-       pinctl |= (new_vref & AC_PINCTL_VREFEN);
-
-       error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl);
-       if (error < 0)
-               return error;
-
-       return 1;
-}
-
-/* prevent codec AFG to D3 state when vref-out pin is used for mute LED */
-/* this hook is set in stac_setup_gpio() */
-static unsigned int stac_vref_led_power_filter(struct hda_codec *codec,
-                                              hda_nid_t nid,
-                                              unsigned int power_state)
-{
-       if (nid == codec->core.afg && power_state == AC_PWRST_D3)
-               return AC_PWRST_D1;
-       return snd_hda_gen_path_power_filter(codec, nid, power_state);
-}
-
-/* update mute-LED accoring to the master switch */
-static void stac_update_led_status(struct hda_codec *codec, bool muted)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (!spec->gpio_led)
-               return;
-
-       /* LED state is inverted on these systems */
-       if (spec->gpio_led_polarity)
-               muted = !muted;
-
-       if (!spec->vref_mute_led_nid) {
-               if (muted)
-                       spec->gpio_data |= spec->gpio_led;
-               else
-                       spec->gpio_data &= ~spec->gpio_led;
-               stac_gpio_set(codec, spec->gpio_mask,
-                               spec->gpio_dir, spec->gpio_data);
-       } else {
-               spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD;
-               stac_vrefout_set(codec, spec->vref_mute_led_nid,
-                                spec->vref_led);
-       }
-}
-
-/* vmaster hook to update mute LED */
-static int stac_vmaster_hook(struct led_classdev *led_cdev,
-                            enum led_brightness brightness)
-{
-       struct hda_codec *codec = dev_to_hda_codec(led_cdev->dev->parent);
-
-       stac_update_led_status(codec, brightness);
-       return 0;
-}
-
-/* automute hook to handle GPIO mute and EAPD updates */
-static void stac_update_outputs(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (spec->gpio_mute)
-               spec->gen.master_mute =
-                       !(snd_hda_codec_read(codec, codec->core.afg, 0,
-                               AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute);
-
-       snd_hda_gen_update_outputs(codec);
-
-       if (spec->eapd_mask && spec->eapd_switch) {
-               unsigned int val = spec->gpio_data;
-               if (spec->gen.speaker_muted)
-                       val &= ~spec->eapd_mask;
-               else
-                       val |= spec->eapd_mask;
-               if (spec->gpio_data != val) {
-                       spec->gpio_data = val;
-                       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir,
-                                     val);
-               }
-       }
-}
-
-static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid,
-                                 bool enable, bool do_write)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int idx, val;
-
-       for (idx = 0; idx < spec->num_pwrs; idx++) {
-               if (spec->pwr_nids[idx] == nid)
-                       break;
-       }
-       if (idx >= spec->num_pwrs)
-               return;
-
-       idx = 1 << idx;
-
-       val = spec->power_map_bits;
-       if (enable)
-               val &= ~idx;
-       else
-               val |= idx;
-
-       /* power down unused output ports */
-       if (val != spec->power_map_bits) {
-               spec->power_map_bits = val;
-               if (do_write)
-                       snd_hda_codec_write(codec, codec->core.afg, 0,
-                                           AC_VERB_IDT_SET_POWER_MAP, val);
-       }
-}
-
-/* update power bit per jack plug/unplug */
-static void jack_update_power(struct hda_codec *codec,
-                             struct hda_jack_callback *jack)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int i;
-
-       if (!spec->num_pwrs)
-               return;
-
-       if (jack && jack->nid) {
-               stac_toggle_power_map(codec, jack->nid,
-                                     snd_hda_jack_detect(codec, jack->nid),
-                                     true);
-               return;
-       }
-
-       /* update all jacks */
-       for (i = 0; i < spec->num_pwrs; i++) {
-               hda_nid_t nid = spec->pwr_nids[i];
-               if (!snd_hda_jack_tbl_get(codec, nid))
-                       continue;
-               stac_toggle_power_map(codec, nid,
-                                     snd_hda_jack_detect(codec, nid),
-                                     false);
-       }
-
-       snd_hda_codec_write(codec, codec->core.afg, 0,
-                           AC_VERB_IDT_SET_POWER_MAP,
-                           spec->power_map_bits);
-}
-
-static void stac_vref_event(struct hda_codec *codec,
-                           struct hda_jack_callback *event)
-{
-       unsigned int data;
-
-       data = snd_hda_codec_read(codec, codec->core.afg, 0,
-                                 AC_VERB_GET_GPIO_DATA, 0);
-       /* toggle VREF state based on GPIOx status */
-       snd_hda_codec_write(codec, codec->core.afg, 0, 0x7e0,
-                           !!(data & (1 << event->private_data)));
-}
-
-/* initialize the power map and enable the power event to jacks that
- * haven't been assigned to automute
- */
-static void stac_init_power_map(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int i;
-
-       for (i = 0; i < spec->num_pwrs; i++)  {
-               hda_nid_t nid = spec->pwr_nids[i];
-               unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid);
-               def_conf = get_defcfg_connect(def_conf);
-               if (def_conf == AC_JACK_PORT_COMPLEX &&
-                   spec->vref_mute_led_nid != nid &&
-                   is_jack_detectable(codec, nid)) {
-                       snd_hda_jack_detect_enable_callback(codec, nid,
-                                                           jack_update_power);
-               } else {
-                       if (def_conf == AC_JACK_PORT_NONE)
-                               stac_toggle_power_map(codec, nid, false, false);
-                       else
-                               stac_toggle_power_map(codec, nid, true, false);
-               }
-       }
-}
-
-/*
- */
-
-static inline bool get_int_hint(struct hda_codec *codec, const char *key,
-                               int *valp)
-{
-       return !snd_hda_get_int_hint(codec, key, valp);
-}
-
-/* override some hints from the hwdep entry */
-static void stac_store_hints(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int val;
-
-       if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) {
-               spec->eapd_mask = spec->gpio_dir = spec->gpio_data =
-                       spec->gpio_mask;
-       }
-       if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir))
-               spec->gpio_dir &= spec->gpio_mask;
-       if (get_int_hint(codec, "gpio_data", &spec->gpio_data))
-               spec->gpio_data &= spec->gpio_mask;
-       if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask))
-               spec->eapd_mask &= spec->gpio_mask;
-       if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute))
-               spec->gpio_mute &= spec->gpio_mask;
-       val = snd_hda_get_bool_hint(codec, "eapd_switch");
-       if (val >= 0)
-               spec->eapd_switch = val;
-}
-
-/*
- * loopback controls
- */
-
-#define stac_aloopback_info snd_ctl_boolean_mono_info
-
-static int stac_aloopback_get(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       struct sigmatel_spec *spec = codec->spec;
-
-       ucontrol->value.integer.value[0] = !!(spec->aloopback &
-                                             (spec->aloopback_mask << idx));
-       return 0;
-}
-
-static int stac_aloopback_put(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-       unsigned int dac_mode;
-       unsigned int val, idx_val;
-
-       idx_val = spec->aloopback_mask << idx;
-       if (ucontrol->value.integer.value[0])
-               val = spec->aloopback | idx_val;
-       else
-               val = spec->aloopback & ~idx_val;
-       if (spec->aloopback == val)
-               return 0;
-
-       spec->aloopback = val;
-
-       /* Only return the bits defined by the shift value of the
-        * first two bytes of the mask
-        */
-       dac_mode = snd_hda_codec_read(codec, codec->core.afg, 0,
-                                     kcontrol->private_value & 0xFFFF, 0x0);
-       dac_mode >>= spec->aloopback_shift;
-
-       if (spec->aloopback & idx_val) {
-               snd_hda_power_up(codec);
-               dac_mode |= idx_val;
-       } else {
-               snd_hda_power_down(codec);
-               dac_mode &= ~idx_val;
-       }
-
-       snd_hda_codec_write_cache(codec, codec->core.afg, 0,
-               kcontrol->private_value >> 16, dac_mode);
-
-       return 1;
-}
-
-#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \
-       { \
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-               .name  = "Analog Loopback", \
-               .count = cnt, \
-               .info  = stac_aloopback_info, \
-               .get   = stac_aloopback_get, \
-               .put   = stac_aloopback_put, \
-               .private_value = verb_read | (verb_write << 16), \
-       }
-
-/*
- * Mute LED handling on HP laptops
- */
-
-/* check whether it's a HP laptop with a docking port */
-static bool hp_bnb2011_with_dock(struct hda_codec *codec)
-{
-       if (codec->core.vendor_id != 0x111d7605 &&
-           codec->core.vendor_id != 0x111d76d1)
-               return false;
-
-       switch (codec->core.subsystem_id) {
-       case 0x103c1618:
-       case 0x103c1619:
-       case 0x103c161a:
-       case 0x103c161b:
-       case 0x103c161c:
-       case 0x103c161d:
-       case 0x103c161e:
-       case 0x103c161f:
-
-       case 0x103c162a:
-       case 0x103c162b:
-
-       case 0x103c1630:
-       case 0x103c1631:
-
-       case 0x103c1633:
-       case 0x103c1634:
-       case 0x103c1635:
-
-       case 0x103c3587:
-       case 0x103c3588:
-       case 0x103c3589:
-       case 0x103c358a:
-
-       case 0x103c3667:
-       case 0x103c3668:
-       case 0x103c3669:
-
-               return true;
-       }
-       return false;
-}
-
-static bool hp_blike_system(u32 subsystem_id)
-{
-       switch (subsystem_id) {
-       case 0x103c1473: /* HP ProBook 6550b */
-       case 0x103c1520:
-       case 0x103c1521:
-       case 0x103c1523:
-       case 0x103c1524:
-       case 0x103c1525:
-       case 0x103c1722:
-       case 0x103c1723:
-       case 0x103c1724:
-       case 0x103c1725:
-       case 0x103c1726:
-       case 0x103c1727:
-       case 0x103c1728:
-       case 0x103c1729:
-       case 0x103c172a:
-       case 0x103c172b:
-       case 0x103c307e:
-       case 0x103c307f:
-       case 0x103c3080:
-       case 0x103c3081:
-       case 0x103c7007:
-       case 0x103c7008:
-               return true;
-       }
-       return false;
-}
-
-static void set_hp_led_gpio(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int gpio;
-
-       if (spec->gpio_led)
-               return;
-
-       gpio = snd_hda_param_read(codec, codec->core.afg, AC_PAR_GPIO_CAP);
-       gpio &= AC_GPIO_IO_COUNT;
-       if (gpio > 3)
-               spec->gpio_led = 0x08; /* GPIO 3 */
-       else
-               spec->gpio_led = 0x01; /* GPIO 0 */
-}
-
-/*
- * This method searches for the mute LED GPIO configuration
- * provided as OEM string in SMBIOS. The format of that string
- * is HP_Mute_LED_P_G or HP_Mute_LED_P
- * where P can be 0 or 1 and defines mute LED GPIO control state (low/high)
- * that corresponds to the NOT muted state of the master volume
- * and G is the index of the GPIO to use as the mute LED control (0..9)
- * If _G portion is missing it is assigned based on the codec ID
- *
- * So, HP B-series like systems may have HP_Mute_LED_0 (current models)
- * or  HP_Mute_LED_0_3 (future models) OEM SMBIOS strings
- *
- *
- * The dv-series laptops don't seem to have the HP_Mute_LED* strings in
- * SMBIOS - at least the ones I have seen do not have them - which include
- * my own system (HP Pavilion dv6-1110ax) and my cousin's
- * HP Pavilion dv9500t CTO.
- * Need more information on whether it is true across the entire series.
- * -- kunal
- */
-static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       const struct dmi_device *dev = NULL;
-
-       if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) {
-               get_int_hint(codec, "gpio_led_polarity",
-                            &spec->gpio_led_polarity);
-               return 1;
-       }
-
-       while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
-               if (sscanf(dev->name, "HP_Mute_LED_%u_%x",
-                          &spec->gpio_led_polarity,
-                          &spec->gpio_led) == 2) {
-                       unsigned int max_gpio;
-                       max_gpio = snd_hda_param_read(codec, codec->core.afg,
-                                                     AC_PAR_GPIO_CAP);
-                       max_gpio &= AC_GPIO_IO_COUNT;
-                       if (spec->gpio_led < max_gpio)
-                               spec->gpio_led = 1 << spec->gpio_led;
-                       else
-                               spec->vref_mute_led_nid = spec->gpio_led;
-                       return 1;
-               }
-               if (sscanf(dev->name, "HP_Mute_LED_%u",
-                          &spec->gpio_led_polarity) == 1) {
-                       set_hp_led_gpio(codec);
-                       return 1;
-               }
-               /* BIOS bug: unfilled OEM string */
-               if (strstr(dev->name, "HP_Mute_LED_P_G")) {
-                       set_hp_led_gpio(codec);
-                       if (default_polarity >= 0)
-                               spec->gpio_led_polarity = default_polarity;
-                       else
-                               spec->gpio_led_polarity = 1;
-                       return 1;
-               }
-       }
-
-       /*
-        * Fallback case - if we don't find the DMI strings,
-        * we statically set the GPIO - if not a B-series system
-        * and default polarity is provided
-        */
-       if (!hp_blike_system(codec->core.subsystem_id) &&
-           (default_polarity == 0 || default_polarity == 1)) {
-               set_hp_led_gpio(codec);
-               spec->gpio_led_polarity = default_polarity;
-               return 1;
-       }
-       return 0;
-}
-
-/* check whether a built-in speaker is included in parsed pins */
-static bool has_builtin_speaker(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       const hda_nid_t *nid_pin;
-       int nids, i;
-
-       if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) {
-               nid_pin = spec->gen.autocfg.line_out_pins;
-               nids = spec->gen.autocfg.line_outs;
-       } else {
-               nid_pin = spec->gen.autocfg.speaker_pins;
-               nids = spec->gen.autocfg.speaker_outs;
-       }
-
-       for (i = 0; i < nids; i++) {
-               unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid_pin[i]);
-               if (snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT)
-                       return true;
-       }
-       return false;
-}
-
-/*
- * PC beep controls
- */
-
-/* create PC beep volume controls */
-static int stac_auto_create_beep_ctls(struct hda_codec *codec,
-                                               hda_nid_t nid)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT);
-       struct snd_kcontrol_new *knew;
-       static const struct snd_kcontrol_new abeep_mute_ctl =
-               HDA_CODEC_MUTE(NULL, 0, 0, 0);
-       static const struct snd_kcontrol_new dbeep_mute_ctl =
-               HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0);
-       static const struct snd_kcontrol_new beep_vol_ctl =
-               HDA_CODEC_VOLUME(NULL, 0, 0, 0);
-
-       /* check for mute support for the amp */
-       if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) {
-               const struct snd_kcontrol_new *temp;
-               if (spec->anabeep_nid == nid)
-                       temp = &abeep_mute_ctl;
-               else
-                       temp = &dbeep_mute_ctl;
-               knew = snd_hda_gen_add_kctl(&spec->gen,
-                                           "Beep Playback Switch", temp);
-               if (!knew)
-                       return -ENOMEM;
-               knew->private_value =
-                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT);
-       }
-
-       /* check to see if there is volume support for the amp */
-       if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) {
-               knew = snd_hda_gen_add_kctl(&spec->gen,
-                                           "Beep Playback Volume",
-                                           &beep_vol_ctl);
-               if (!knew)
-                       return -ENOMEM;
-               knew->private_value =
-                       HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT);
-       }
-       return 0;
-}
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-#define stac_dig_beep_switch_info snd_ctl_boolean_mono_info
-
-static int stac_dig_beep_switch_get(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       ucontrol->value.integer.value[0] = codec->beep->enabled;
-       return 0;
-}
-
-static int stac_dig_beep_switch_put(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]);
-}
-
-static const struct snd_kcontrol_new stac_dig_beep_ctrl = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Beep Playback Switch",
-       .info = stac_dig_beep_switch_info,
-       .get = stac_dig_beep_switch_get,
-       .put = stac_dig_beep_switch_put,
-};
-
-static int stac_beep_switch_ctl(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_dig_beep_ctrl))
-               return -ENOMEM;
-       return 0;
-}
-#endif
-
-/*
- * SPDIF-out mux controls
- */
-
-static int stac_smux_enum_info(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_info *uinfo)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-       return snd_hda_input_mux_info(&spec->spdif_mux, uinfo);
-}
-
-static int stac_smux_enum_get(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-       ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx];
-       return 0;
-}
-
-static int stac_smux_enum_put(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
-
-       return snd_hda_input_mux_put(codec, &spec->spdif_mux, ucontrol,
-                                    spec->gen.autocfg.dig_out_pins[smux_idx],
-                                    &spec->cur_smux[smux_idx]);
-}
-
-static const struct snd_kcontrol_new stac_smux_mixer = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "IEC958 Playback Source",
-       /* count set later */
-       .info = stac_smux_enum_info,
-       .get = stac_smux_enum_get,
-       .put = stac_smux_enum_put,
-};
-
-static const char * const stac_spdif_labels[] = {
-       "Digital Playback", "Analog Mux 1", "Analog Mux 2", NULL
-};
-
-static int stac_create_spdif_mux_ctls(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       struct auto_pin_cfg *cfg = &spec->gen.autocfg;
-       const char * const *labels = spec->spdif_labels;
-       struct snd_kcontrol_new *kctl;
-       int i, num_cons;
-
-       if (cfg->dig_outs < 1)
-               return 0;
-
-       num_cons = snd_hda_get_num_conns(codec, cfg->dig_out_pins[0]);
-       if (num_cons <= 1)
-               return 0;
-
-       if (!labels)
-               labels = stac_spdif_labels;
-       for (i = 0; i < num_cons; i++) {
-               if (snd_BUG_ON(!labels[i]))
-                       return -EINVAL;
-               snd_hda_add_imux_item(codec, &spec->spdif_mux, labels[i], i, NULL);
-       }
-
-       kctl = snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_smux_mixer);
-       if (!kctl)
-               return -ENOMEM;
-       kctl->count = cfg->dig_outs;
-
-       return 0;
-}
-
-static const struct hda_verb stac9200_eapd_init[] = {
-       /* set dac0mux for dac converter */
-       {0x07, AC_VERB_SET_CONNECT_SEL, 0x00},
-       {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-       {}
-};
-
-static const struct hda_verb dell_eq_core_init[] = {
-       /* set master volume to max value without distortion
-        * and direct control */
-       { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xec},
-       {}
-};
-
-static const struct hda_verb stac92hd73xx_core_init[] = {
-       /* set master volume and direct control */
-       { 0x1f, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       {}
-};
-
-static const struct hda_verb stac92hd83xxx_core_init[] = {
-       /* power state controls amps */
-       { 0x01, AC_VERB_SET_EAPD, 1 << 2},
-       {}
-};
-
-static const struct hda_verb stac92hd83xxx_hp_zephyr_init[] = {
-       { 0x22, 0x785, 0x43 },
-       { 0x22, 0x782, 0xe0 },
-       { 0x22, 0x795, 0x00 },
-       {}
-};
-
-static const struct hda_verb stac92hd71bxx_core_init[] = {
-       /* set master volume and direct control */
-       { 0x28, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       {}
-};
-
-static const hda_nid_t stac92hd71bxx_unmute_nids[] = {
-       /* unmute right and left channels for nodes 0x0f, 0xa, 0x0d */
-       0x0f, 0x0a, 0x0d, 0
-};
-
-static const struct hda_verb stac925x_core_init[] = {
-       /* set dac0mux for dac converter */
-       { 0x06, AC_VERB_SET_CONNECT_SEL, 0x00},
-       /* mute the master volume */
-       { 0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE },
-       {}
-};
-
-static const struct hda_verb stac922x_core_init[] = {
-       /* set master volume and direct control */
-       { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       {}
-};
-
-static const struct hda_verb d965_core_init[] = {
-       /* unmute node 0x1b */
-       { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       /* select node 0x03 as DAC */
-       { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {}
-};
-
-static const struct hda_verb dell_3st_core_init[] = {
-       /* don't set delta bit */
-       {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
-       /* unmute node 0x1b */
-       {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000},
-       /* select node 0x03 as DAC */
-       {0x0b, AC_VERB_SET_CONNECT_SEL, 0x01},
-       {}
-};
-
-static const struct hda_verb stac927x_core_init[] = {
-       /* set master volume and direct control */
-       { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* enable analog pc beep path */
-       { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
-       {}
-};
-
-static const struct hda_verb stac927x_volknob_core_init[] = {
-       /* don't set delta bit */
-       {0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0x7f},
-       /* enable analog pc beep path */
-       {0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
-       {}
-};
-
-static const struct hda_verb stac9205_core_init[] = {
-       /* set master volume and direct control */
-       { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff},
-       /* enable analog pc beep path */
-       { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5},
-       {}
-};
-
-static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback =
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3);
-
-static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback =
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4);
-
-static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback =
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5);
-
-static const struct snd_kcontrol_new stac92hd71bxx_loopback =
-       STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2);
-
-static const struct snd_kcontrol_new stac9205_loopback =
-       STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1);
-
-static const struct snd_kcontrol_new stac927x_loopback =
-       STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1);
-
-static const struct hda_pintbl ref9200_pin_configs[] = {
-       { 0x08, 0x01c47010 },
-       { 0x09, 0x01447010 },
-       { 0x0d, 0x0221401f },
-       { 0x0e, 0x01114010 },
-       { 0x0f, 0x02a19020 },
-       { 0x10, 0x01a19021 },
-       { 0x11, 0x90100140 },
-       { 0x12, 0x01813122 },
-       {}
-};
-
-static const struct hda_pintbl gateway9200_m4_pin_configs[] = {
-       { 0x08, 0x400000fe },
-       { 0x09, 0x404500f4 },
-       { 0x0d, 0x400100f0 },
-       { 0x0e, 0x90110010 },
-       { 0x0f, 0x400100f1 },
-       { 0x10, 0x02a1902e },
-       { 0x11, 0x500000f2 },
-       { 0x12, 0x500000f3 },
-       {}
-};
-
-static const struct hda_pintbl gateway9200_m4_2_pin_configs[] = {
-       { 0x08, 0x400000fe },
-       { 0x09, 0x404500f4 },
-       { 0x0d, 0x400100f0 },
-       { 0x0e, 0x90110010 },
-       { 0x0f, 0x400100f1 },
-       { 0x10, 0x02a1902e },
-       { 0x11, 0x500000f2 },
-       { 0x12, 0x500000f3 },
-       {}
-};
-
-/*
-    STAC 9200 pin configs for
-    102801A8
-    102801DE
-    102801E8
-*/
-static const struct hda_pintbl dell9200_d21_pin_configs[] = {
-       { 0x08, 0x400001f0 },
-       { 0x09, 0x400001f1 },
-       { 0x0d, 0x02214030 },
-       { 0x0e, 0x01014010 },
-       { 0x0f, 0x02a19020 },
-       { 0x10, 0x01a19021 },
-       { 0x11, 0x90100140 },
-       { 0x12, 0x01813122 },
-       {}
-};
-
-/*
-    STAC 9200 pin configs for
-    102801C0
-    102801C1
-*/
-static const struct hda_pintbl dell9200_d22_pin_configs[] = {
-       { 0x08, 0x400001f0 },
-       { 0x09, 0x400001f1 },
-       { 0x0d, 0x0221401f },
-       { 0x0e, 0x01014010 },
-       { 0x0f, 0x01813020 },
-       { 0x10, 0x02a19021 },
-       { 0x11, 0x90100140 },
-       { 0x12, 0x400001f2 },
-       {}
-};
-
-/*
-    STAC 9200 pin configs for
-    102801C4 (Dell Dimension E310)
-    102801C5
-    102801C7
-    102801D9
-    102801DA
-    102801E3
-*/
-static const struct hda_pintbl dell9200_d23_pin_configs[] = {
-       { 0x08, 0x400001f0 },
-       { 0x09, 0x400001f1 },
-       { 0x0d, 0x0221401f },
-       { 0x0e, 0x01014010 },
-       { 0x0f, 0x01813020 },
-       { 0x10, 0x01a19021 },
-       { 0x11, 0x90100140 },
-       { 0x12, 0x400001f2 },
-       {}
-};
-
-
-/* 
-    STAC 9200-32 pin configs for
-    102801B5 (Dell Inspiron 630m)
-    102801D8 (Dell Inspiron 640m)
-*/
-static const struct hda_pintbl dell9200_m21_pin_configs[] = {
-       { 0x08, 0x40c003fa },
-       { 0x09, 0x03441340 },
-       { 0x0d, 0x0321121f },
-       { 0x0e, 0x90170310 },
-       { 0x0f, 0x408003fb },
-       { 0x10, 0x03a11020 },
-       { 0x11, 0x401003fc },
-       { 0x12, 0x403003fd },
-       {}
-};
-
-/* 
-    STAC 9200-32 pin configs for
-    102801C2 (Dell Latitude D620)
-    102801C8 
-    102801CC (Dell Latitude D820)
-    102801D4 
-    102801D6 
-*/
-static const struct hda_pintbl dell9200_m22_pin_configs[] = {
-       { 0x08, 0x40c003fa },
-       { 0x09, 0x0144131f },
-       { 0x0d, 0x0321121f },
-       { 0x0e, 0x90170310 },
-       { 0x0f, 0x90a70321 },
-       { 0x10, 0x03a11020 },
-       { 0x11, 0x401003fb },
-       { 0x12, 0x40f000fc },
-       {}
-};
-
-/* 
-    STAC 9200-32 pin configs for
-    102801CE (Dell XPS M1710)
-    102801CF (Dell Precision M90)
-*/
-static const struct hda_pintbl dell9200_m23_pin_configs[] = {
-       { 0x08, 0x40c003fa },
-       { 0x09, 0x01441340 },
-       { 0x0d, 0x0421421f },
-       { 0x0e, 0x90170310 },
-       { 0x0f, 0x408003fb },
-       { 0x10, 0x04a1102e },
-       { 0x11, 0x90170311 },
-       { 0x12, 0x403003fc },
-       {}
-};
-
-/*
-    STAC 9200-32 pin configs for 
-    102801C9
-    102801CA
-    102801CB (Dell Latitude 120L)
-    102801D3
-*/
-static const struct hda_pintbl dell9200_m24_pin_configs[] = {
-       { 0x08, 0x40c003fa },
-       { 0x09, 0x404003fb },
-       { 0x0d, 0x0321121f },
-       { 0x0e, 0x90170310 },
-       { 0x0f, 0x408003fc },
-       { 0x10, 0x03a11020 },
-       { 0x11, 0x401003fd },
-       { 0x12, 0x403003fe },
-       {}
-};
-
-/*
-    STAC 9200-32 pin configs for
-    102801BD (Dell Inspiron E1505n)
-    102801EE
-    102801EF
-*/
-static const struct hda_pintbl dell9200_m25_pin_configs[] = {
-       { 0x08, 0x40c003fa },
-       { 0x09, 0x01441340 },
-       { 0x0d, 0x0421121f },
-       { 0x0e, 0x90170310 },
-       { 0x0f, 0x408003fb },
-       { 0x10, 0x04a11020 },
-       { 0x11, 0x401003fc },
-       { 0x12, 0x403003fd },
-       {}
-};
-
-/*
-    STAC 9200-32 pin configs for
-    102801F5 (Dell Inspiron 1501)
-    102801F6
-*/
-static const struct hda_pintbl dell9200_m26_pin_configs[] = {
-       { 0x08, 0x40c003fa },
-       { 0x09, 0x404003fb },
-       { 0x0d, 0x0421121f },
-       { 0x0e, 0x90170310 },
-       { 0x0f, 0x408003fc },
-       { 0x10, 0x04a11020 },
-       { 0x11, 0x401003fd },
-       { 0x12, 0x403003fe },
-       {}
-};
-
-/*
-    STAC 9200-32
-    102801CD (Dell Inspiron E1705/9400)
-*/
-static const struct hda_pintbl dell9200_m27_pin_configs[] = {
-       { 0x08, 0x40c003fa },
-       { 0x09, 0x01441340 },
-       { 0x0d, 0x0421121f },
-       { 0x0e, 0x90170310 },
-       { 0x0f, 0x90170310 },
-       { 0x10, 0x04a11020 },
-       { 0x11, 0x90170310 },
-       { 0x12, 0x40f003fc },
-       {}
-};
-
-static const struct hda_pintbl oqo9200_pin_configs[] = {
-       { 0x08, 0x40c000f0 },
-       { 0x09, 0x404000f1 },
-       { 0x0d, 0x0221121f },
-       { 0x0e, 0x02211210 },
-       { 0x0f, 0x90170111 },
-       { 0x10, 0x90a70120 },
-       { 0x11, 0x400000f2 },
-       { 0x12, 0x400000f3 },
-       {}
-};
-
-/*
- *  STAC 92HD700
- *  18881000 Amigaone X1000
- */
-static const struct hda_pintbl nemo_pin_configs[] = {
-       { 0x0a, 0x02214020 },   /* Front panel HP socket */
-       { 0x0b, 0x02a19080 },   /* Front Mic */
-       { 0x0c, 0x0181304e },   /* Line in */
-       { 0x0d, 0x01014010 },   /* Line out */
-       { 0x0e, 0x01a19040 },   /* Rear Mic */
-       { 0x0f, 0x01011012 },   /* Rear speakers */
-       { 0x10, 0x01016011 },   /* Center speaker */
-       { 0x11, 0x01012014 },   /* Side speakers (7.1) */
-       { 0x12, 0x103301f0 },   /* Motherboard CD line in connector */
-       { 0x13, 0x411111f0 },   /* Unused */
-       { 0x14, 0x411111f0 },   /* Unused */
-       { 0x21, 0x01442170 },   /* S/PDIF line out */
-       { 0x22, 0x411111f0 },   /* Unused */
-       { 0x23, 0x411111f0 },   /* Unused */
-       {}
-};
-
-static void stac9200_fixup_panasonic(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gpio_mask = spec->gpio_dir = 0x09;
-               spec->gpio_data = 0x00;
-               /* CF-74 has no headphone detection, and the driver should *NOT*
-                * do detection and HP/speaker toggle because the hardware does it.
-                */
-               spec->gen.suppress_auto_mute = 1;
-       }
-}
-
-
-static const struct hda_fixup stac9200_fixups[] = {
-       [STAC_REF] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = ref9200_pin_configs,
-       },
-       [STAC_9200_OQO] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = oqo9200_pin_configs,
-               .chained = true,
-               .chain_id = STAC_9200_EAPD_INIT,
-       },
-       [STAC_9200_DELL_D21] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_d21_pin_configs,
-       },
-       [STAC_9200_DELL_D22] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_d22_pin_configs,
-       },
-       [STAC_9200_DELL_D23] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_d23_pin_configs,
-       },
-       [STAC_9200_DELL_M21] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_m21_pin_configs,
-       },
-       [STAC_9200_DELL_M22] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_m22_pin_configs,
-       },
-       [STAC_9200_DELL_M23] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_m23_pin_configs,
-       },
-       [STAC_9200_DELL_M24] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_m24_pin_configs,
-       },
-       [STAC_9200_DELL_M25] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_m25_pin_configs,
-       },
-       [STAC_9200_DELL_M26] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_m26_pin_configs,
-       },
-       [STAC_9200_DELL_M27] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell9200_m27_pin_configs,
-       },
-       [STAC_9200_M4] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = gateway9200_m4_pin_configs,
-               .chained = true,
-               .chain_id = STAC_9200_EAPD_INIT,
-       },
-       [STAC_9200_M4_2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = gateway9200_m4_2_pin_configs,
-               .chained = true,
-               .chain_id = STAC_9200_EAPD_INIT,
-       },
-       [STAC_9200_PANASONIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac9200_fixup_panasonic,
-       },
-       [STAC_9200_EAPD_INIT] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
-                       {}
-               },
-       },
-};
-
-static const struct hda_model_fixup stac9200_models[] = {
-       { .id = STAC_REF, .name = "ref" },
-       { .id = STAC_9200_OQO, .name = "oqo" },
-       { .id = STAC_9200_DELL_D21, .name = "dell-d21" },
-       { .id = STAC_9200_DELL_D22, .name = "dell-d22" },
-       { .id = STAC_9200_DELL_D23, .name = "dell-d23" },
-       { .id = STAC_9200_DELL_M21, .name = "dell-m21" },
-       { .id = STAC_9200_DELL_M22, .name = "dell-m22" },
-       { .id = STAC_9200_DELL_M23, .name = "dell-m23" },
-       { .id = STAC_9200_DELL_M24, .name = "dell-m24" },
-       { .id = STAC_9200_DELL_M25, .name = "dell-m25" },
-       { .id = STAC_9200_DELL_M26, .name = "dell-m26" },
-       { .id = STAC_9200_DELL_M27, .name = "dell-m27" },
-       { .id = STAC_9200_M4, .name = "gateway-m4" },
-       { .id = STAC_9200_M4_2, .name = "gateway-m4-2" },
-       { .id = STAC_9200_PANASONIC, .name = "panasonic" },
-       {}
-};
-
-static const struct hda_quirk stac9200_fixup_tbl[] = {
-       /* SigmaTel reference board */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
-                     "DFI LanParty", STAC_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
-                     "DFI LanParty", STAC_REF),
-       /* Dell laptops have BIOS problem */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a8,
-                     "unknown Dell", STAC_9200_DELL_D21),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01b5,
-                     "Dell Inspiron 630m", STAC_9200_DELL_M21),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bd,
-                     "Dell Inspiron E1505n", STAC_9200_DELL_M25),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c0,
-                     "unknown Dell", STAC_9200_DELL_D22),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c1,
-                     "unknown Dell", STAC_9200_DELL_D22),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c2,
-                     "Dell Latitude D620", STAC_9200_DELL_M22),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c5,
-                     "unknown Dell", STAC_9200_DELL_D23),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c7,
-                     "unknown Dell", STAC_9200_DELL_D23),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c8,
-                     "unknown Dell", STAC_9200_DELL_M22),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01c9,
-                     "unknown Dell", STAC_9200_DELL_M24),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ca,
-                     "unknown Dell", STAC_9200_DELL_M24),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cb,
-                     "Dell Latitude 120L", STAC_9200_DELL_M24),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cc,
-                     "Dell Latitude D820", STAC_9200_DELL_M22),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cd,
-                     "Dell Inspiron E1705/9400", STAC_9200_DELL_M27),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ce,
-                     "Dell XPS M1710", STAC_9200_DELL_M23),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01cf,
-                     "Dell Precision M90", STAC_9200_DELL_M23),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d3,
-                     "unknown Dell", STAC_9200_DELL_M22),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d4,
-                     "unknown Dell", STAC_9200_DELL_M22),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d6,
-                     "unknown Dell", STAC_9200_DELL_M22),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d8,
-                     "Dell Inspiron 640m", STAC_9200_DELL_M21),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d9,
-                     "unknown Dell", STAC_9200_DELL_D23),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01da,
-                     "unknown Dell", STAC_9200_DELL_D23),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01de,
-                     "unknown Dell", STAC_9200_DELL_D21),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e3,
-                     "unknown Dell", STAC_9200_DELL_D23),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01e8,
-                     "unknown Dell", STAC_9200_DELL_D21),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ee,
-                     "unknown Dell", STAC_9200_DELL_M25),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ef,
-                     "unknown Dell", STAC_9200_DELL_M25),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f5,
-                     "Dell Inspiron 1501", STAC_9200_DELL_M26),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f6,
-                     "unknown Dell", STAC_9200_DELL_M26),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0201,
-                     "Dell Latitude D430", STAC_9200_DELL_M22),
-       /* Panasonic */
-       SND_PCI_QUIRK(0x10f7, 0x8338, "Panasonic CF-74", STAC_9200_PANASONIC),
-       /* Gateway machines needs EAPD to be set on resume */
-       SND_PCI_QUIRK(0x107b, 0x0205, "Gateway S-7110M", STAC_9200_M4),
-       SND_PCI_QUIRK(0x107b, 0x0317, "Gateway MT3423, MX341*", STAC_9200_M4_2),
-       SND_PCI_QUIRK(0x107b, 0x0318, "Gateway ML3019, MT3707", STAC_9200_M4_2),
-       /* OQO Mobile */
-       SND_PCI_QUIRK(0x1106, 0x3288, "OQO Model 2", STAC_9200_OQO),
-       {} /* terminator */
-};
-
-static const struct hda_pintbl ref925x_pin_configs[] = {
-       { 0x07, 0x40c003f0 },
-       { 0x08, 0x424503f2 },
-       { 0x0a, 0x01813022 },
-       { 0x0b, 0x02a19021 },
-       { 0x0c, 0x90a70320 },
-       { 0x0d, 0x02214210 },
-       { 0x10, 0x01019020 },
-       { 0x11, 0x9033032e },
-       {}
-};
-
-static const struct hda_pintbl stac925xM1_pin_configs[] = {
-       { 0x07, 0x40c003f4 },
-       { 0x08, 0x424503f2 },
-       { 0x0a, 0x400000f3 },
-       { 0x0b, 0x02a19020 },
-       { 0x0c, 0x40a000f0 },
-       { 0x0d, 0x90100210 },
-       { 0x10, 0x400003f1 },
-       { 0x11, 0x9033032e },
-       {}
-};
-
-static const struct hda_pintbl stac925xM1_2_pin_configs[] = {
-       { 0x07, 0x40c003f4 },
-       { 0x08, 0x424503f2 },
-       { 0x0a, 0x400000f3 },
-       { 0x0b, 0x02a19020 },
-       { 0x0c, 0x40a000f0 },
-       { 0x0d, 0x90100210 },
-       { 0x10, 0x400003f1 },
-       { 0x11, 0x9033032e },
-       {}
-};
-
-static const struct hda_pintbl stac925xM2_pin_configs[] = {
-       { 0x07, 0x40c003f4 },
-       { 0x08, 0x424503f2 },
-       { 0x0a, 0x400000f3 },
-       { 0x0b, 0x02a19020 },
-       { 0x0c, 0x40a000f0 },
-       { 0x0d, 0x90100210 },
-       { 0x10, 0x400003f1 },
-       { 0x11, 0x9033032e },
-       {}
-};
-
-static const struct hda_pintbl stac925xM2_2_pin_configs[] = {
-       { 0x07, 0x40c003f4 },
-       { 0x08, 0x424503f2 },
-       { 0x0a, 0x400000f3 },
-       { 0x0b, 0x02a19020 },
-       { 0x0c, 0x40a000f0 },
-       { 0x0d, 0x90100210 },
-       { 0x10, 0x400003f1 },
-       { 0x11, 0x9033032e },
-       {}
-};
-
-static const struct hda_pintbl stac925xM3_pin_configs[] = {
-       { 0x07, 0x40c003f4 },
-       { 0x08, 0x424503f2 },
-       { 0x0a, 0x400000f3 },
-       { 0x0b, 0x02a19020 },
-       { 0x0c, 0x40a000f0 },
-       { 0x0d, 0x90100210 },
-       { 0x10, 0x400003f1 },
-       { 0x11, 0x503303f3 },
-       {}
-};
-
-static const struct hda_pintbl stac925xM5_pin_configs[] = {
-       { 0x07, 0x40c003f4 },
-       { 0x08, 0x424503f2 },
-       { 0x0a, 0x400000f3 },
-       { 0x0b, 0x02a19020 },
-       { 0x0c, 0x40a000f0 },
-       { 0x0d, 0x90100210 },
-       { 0x10, 0x400003f1 },
-       { 0x11, 0x9033032e },
-       {}
-};
-
-static const struct hda_pintbl stac925xM6_pin_configs[] = {
-       { 0x07, 0x40c003f4 },
-       { 0x08, 0x424503f2 },
-       { 0x0a, 0x400000f3 },
-       { 0x0b, 0x02a19020 },
-       { 0x0c, 0x40a000f0 },
-       { 0x0d, 0x90100210 },
-       { 0x10, 0x400003f1 },
-       { 0x11, 0x90330320 },
-       {}
-};
-
-static const struct hda_fixup stac925x_fixups[] = {
-       [STAC_REF] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = ref925x_pin_configs,
-       },
-       [STAC_M1] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac925xM1_pin_configs,
-       },
-       [STAC_M1_2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac925xM1_2_pin_configs,
-       },
-       [STAC_M2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac925xM2_pin_configs,
-       },
-       [STAC_M2_2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac925xM2_2_pin_configs,
-       },
-       [STAC_M3] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac925xM3_pin_configs,
-       },
-       [STAC_M5] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac925xM5_pin_configs,
-       },
-       [STAC_M6] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac925xM6_pin_configs,
-       },
-};
-
-static const struct hda_model_fixup stac925x_models[] = {
-       { .id = STAC_REF, .name = "ref" },
-       { .id = STAC_M1, .name = "m1" },
-       { .id = STAC_M1_2, .name = "m1-2" },
-       { .id = STAC_M2, .name = "m2" },
-       { .id = STAC_M2_2, .name = "m2-2" },
-       { .id = STAC_M3, .name = "m3" },
-       { .id = STAC_M5, .name = "m5" },
-       { .id = STAC_M6, .name = "m6" },
-       {}
-};
-
-static const struct hda_quirk stac925x_fixup_tbl[] = {
-       /* SigmaTel reference board */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF),
-       SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF),
-
-       /* Default table for unknown ID */
-       SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2),
-
-       /* gateway machines are checked via codec ssid */
-       SND_PCI_QUIRK(0x107b, 0x0316, "Gateway M255", STAC_M2),
-       SND_PCI_QUIRK(0x107b, 0x0366, "Gateway MP6954", STAC_M5),
-       SND_PCI_QUIRK(0x107b, 0x0461, "Gateway NX560XL", STAC_M1),
-       SND_PCI_QUIRK(0x107b, 0x0681, "Gateway NX860", STAC_M2),
-       SND_PCI_QUIRK(0x107b, 0x0367, "Gateway MX6453", STAC_M1_2),
-       /* Not sure about the brand name for those */
-       SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M1),
-       SND_PCI_QUIRK(0x107b, 0x0507, "Gateway mobile", STAC_M3),
-       SND_PCI_QUIRK(0x107b, 0x0281, "Gateway mobile", STAC_M6),
-       SND_PCI_QUIRK(0x107b, 0x0685, "Gateway mobile", STAC_M2_2),
-       {} /* terminator */
-};
-
-static const struct hda_pintbl ref92hd73xx_pin_configs[] = {
-       // Port A-H
-       { 0x0a, 0x02214030 },
-       { 0x0b, 0x02a19040 },
-       { 0x0c, 0x01a19020 },
-       { 0x0d, 0x02214030 },
-       { 0x0e, 0x0181302e },
-       { 0x0f, 0x01014010 },
-       { 0x10, 0x01014020 },
-       { 0x11, 0x01014030 },
-       // CD in
-       { 0x12, 0x02319040 },
-       // Digial Mic ins
-       { 0x13, 0x90a000f0 },
-       { 0x14, 0x90a000f0 },
-       // Digital outs
-       { 0x22, 0x01452050 },
-       { 0x23, 0x01452050 },
-       {}
-};
-
-static const struct hda_pintbl dell_m6_pin_configs[] = {
-       { 0x0a, 0x0321101f },
-       { 0x0b, 0x4f00000f },
-       { 0x0c, 0x4f0000f0 },
-       { 0x0d, 0x90170110 },
-       { 0x0e, 0x03a11020 },
-       { 0x0f, 0x0321101f },
-       { 0x10, 0x4f0000f0 },
-       { 0x11, 0x4f0000f0 },
-       { 0x12, 0x4f0000f0 },
-       { 0x13, 0x90a60160 },
-       { 0x14, 0x4f0000f0 },
-       { 0x22, 0x4f0000f0 },
-       { 0x23, 0x4f0000f0 },
-       {}
-};
-
-static const struct hda_pintbl alienware_m17x_pin_configs[] = {
-       { 0x0a, 0x0321101f },
-       { 0x0b, 0x0321101f },
-       { 0x0c, 0x03a11020 },
-       { 0x0d, 0x03014020 },
-       { 0x0e, 0x90170110 },
-       { 0x0f, 0x4f0000f0 },
-       { 0x10, 0x4f0000f0 },
-       { 0x11, 0x4f0000f0 },
-       { 0x12, 0x4f0000f0 },
-       { 0x13, 0x90a60160 },
-       { 0x14, 0x4f0000f0 },
-       { 0x22, 0x4f0000f0 },
-       { 0x23, 0x904601b0 },
-       {}
-};
-
-static const struct hda_pintbl intel_dg45id_pin_configs[] = {
-       // Analog outputs
-       { 0x0a, 0x02214230 },
-       { 0x0b, 0x02A19240 },
-       { 0x0c, 0x01013214 },
-       { 0x0d, 0x01014210 },
-       { 0x0e, 0x01A19250 },
-       { 0x0f, 0x01011212 },
-       { 0x10, 0x01016211 },
-       // Digital output
-       { 0x22, 0x01451380 },
-       { 0x23, 0x40f000f0 },
-       {}
-};
-
-static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = {
-       { 0x0a, 0x02214030 },
-       { 0x0b, 0x02A19010 },
-       {}
-};
-
-static const struct hda_pintbl stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs[] = {
-       { 0x0e, 0x400000f0 },
-       {}
-};
-
-static void stac92hd73xx_fixup_ref(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       snd_hda_apply_pincfgs(codec, ref92hd73xx_pin_configs);
-       spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0;
-}
-
-static void stac92hd73xx_fixup_dell(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       snd_hda_apply_pincfgs(codec, dell_m6_pin_configs);
-       spec->eapd_switch = 0;
-}
-
-static void stac92hd73xx_fixup_dell_eq(struct hda_codec *codec,
-                                      const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       stac92hd73xx_fixup_dell(codec);
-       snd_hda_add_verbs(codec, dell_eq_core_init);
-       spec->volknob_init = 1;
-}
-
-/* Analog Mics */
-static void stac92hd73xx_fixup_dell_m6_amic(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       stac92hd73xx_fixup_dell(codec);
-       snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
-}
-
-/* Digital Mics */
-static void stac92hd73xx_fixup_dell_m6_dmic(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       stac92hd73xx_fixup_dell(codec);
-       snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
-}
-
-/* Both */
-static void stac92hd73xx_fixup_dell_m6_both(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       stac92hd73xx_fixup_dell(codec);
-       snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170);
-       snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160);
-}
-
-static void stac92hd73xx_fixup_alienware_m17x(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       snd_hda_apply_pincfgs(codec, alienware_m17x_pin_configs);
-       spec->eapd_switch = 0;
-}
-
-static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               codec->no_jack_detect = 1;
-}
-
-
-static void stac92hd73xx_disable_automute(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       spec->gen.suppress_auto_mute = 1;
-}
-
-static const struct hda_fixup stac92hd73xx_fixups[] = {
-       [STAC_92HD73XX_REF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd73xx_fixup_ref,
-       },
-       [STAC_DELL_M6_AMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd73xx_fixup_dell_m6_amic,
-       },
-       [STAC_DELL_M6_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd73xx_fixup_dell_m6_dmic,
-       },
-       [STAC_DELL_M6_BOTH] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd73xx_fixup_dell_m6_both,
-       },
-       [STAC_DELL_EQ]  = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd73xx_fixup_dell_eq,
-       },
-       [STAC_ALIENWARE_M17X] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd73xx_fixup_alienware_m17x,
-       },
-       [STAC_ELO_VUPOINT_15MX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd73xx_disable_automute,
-       },
-       [STAC_92HD73XX_INTEL] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = intel_dg45id_pin_configs,
-       },
-       [STAC_92HD73XX_NO_JD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd73xx_fixup_no_jd,
-       },
-       [STAC_92HD89XX_HP_FRONT_JACK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac92hd89xx_hp_front_jack_pin_configs,
-       },
-       [STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac92hd89xx_hp_z1_g2_right_mic_jack_pin_configs,
-       },
-       [STAC_92HD73XX_ASUS_MOBO] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* enable 5.1 and SPDIF out */
-                       { 0x0c, 0x01014411 },
-                       { 0x0d, 0x01014410 },
-                       { 0x0e, 0x01014412 },
-                       { 0x22, 0x014b1180 },
-                       { }
-               }
-       },
-};
-
-static const struct hda_model_fixup stac92hd73xx_models[] = {
-       { .id = STAC_92HD73XX_NO_JD, .name = "no-jd" },
-       { .id = STAC_92HD73XX_REF, .name = "ref" },
-       { .id = STAC_92HD73XX_INTEL, .name = "intel" },
-       { .id = STAC_DELL_M6_AMIC, .name = "dell-m6-amic" },
-       { .id = STAC_DELL_M6_DMIC, .name = "dell-m6-dmic" },
-       { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" },
-       { .id = STAC_DELL_EQ, .name = "dell-eq" },
-       { .id = STAC_ALIENWARE_M17X, .name = "alienware" },
-       { .id = STAC_ELO_VUPOINT_15MX, .name = "elo-vupoint-15mx" },
-       { .id = STAC_92HD73XX_ASUS_MOBO, .name = "asus-mobo" },
-       {}
-};
-
-static const struct hda_quirk stac92hd73xx_fixup_tbl[] = {
-       /* SigmaTel reference board */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
-                               "DFI LanParty", STAC_92HD73XX_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
-                               "DFI LanParty", STAC_92HD73XX_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5001,
-                               "Intel DP45SG", STAC_92HD73XX_INTEL),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5002,
-                               "Intel DG45ID", STAC_92HD73XX_INTEL),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5003,
-                               "Intel DG45FC", STAC_92HD73XX_INTEL),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0254,
-                               "Dell Studio 1535", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0255,
-                               "unknown Dell", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0256,
-                               "unknown Dell", STAC_DELL_M6_BOTH),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0257,
-                               "unknown Dell", STAC_DELL_M6_BOTH),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025e,
-                               "unknown Dell", STAC_DELL_M6_AMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x025f,
-                               "unknown Dell", STAC_DELL_M6_AMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0271,
-                               "unknown Dell", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0272,
-                               "unknown Dell", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x029f,
-                               "Dell Studio 1537", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a0,
-                               "Dell Studio 17", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be,
-                               "Dell Studio 1555", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd,
-                               "Dell Studio 1557", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02fe,
-                               "Dell Studio XPS 1645", STAC_DELL_M6_DMIC),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413,
-                               "Dell Studio 1558", STAC_DELL_M6_DMIC),
-       /* codec SSID matching */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1,
-                     "Alienware M17x", STAC_ALIENWARE_M17X),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a,
-                     "Alienware M17x", STAC_ALIENWARE_M17X),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490,
-                     "Alienware M17x R3", STAC_DELL_EQ),
-       SND_PCI_QUIRK(0x1059, 0x1011,
-                     "ELO VuPoint 15MX", STAC_ELO_VUPOINT_15MX),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1927,
-                               "HP Z1 G2", STAC_92HD89XX_HP_Z1_G2_RIGHT_MIC_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17,
-                               "unknown HP", STAC_92HD89XX_HP_FRONT_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_ASUSTEK, 0x83f8, "ASUS AT4NM10",
-                     STAC_92HD73XX_ASUS_MOBO),
-       {} /* terminator */
-};
-
-static const struct hda_pintbl ref92hd83xxx_pin_configs[] = {
-       { 0x0a, 0x02214030 },
-       { 0x0b, 0x02211010 },
-       { 0x0c, 0x02a19020 },
-       { 0x0d, 0x02170130 },
-       { 0x0e, 0x01014050 },
-       { 0x0f, 0x01819040 },
-       { 0x10, 0x01014020 },
-       { 0x11, 0x90a3014e },
-       { 0x1f, 0x01451160 },
-       { 0x20, 0x98560170 },
-       {}
-};
-
-static const struct hda_pintbl dell_s14_pin_configs[] = {
-       { 0x0a, 0x0221403f },
-       { 0x0b, 0x0221101f },
-       { 0x0c, 0x02a19020 },
-       { 0x0d, 0x90170110 },
-       { 0x0e, 0x40f000f0 },
-       { 0x0f, 0x40f000f0 },
-       { 0x10, 0x40f000f0 },
-       { 0x11, 0x90a60160 },
-       { 0x1f, 0x40f000f0 },
-       { 0x20, 0x40f000f0 },
-       {}
-};
-
-static const struct hda_pintbl dell_vostro_3500_pin_configs[] = {
-       { 0x0a, 0x02a11020 },
-       { 0x0b, 0x0221101f },
-       { 0x0c, 0x400000f0 },
-       { 0x0d, 0x90170110 },
-       { 0x0e, 0x400000f1 },
-       { 0x0f, 0x400000f2 },
-       { 0x10, 0x400000f3 },
-       { 0x11, 0x90a60160 },
-       { 0x1f, 0x400000f4 },
-       { 0x20, 0x400000f5 },
-       {}
-};
-
-static const struct hda_pintbl hp_dv7_4000_pin_configs[] = {
-       { 0x0a, 0x03a12050 },
-       { 0x0b, 0x0321201f },
-       { 0x0c, 0x40f000f0 },
-       { 0x0d, 0x90170110 },
-       { 0x0e, 0x40f000f0 },
-       { 0x0f, 0x40f000f0 },
-       { 0x10, 0x90170110 },
-       { 0x11, 0xd5a30140 },
-       { 0x1f, 0x40f000f0 },
-       { 0x20, 0x40f000f0 },
-       {}
-};
-
-static const struct hda_pintbl hp_zephyr_pin_configs[] = {
-       { 0x0a, 0x01813050 },
-       { 0x0b, 0x0421201f },
-       { 0x0c, 0x04a1205e },
-       { 0x0d, 0x96130310 },
-       { 0x0e, 0x96130310 },
-       { 0x0f, 0x0101401f },
-       { 0x10, 0x1111611f },
-       { 0x11, 0xd5a30130 },
-       {}
-};
-
-static const struct hda_pintbl hp_cNB11_intquad_pin_configs[] = {
-       { 0x0a, 0x40f000f0 },
-       { 0x0b, 0x0221101f },
-       { 0x0c, 0x02a11020 },
-       { 0x0d, 0x92170110 },
-       { 0x0e, 0x40f000f0 },
-       { 0x0f, 0x92170110 },
-       { 0x10, 0x40f000f0 },
-       { 0x11, 0xd5a30130 },
-       { 0x1f, 0x40f000f0 },
-       { 0x20, 0x40f000f0 },
-       {}
-};
-
-static void stac92hd83xxx_fixup_hp(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       if (hp_bnb2011_with_dock(codec)) {
-               snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f);
-               snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e);
-       }
-
-       if (find_mute_led_cfg(codec, spec->default_polarity))
-               codec_dbg(codec, "mute LED gpio %d polarity %d\n",
-                               spec->gpio_led,
-                               spec->gpio_led_polarity);
-
-       /* allow auto-switching of dock line-in */
-       spec->gen.line_in_auto_switch = true;
-}
-
-static void stac92hd83xxx_fixup_hp_zephyr(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       snd_hda_apply_pincfgs(codec, hp_zephyr_pin_configs);
-       snd_hda_add_verbs(codec, stac92hd83xxx_hp_zephyr_init);
-}
-
-static void stac92hd83xxx_fixup_hp_led(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->default_polarity = 0;
-}
-
-static void stac92hd83xxx_fixup_hp_inv_led(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->default_polarity = 1;
-}
-
-static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
-               /* resetting controller clears GPIO, so we need to keep on */
-               codec->core.power_caps &= ~AC_PWRST_CLKSTOP;
-       }
-}
-
-static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gpio_led = 0x10; /* GPIO4 */
-               spec->default_polarity = 0;
-       }
-}
-
-static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->headset_jack = 1;
-}
-
-static void stac92hd83xxx_fixup_gpio10_eapd(struct hda_codec *codec,
-                                           const struct hda_fixup *fix,
-                                           int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-       spec->eapd_mask = spec->gpio_mask = spec->gpio_dir =
-               spec->gpio_data = 0x10;
-       spec->eapd_switch = 0;
-}
-
-static void hp_envy_ts_fixup_dac_bind(struct hda_codec *codec,
-                                           const struct hda_fixup *fix,
-                                           int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       static const hda_nid_t preferred_pairs[] = {
-               0xd, 0x13,
-               0
-       };
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       spec->gen.preferred_dacs = preferred_pairs;
-}
-
-static const struct hda_verb hp_bnb13_eq_verbs[] = {
-       /* 44.1KHz base */
-       { 0x22, 0x7A6, 0x3E },
-       { 0x22, 0x7A7, 0x68 },
-       { 0x22, 0x7A8, 0x17 },
-       { 0x22, 0x7A9, 0x3E },
-       { 0x22, 0x7AA, 0x68 },
-       { 0x22, 0x7AB, 0x17 },
-       { 0x22, 0x7AC, 0x00 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x83 },
-       { 0x22, 0x7A7, 0x2F },
-       { 0x22, 0x7A8, 0xD1 },
-       { 0x22, 0x7A9, 0x83 },
-       { 0x22, 0x7AA, 0x2F },
-       { 0x22, 0x7AB, 0xD1 },
-       { 0x22, 0x7AC, 0x01 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3E },
-       { 0x22, 0x7A7, 0x68 },
-       { 0x22, 0x7A8, 0x17 },
-       { 0x22, 0x7A9, 0x3E },
-       { 0x22, 0x7AA, 0x68 },
-       { 0x22, 0x7AB, 0x17 },
-       { 0x22, 0x7AC, 0x02 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x7C },
-       { 0x22, 0x7A7, 0xC6 },
-       { 0x22, 0x7A8, 0x0C },
-       { 0x22, 0x7A9, 0x7C },
-       { 0x22, 0x7AA, 0xC6 },
-       { 0x22, 0x7AB, 0x0C },
-       { 0x22, 0x7AC, 0x03 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xC3 },
-       { 0x22, 0x7A7, 0x25 },
-       { 0x22, 0x7A8, 0xAF },
-       { 0x22, 0x7A9, 0xC3 },
-       { 0x22, 0x7AA, 0x25 },
-       { 0x22, 0x7AB, 0xAF },
-       { 0x22, 0x7AC, 0x04 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3E },
-       { 0x22, 0x7A7, 0x85 },
-       { 0x22, 0x7A8, 0x73 },
-       { 0x22, 0x7A9, 0x3E },
-       { 0x22, 0x7AA, 0x85 },
-       { 0x22, 0x7AB, 0x73 },
-       { 0x22, 0x7AC, 0x05 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x85 },
-       { 0x22, 0x7A7, 0x39 },
-       { 0x22, 0x7A8, 0xC7 },
-       { 0x22, 0x7A9, 0x85 },
-       { 0x22, 0x7AA, 0x39 },
-       { 0x22, 0x7AB, 0xC7 },
-       { 0x22, 0x7AC, 0x06 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3C },
-       { 0x22, 0x7A7, 0x90 },
-       { 0x22, 0x7A8, 0xB0 },
-       { 0x22, 0x7A9, 0x3C },
-       { 0x22, 0x7AA, 0x90 },
-       { 0x22, 0x7AB, 0xB0 },
-       { 0x22, 0x7AC, 0x07 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x7A },
-       { 0x22, 0x7A7, 0xC6 },
-       { 0x22, 0x7A8, 0x39 },
-       { 0x22, 0x7A9, 0x7A },
-       { 0x22, 0x7AA, 0xC6 },
-       { 0x22, 0x7AB, 0x39 },
-       { 0x22, 0x7AC, 0x08 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xC4 },
-       { 0x22, 0x7A7, 0xE9 },
-       { 0x22, 0x7A8, 0xDC },
-       { 0x22, 0x7A9, 0xC4 },
-       { 0x22, 0x7AA, 0xE9 },
-       { 0x22, 0x7AB, 0xDC },
-       { 0x22, 0x7AC, 0x09 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3D },
-       { 0x22, 0x7A7, 0xE1 },
-       { 0x22, 0x7A8, 0x0D },
-       { 0x22, 0x7A9, 0x3D },
-       { 0x22, 0x7AA, 0xE1 },
-       { 0x22, 0x7AB, 0x0D },
-       { 0x22, 0x7AC, 0x0A },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x89 },
-       { 0x22, 0x7A7, 0xB6 },
-       { 0x22, 0x7A8, 0xEB },
-       { 0x22, 0x7A9, 0x89 },
-       { 0x22, 0x7AA, 0xB6 },
-       { 0x22, 0x7AB, 0xEB },
-       { 0x22, 0x7AC, 0x0B },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x39 },
-       { 0x22, 0x7A7, 0x9D },
-       { 0x22, 0x7A8, 0xFE },
-       { 0x22, 0x7A9, 0x39 },
-       { 0x22, 0x7AA, 0x9D },
-       { 0x22, 0x7AB, 0xFE },
-       { 0x22, 0x7AC, 0x0C },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x76 },
-       { 0x22, 0x7A7, 0x49 },
-       { 0x22, 0x7A8, 0x15 },
-       { 0x22, 0x7A9, 0x76 },
-       { 0x22, 0x7AA, 0x49 },
-       { 0x22, 0x7AB, 0x15 },
-       { 0x22, 0x7AC, 0x0D },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xC8 },
-       { 0x22, 0x7A7, 0x80 },
-       { 0x22, 0x7A8, 0xF5 },
-       { 0x22, 0x7A9, 0xC8 },
-       { 0x22, 0x7AA, 0x80 },
-       { 0x22, 0x7AB, 0xF5 },
-       { 0x22, 0x7AC, 0x0E },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x40 },
-       { 0x22, 0x7A7, 0x00 },
-       { 0x22, 0x7A8, 0x00 },
-       { 0x22, 0x7A9, 0x40 },
-       { 0x22, 0x7AA, 0x00 },
-       { 0x22, 0x7AB, 0x00 },
-       { 0x22, 0x7AC, 0x0F },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x90 },
-       { 0x22, 0x7A7, 0x68 },
-       { 0x22, 0x7A8, 0xF1 },
-       { 0x22, 0x7A9, 0x90 },
-       { 0x22, 0x7AA, 0x68 },
-       { 0x22, 0x7AB, 0xF1 },
-       { 0x22, 0x7AC, 0x10 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x34 },
-       { 0x22, 0x7A7, 0x47 },
-       { 0x22, 0x7A8, 0x6C },
-       { 0x22, 0x7A9, 0x34 },
-       { 0x22, 0x7AA, 0x47 },
-       { 0x22, 0x7AB, 0x6C },
-       { 0x22, 0x7AC, 0x11 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x6F },
-       { 0x22, 0x7A7, 0x97 },
-       { 0x22, 0x7A8, 0x0F },
-       { 0x22, 0x7A9, 0x6F },
-       { 0x22, 0x7AA, 0x97 },
-       { 0x22, 0x7AB, 0x0F },
-       { 0x22, 0x7AC, 0x12 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xCB },
-       { 0x22, 0x7A7, 0xB8 },
-       { 0x22, 0x7A8, 0x94 },
-       { 0x22, 0x7A9, 0xCB },
-       { 0x22, 0x7AA, 0xB8 },
-       { 0x22, 0x7AB, 0x94 },
-       { 0x22, 0x7AC, 0x13 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x40 },
-       { 0x22, 0x7A7, 0x00 },
-       { 0x22, 0x7A8, 0x00 },
-       { 0x22, 0x7A9, 0x40 },
-       { 0x22, 0x7AA, 0x00 },
-       { 0x22, 0x7AB, 0x00 },
-       { 0x22, 0x7AC, 0x14 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x95 },
-       { 0x22, 0x7A7, 0x76 },
-       { 0x22, 0x7A8, 0x5B },
-       { 0x22, 0x7A9, 0x95 },
-       { 0x22, 0x7AA, 0x76 },
-       { 0x22, 0x7AB, 0x5B },
-       { 0x22, 0x7AC, 0x15 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x31 },
-       { 0x22, 0x7A7, 0xAC },
-       { 0x22, 0x7A8, 0x31 },
-       { 0x22, 0x7A9, 0x31 },
-       { 0x22, 0x7AA, 0xAC },
-       { 0x22, 0x7AB, 0x31 },
-       { 0x22, 0x7AC, 0x16 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x6A },
-       { 0x22, 0x7A7, 0x89 },
-       { 0x22, 0x7A8, 0xA5 },
-       { 0x22, 0x7A9, 0x6A },
-       { 0x22, 0x7AA, 0x89 },
-       { 0x22, 0x7AB, 0xA5 },
-       { 0x22, 0x7AC, 0x17 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xCE },
-       { 0x22, 0x7A7, 0x53 },
-       { 0x22, 0x7A8, 0xCF },
-       { 0x22, 0x7A9, 0xCE },
-       { 0x22, 0x7AA, 0x53 },
-       { 0x22, 0x7AB, 0xCF },
-       { 0x22, 0x7AC, 0x18 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x40 },
-       { 0x22, 0x7A7, 0x00 },
-       { 0x22, 0x7A8, 0x00 },
-       { 0x22, 0x7A9, 0x40 },
-       { 0x22, 0x7AA, 0x00 },
-       { 0x22, 0x7AB, 0x00 },
-       { 0x22, 0x7AC, 0x19 },
-       { 0x22, 0x7AD, 0x80 },
-       /* 48KHz base */
-       { 0x22, 0x7A6, 0x3E },
-       { 0x22, 0x7A7, 0x88 },
-       { 0x22, 0x7A8, 0xDC },
-       { 0x22, 0x7A9, 0x3E },
-       { 0x22, 0x7AA, 0x88 },
-       { 0x22, 0x7AB, 0xDC },
-       { 0x22, 0x7AC, 0x1A },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x82 },
-       { 0x22, 0x7A7, 0xEE },
-       { 0x22, 0x7A8, 0x46 },
-       { 0x22, 0x7A9, 0x82 },
-       { 0x22, 0x7AA, 0xEE },
-       { 0x22, 0x7AB, 0x46 },
-       { 0x22, 0x7AC, 0x1B },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3E },
-       { 0x22, 0x7A7, 0x88 },
-       { 0x22, 0x7A8, 0xDC },
-       { 0x22, 0x7A9, 0x3E },
-       { 0x22, 0x7AA, 0x88 },
-       { 0x22, 0x7AB, 0xDC },
-       { 0x22, 0x7AC, 0x1C },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x7D },
-       { 0x22, 0x7A7, 0x09 },
-       { 0x22, 0x7A8, 0x28 },
-       { 0x22, 0x7A9, 0x7D },
-       { 0x22, 0x7AA, 0x09 },
-       { 0x22, 0x7AB, 0x28 },
-       { 0x22, 0x7AC, 0x1D },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xC2 },
-       { 0x22, 0x7A7, 0xE5 },
-       { 0x22, 0x7A8, 0xB4 },
-       { 0x22, 0x7A9, 0xC2 },
-       { 0x22, 0x7AA, 0xE5 },
-       { 0x22, 0x7AB, 0xB4 },
-       { 0x22, 0x7AC, 0x1E },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3E },
-       { 0x22, 0x7A7, 0xA3 },
-       { 0x22, 0x7A8, 0x1F },
-       { 0x22, 0x7A9, 0x3E },
-       { 0x22, 0x7AA, 0xA3 },
-       { 0x22, 0x7AB, 0x1F },
-       { 0x22, 0x7AC, 0x1F },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x84 },
-       { 0x22, 0x7A7, 0xCA },
-       { 0x22, 0x7A8, 0xF1 },
-       { 0x22, 0x7A9, 0x84 },
-       { 0x22, 0x7AA, 0xCA },
-       { 0x22, 0x7AB, 0xF1 },
-       { 0x22, 0x7AC, 0x20 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3C },
-       { 0x22, 0x7A7, 0xD5 },
-       { 0x22, 0x7A8, 0x9C },
-       { 0x22, 0x7A9, 0x3C },
-       { 0x22, 0x7AA, 0xD5 },
-       { 0x22, 0x7AB, 0x9C },
-       { 0x22, 0x7AC, 0x21 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x7B },
-       { 0x22, 0x7A7, 0x35 },
-       { 0x22, 0x7A8, 0x0F },
-       { 0x22, 0x7A9, 0x7B },
-       { 0x22, 0x7AA, 0x35 },
-       { 0x22, 0x7AB, 0x0F },
-       { 0x22, 0x7AC, 0x22 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xC4 },
-       { 0x22, 0x7A7, 0x87 },
-       { 0x22, 0x7A8, 0x45 },
-       { 0x22, 0x7A9, 0xC4 },
-       { 0x22, 0x7AA, 0x87 },
-       { 0x22, 0x7AB, 0x45 },
-       { 0x22, 0x7AC, 0x23 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3E },
-       { 0x22, 0x7A7, 0x0A },
-       { 0x22, 0x7A8, 0x78 },
-       { 0x22, 0x7A9, 0x3E },
-       { 0x22, 0x7AA, 0x0A },
-       { 0x22, 0x7AB, 0x78 },
-       { 0x22, 0x7AC, 0x24 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x88 },
-       { 0x22, 0x7A7, 0xE2 },
-       { 0x22, 0x7A8, 0x05 },
-       { 0x22, 0x7A9, 0x88 },
-       { 0x22, 0x7AA, 0xE2 },
-       { 0x22, 0x7AB, 0x05 },
-       { 0x22, 0x7AC, 0x25 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x3A },
-       { 0x22, 0x7A7, 0x1A },
-       { 0x22, 0x7A8, 0xA3 },
-       { 0x22, 0x7A9, 0x3A },
-       { 0x22, 0x7AA, 0x1A },
-       { 0x22, 0x7AB, 0xA3 },
-       { 0x22, 0x7AC, 0x26 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x77 },
-       { 0x22, 0x7A7, 0x1D },
-       { 0x22, 0x7A8, 0xFB },
-       { 0x22, 0x7A9, 0x77 },
-       { 0x22, 0x7AA, 0x1D },
-       { 0x22, 0x7AB, 0xFB },
-       { 0x22, 0x7AC, 0x27 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xC7 },
-       { 0x22, 0x7A7, 0xDA },
-       { 0x22, 0x7A8, 0xE5 },
-       { 0x22, 0x7A9, 0xC7 },
-       { 0x22, 0x7AA, 0xDA },
-       { 0x22, 0x7AB, 0xE5 },
-       { 0x22, 0x7AC, 0x28 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x40 },
-       { 0x22, 0x7A7, 0x00 },
-       { 0x22, 0x7A8, 0x00 },
-       { 0x22, 0x7A9, 0x40 },
-       { 0x22, 0x7AA, 0x00 },
-       { 0x22, 0x7AB, 0x00 },
-       { 0x22, 0x7AC, 0x29 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x8E },
-       { 0x22, 0x7A7, 0xD7 },
-       { 0x22, 0x7A8, 0x22 },
-       { 0x22, 0x7A9, 0x8E },
-       { 0x22, 0x7AA, 0xD7 },
-       { 0x22, 0x7AB, 0x22 },
-       { 0x22, 0x7AC, 0x2A },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x35 },
-       { 0x22, 0x7A7, 0x26 },
-       { 0x22, 0x7A8, 0xC6 },
-       { 0x22, 0x7A9, 0x35 },
-       { 0x22, 0x7AA, 0x26 },
-       { 0x22, 0x7AB, 0xC6 },
-       { 0x22, 0x7AC, 0x2B },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x71 },
-       { 0x22, 0x7A7, 0x28 },
-       { 0x22, 0x7A8, 0xDE },
-       { 0x22, 0x7A9, 0x71 },
-       { 0x22, 0x7AA, 0x28 },
-       { 0x22, 0x7AB, 0xDE },
-       { 0x22, 0x7AC, 0x2C },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xCA },
-       { 0x22, 0x7A7, 0xD9 },
-       { 0x22, 0x7A8, 0x3A },
-       { 0x22, 0x7A9, 0xCA },
-       { 0x22, 0x7AA, 0xD9 },
-       { 0x22, 0x7AB, 0x3A },
-       { 0x22, 0x7AC, 0x2D },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x40 },
-       { 0x22, 0x7A7, 0x00 },
-       { 0x22, 0x7A8, 0x00 },
-       { 0x22, 0x7A9, 0x40 },
-       { 0x22, 0x7AA, 0x00 },
-       { 0x22, 0x7AB, 0x00 },
-       { 0x22, 0x7AC, 0x2E },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x93 },
-       { 0x22, 0x7A7, 0x5E },
-       { 0x22, 0x7A8, 0xD8 },
-       { 0x22, 0x7A9, 0x93 },
-       { 0x22, 0x7AA, 0x5E },
-       { 0x22, 0x7AB, 0xD8 },
-       { 0x22, 0x7AC, 0x2F },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x32 },
-       { 0x22, 0x7A7, 0xB7 },
-       { 0x22, 0x7A8, 0xB1 },
-       { 0x22, 0x7A9, 0x32 },
-       { 0x22, 0x7AA, 0xB7 },
-       { 0x22, 0x7AB, 0xB1 },
-       { 0x22, 0x7AC, 0x30 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x6C },
-       { 0x22, 0x7A7, 0xA1 },
-       { 0x22, 0x7A8, 0x28 },
-       { 0x22, 0x7A9, 0x6C },
-       { 0x22, 0x7AA, 0xA1 },
-       { 0x22, 0x7AB, 0x28 },
-       { 0x22, 0x7AC, 0x31 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0xCD },
-       { 0x22, 0x7A7, 0x48 },
-       { 0x22, 0x7A8, 0x4F },
-       { 0x22, 0x7A9, 0xCD },
-       { 0x22, 0x7AA, 0x48 },
-       { 0x22, 0x7AB, 0x4F },
-       { 0x22, 0x7AC, 0x32 },
-       { 0x22, 0x7AD, 0x80 },
-       { 0x22, 0x7A6, 0x40 },
-       { 0x22, 0x7A7, 0x00 },
-       { 0x22, 0x7A8, 0x00 },
-       { 0x22, 0x7A9, 0x40 },
-       { 0x22, 0x7AA, 0x00 },
-       { 0x22, 0x7AB, 0x00 },
-       { 0x22, 0x7AC, 0x33 },
-       { 0x22, 0x7AD, 0x80 },
-       /* common */
-       { 0x22, 0x782, 0xC1 },
-       { 0x22, 0x771, 0x2C },
-       { 0x22, 0x772, 0x2C },
-       { 0x22, 0x788, 0x04 },
-       { 0x01, 0x7B0, 0x08 },
-       {}
-};
-
-static const struct hda_fixup stac92hd83xxx_fixups[] = {
-       [STAC_92HD83XXX_REF] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = ref92hd83xxx_pin_configs,
-       },
-       [STAC_92HD83XXX_PWR_REF] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = ref92hd83xxx_pin_configs,
-       },
-       [STAC_DELL_S14] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_s14_pin_configs,
-       },
-       [STAC_DELL_VOSTRO_3500] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_vostro_3500_pin_configs,
-       },
-       [STAC_92HD83XXX_HP_cNB11_INTQUAD] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = hp_cNB11_intquad_pin_configs,
-               .chained = true,
-               .chain_id = STAC_92HD83XXX_HP,
-       },
-       [STAC_92HD83XXX_HP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd83xxx_fixup_hp,
-       },
-       [STAC_HP_DV7_4000] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = hp_dv7_4000_pin_configs,
-               .chained = true,
-               .chain_id = STAC_92HD83XXX_HP,
-       },
-       [STAC_HP_ZEPHYR] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd83xxx_fixup_hp_zephyr,
-               .chained = true,
-               .chain_id = STAC_92HD83XXX_HP,
-       },
-       [STAC_92HD83XXX_HP_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd83xxx_fixup_hp_led,
-               .chained = true,
-               .chain_id = STAC_92HD83XXX_HP,
-       },
-       [STAC_92HD83XXX_HP_INV_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd83xxx_fixup_hp_inv_led,
-               .chained = true,
-               .chain_id = STAC_92HD83XXX_HP,
-       },
-       [STAC_92HD83XXX_HP_MIC_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd83xxx_fixup_hp_mic_led,
-               .chained = true,
-               .chain_id = STAC_92HD83XXX_HP,
-       },
-       [STAC_HP_LED_GPIO10] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd83xxx_fixup_hp_led_gpio10,
-               .chained = true,
-               .chain_id = STAC_92HD83XXX_HP,
-       },
-       [STAC_92HD83XXX_HEADSET_JACK] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd83xxx_fixup_headset_jack,
-       },
-       [STAC_HP_ENVY_BASS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x0f, 0x90170111 },
-                       {}
-               },
-       },
-       [STAC_HP_BNB13_EQ] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = hp_bnb13_eq_verbs,
-               .chained = true,
-               .chain_id = STAC_92HD83XXX_HP_MIC_LED,
-       },
-       [STAC_HP_ENVY_TS_BASS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       { 0x10, 0x92170111 },
-                       {}
-               },
-       },
-       [STAC_HP_ENVY_TS_DAC_BIND] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = hp_envy_ts_fixup_dac_bind,
-               .chained = true,
-               .chain_id = STAC_HP_ENVY_TS_BASS,
-       },
-       [STAC_92HD83XXX_GPIO10_EAPD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd83xxx_fixup_gpio10_eapd,
-       },
-};
-
-static const struct hda_model_fixup stac92hd83xxx_models[] = {
-       { .id = STAC_92HD83XXX_REF, .name = "ref" },
-       { .id = STAC_92HD83XXX_PWR_REF, .name = "mic-ref" },
-       { .id = STAC_DELL_S14, .name = "dell-s14" },
-       { .id = STAC_DELL_VOSTRO_3500, .name = "dell-vostro-3500" },
-       { .id = STAC_92HD83XXX_HP_cNB11_INTQUAD, .name = "hp_cNB11_intquad" },
-       { .id = STAC_HP_DV7_4000, .name = "hp-dv7-4000" },
-       { .id = STAC_HP_ZEPHYR, .name = "hp-zephyr" },
-       { .id = STAC_92HD83XXX_HP_LED, .name = "hp-led" },
-       { .id = STAC_92HD83XXX_HP_INV_LED, .name = "hp-inv-led" },
-       { .id = STAC_92HD83XXX_HP_MIC_LED, .name = "hp-mic-led" },
-       { .id = STAC_92HD83XXX_HEADSET_JACK, .name = "headset-jack" },
-       { .id = STAC_HP_ENVY_BASS, .name = "hp-envy-bass" },
-       { .id = STAC_HP_BNB13_EQ, .name = "hp-bnb13-eq" },
-       { .id = STAC_HP_ENVY_TS_BASS, .name = "hp-envy-ts-bass" },
-       {}
-};
-
-static const struct hda_quirk stac92hd83xxx_fixup_tbl[] = {
-       /* SigmaTel reference board */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
-                     "DFI LanParty", STAC_92HD83XXX_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
-                     "DFI LanParty", STAC_92HD83XXX_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba,
-                     "unknown Dell", STAC_DELL_S14),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0532,
-                     "Dell Latitude E6230", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0533,
-                     "Dell Latitude E6330", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0534,
-                     "Dell Latitude E6430", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0535,
-                     "Dell Latitude E6530", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053c,
-                     "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x053d,
-                     "Dell Latitude E5530", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0549,
-                     "Dell Latitude E5430", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x057d,
-                     "Dell Latitude E6430s", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0584,
-                     "Dell Latitude E6430U", STAC_92HD83XXX_HEADSET_JACK),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x1028,
-                     "Dell Vostro 3500", STAC_DELL_VOSTRO_3500),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659,
-                         "HP Pavilion dv7", STAC_HP_DV7_4000),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888,
-                         "HP Envy Spectre", STAC_HP_ENVY_BASS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899,
-                         "HP Folio 13", STAC_HP_LED_GPIO10),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df,
-                         "HP Folio", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1909,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190A,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190e,
-                         "HP ENVY TS", STAC_HP_ENVY_TS_BASS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1967,
-                         "HP ENVY TS", STAC_HP_ENVY_TS_DAC_BIND),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1940,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1941,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1942,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1943,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1944,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1945,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1946,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1948,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1949,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194A,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194B,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194C,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194E,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194F,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1950,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1951,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195A,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195B,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195C,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1991,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2103,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2104,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2105,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2106,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2107,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2108,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2109,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x210A,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x210B,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211C,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211D,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211E,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211F,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2120,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2121,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2122,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2123,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x213E,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x213F,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2140,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B2,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B3,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B5,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B6,
-                         "HP bNB13", STAC_HP_BNB13_EQ),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900,
-                         "HP", STAC_92HD83XXX_HP_MIC_LED),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2000,
-                         "HP", STAC_92HD83XXX_HP_MIC_LED),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2100,
-                         "HP", STAC_92HD83XXX_HP_MIC_LED),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593,
-                         "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561,
-                         "HP", STAC_HP_ZEPHYR),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660,
-                         "HP Mini", STAC_92HD83XXX_HP_LED),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E,
-                         "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a,
-                     "HP Mini", STAC_92HD83XXX_HP_LED),
-       SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP),
-       /* match both for 0xfa91 and 0xfa93 */
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_TOSHIBA, 0xfffd, 0xfa91,
-                     "Toshiba Satellite S50D", STAC_92HD83XXX_GPIO10_EAPD),
-       {} /* terminator */
-};
-
-/* HP dv7 bass switch - GPIO5 */
-#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info
-static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-       ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20);
-       return 0;
-}
-
-static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct sigmatel_spec *spec = codec->spec;
-       unsigned int gpio_data;
-
-       gpio_data = (spec->gpio_data & ~0x20) |
-               (ucontrol->value.integer.value[0] ? 0x20 : 0);
-       if (gpio_data == spec->gpio_data)
-               return 0;
-       spec->gpio_data = gpio_data;
-       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
-       return 1;
-}
-
-static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .info = stac_hp_bass_gpio_info,
-       .get = stac_hp_bass_gpio_get,
-       .put = stac_hp_bass_gpio_put,
-};
-
-static int stac_add_hp_bass_switch(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (!snd_hda_gen_add_kctl(&spec->gen, "Bass Speaker Playback Switch",
-                                 &stac_hp_bass_sw_ctrl))
-               return -ENOMEM;
-
-       spec->gpio_mask |= 0x20;
-       spec->gpio_dir |= 0x20;
-       spec->gpio_data |= 0x20;
-       return 0;
-}
-
-static const struct hda_pintbl ref92hd71bxx_pin_configs[] = {
-       { 0x0a, 0x02214030 },
-       { 0x0b, 0x02a19040 },
-       { 0x0c, 0x01a19020 },
-       { 0x0d, 0x01014010 },
-       { 0x0e, 0x0181302e },
-       { 0x0f, 0x01014010 },
-       { 0x14, 0x01019020 },
-       { 0x18, 0x90a000f0 },
-       { 0x19, 0x90a000f0 },
-       { 0x1e, 0x01452050 },
-       { 0x1f, 0x01452050 },
-       {}
-};
-
-static const struct hda_pintbl dell_m4_1_pin_configs[] = {
-       { 0x0a, 0x0421101f },
-       { 0x0b, 0x04a11221 },
-       { 0x0c, 0x40f000f0 },
-       { 0x0d, 0x90170110 },
-       { 0x0e, 0x23a1902e },
-       { 0x0f, 0x23014250 },
-       { 0x14, 0x40f000f0 },
-       { 0x18, 0x90a000f0 },
-       { 0x19, 0x40f000f0 },
-       { 0x1e, 0x4f0000f0 },
-       { 0x1f, 0x4f0000f0 },
-       {}
-};
-
-static const struct hda_pintbl dell_m4_2_pin_configs[] = {
-       { 0x0a, 0x0421101f },
-       { 0x0b, 0x04a11221 },
-       { 0x0c, 0x90a70330 },
-       { 0x0d, 0x90170110 },
-       { 0x0e, 0x23a1902e },
-       { 0x0f, 0x23014250 },
-       { 0x14, 0x40f000f0 },
-       { 0x18, 0x40f000f0 },
-       { 0x19, 0x40f000f0 },
-       { 0x1e, 0x044413b0 },
-       { 0x1f, 0x044413b0 },
-       {}
-};
-
-static const struct hda_pintbl dell_m4_3_pin_configs[] = {
-       { 0x0a, 0x0421101f },
-       { 0x0b, 0x04a11221 },
-       { 0x0c, 0x90a70330 },
-       { 0x0d, 0x90170110 },
-       { 0x0e, 0x40f000f0 },
-       { 0x0f, 0x40f000f0 },
-       { 0x14, 0x40f000f0 },
-       { 0x18, 0x90a000f0 },
-       { 0x19, 0x40f000f0 },
-       { 0x1e, 0x044413b0 },
-       { 0x1f, 0x044413b0 },
-       {}
-};
-
-static void stac92hd71bxx_fixup_ref(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       snd_hda_apply_pincfgs(codec, ref92hd71bxx_pin_configs);
-       spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0;
-}
-
-static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec,
-                                     const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       struct hda_jack_callback *jack;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       /* Enable VREF power saving on GPIO1 detect */
-       snd_hda_codec_write_cache(codec, codec->core.afg, 0,
-                                 AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02);
-       jack = snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
-                                                  stac_vref_event);
-       if (!IS_ERR(jack))
-               jack->private_data = 0x02;
-
-       spec->gpio_mask |= 0x02;
-
-       /* enable internal microphone */
-       snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040);
-}
-
-static void stac92hd71bxx_fixup_hp_dv4(struct hda_codec *codec,
-                                      const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-       spec->gpio_led = 0x01;
-}
-
-static void stac92hd71bxx_fixup_hp_dv5(struct hda_codec *codec,
-                                      const struct hda_fixup *fix, int action)
-{
-       unsigned int cap;
-
-       switch (action) {
-       case HDA_FIXUP_ACT_PRE_PROBE:
-               snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010);
-               break;
-
-       case HDA_FIXUP_ACT_PROBE:
-               /* enable bass on HP dv7 */
-               cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP);
-               cap &= AC_GPIO_IO_COUNT;
-               if (cap >= 6)
-                       stac_add_hp_bass_switch(codec);
-               break;
-       }
-}
-
-static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec,
-                                      const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-       spec->gpio_led = 0x08;
-}
-
-static bool is_hp_output(struct hda_codec *codec, hda_nid_t pin)
-{
-       unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin);
-
-       /* count line-out, too, as BIOS sets often so */
-       return get_defcfg_connect(pin_cfg) != AC_JACK_PORT_NONE &&
-               (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT ||
-                get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT);
-}
-
-static void fixup_hp_headphone(struct hda_codec *codec, hda_nid_t pin)
-{
-       unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, pin);
-
-       /* It was changed in the BIOS to just satisfy MS DTM.
-        * Lets turn it back into follower HP
-        */
-       pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) |
-               (AC_JACK_HP_OUT << AC_DEFCFG_DEVICE_SHIFT);
-       pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC | AC_DEFCFG_SEQUENCE))) |
-               0x1f;
-       snd_hda_codec_set_pincfg(codec, pin, pin_cfg);
-}
-
-static void stac92hd71bxx_fixup_hp(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       /* when both output A and F are assigned, these are supposedly
-        * dock and built-in headphones; fix both pin configs
-        */
-       if (is_hp_output(codec, 0x0a) && is_hp_output(codec, 0x0f)) {
-               fixup_hp_headphone(codec, 0x0a);
-               fixup_hp_headphone(codec, 0x0f);
-       }
-
-       if (find_mute_led_cfg(codec, 1))
-               codec_dbg(codec, "mute LED gpio %d polarity %d\n",
-                               spec->gpio_led,
-                               spec->gpio_led_polarity);
-
-}
-
-static const struct hda_fixup stac92hd71bxx_fixups[] = {
-       [STAC_92HD71BXX_REF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd71bxx_fixup_ref,
-       },
-       [STAC_DELL_M4_1] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_m4_1_pin_configs,
-       },
-       [STAC_DELL_M4_2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_m4_2_pin_configs,
-       },
-       [STAC_DELL_M4_3] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_m4_3_pin_configs,
-       },
-       [STAC_HP_M4] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd71bxx_fixup_hp_m4,
-               .chained = true,
-               .chain_id = STAC_92HD71BXX_HP,
-       },
-       [STAC_HP_DV4] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd71bxx_fixup_hp_dv4,
-               .chained = true,
-               .chain_id = STAC_HP_DV5,
-       },
-       [STAC_HP_DV5] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd71bxx_fixup_hp_dv5,
-               .chained = true,
-               .chain_id = STAC_92HD71BXX_HP,
-       },
-       [STAC_HP_HDX] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd71bxx_fixup_hp_hdx,
-               .chained = true,
-               .chain_id = STAC_92HD71BXX_HP,
-       },
-       [STAC_92HD71BXX_HP] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd71bxx_fixup_hp,
-       },
-};
-
-static const struct hda_model_fixup stac92hd71bxx_models[] = {
-       { .id = STAC_92HD71BXX_REF, .name = "ref" },
-       { .id = STAC_DELL_M4_1, .name = "dell-m4-1" },
-       { .id = STAC_DELL_M4_2, .name = "dell-m4-2" },
-       { .id = STAC_DELL_M4_3, .name = "dell-m4-3" },
-       { .id = STAC_HP_M4, .name = "hp-m4" },
-       { .id = STAC_HP_DV4, .name = "hp-dv4" },
-       { .id = STAC_HP_DV5, .name = "hp-dv5" },
-       { .id = STAC_HP_HDX, .name = "hp-hdx" },
-       { .id = STAC_HP_DV4, .name = "hp-dv4-1222nr" },
-       {}
-};
-
-static const struct hda_quirk stac92hd71bxx_fixup_tbl[] = {
-       /* SigmaTel reference board */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
-                     "DFI LanParty", STAC_92HD71BXX_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
-                     "DFI LanParty", STAC_92HD71BXX_REF),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x1720,
-                         "HP", STAC_HP_DV5),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080,
-                     "HP", STAC_HP_DV5),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0,
-                     "HP dv4-7", STAC_HP_DV4),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3600,
-                     "HP dv4-7", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3610,
-                     "HP HDX", STAC_HP_HDX),  /* HDX18 */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361a,
-                     "HP mini 1000", STAC_HP_M4),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x361b,
-                     "HP HDX", STAC_HP_HDX),  /* HDX16 */
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3620,
-                     "HP dv6", STAC_HP_DV5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061,
-                     "HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x363e,
-                     "HP DV6", STAC_HP_DV5),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010,
-                     "HP", STAC_HP_DV5),
-       SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD71BXX_HP),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233,
-                               "unknown Dell", STAC_DELL_M4_1),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234,
-                               "unknown Dell", STAC_DELL_M4_1),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0250,
-                               "unknown Dell", STAC_DELL_M4_1),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024f,
-                               "unknown Dell", STAC_DELL_M4_1),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x024d,
-                               "unknown Dell", STAC_DELL_M4_1),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0251,
-                               "unknown Dell", STAC_DELL_M4_1),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0277,
-                               "unknown Dell", STAC_DELL_M4_1),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0263,
-                               "unknown Dell", STAC_DELL_M4_2),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0265,
-                               "unknown Dell", STAC_DELL_M4_2),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0262,
-                               "unknown Dell", STAC_DELL_M4_2),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0264,
-                               "unknown Dell", STAC_DELL_M4_2),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02aa,
-                               "unknown Dell", STAC_DELL_M4_3),
-       {} /* terminator */
-};
-
-static const struct hda_pintbl ref922x_pin_configs[] = {
-       { 0x0a, 0x01014010 },
-       { 0x0b, 0x01016011 },
-       { 0x0c, 0x01012012 },
-       { 0x0d, 0x0221401f },
-       { 0x0e, 0x01813122 },
-       { 0x0f, 0x01011014 },
-       { 0x10, 0x01441030 },
-       { 0x11, 0x01c41030 },
-       { 0x15, 0x40000100 },
-       { 0x1b, 0x40000100 },
-       {}
-};
-
-/*
-    STAC 922X pin configs for
-    102801A7
-    102801AB
-    102801A9
-    102801D1
-    102801D2
-*/
-static const struct hda_pintbl dell_922x_d81_pin_configs[] = {
-       { 0x0a, 0x02214030 },
-       { 0x0b, 0x01a19021 },
-       { 0x0c, 0x01111012 },
-       { 0x0d, 0x01114010 },
-       { 0x0e, 0x02a19020 },
-       { 0x0f, 0x01117011 },
-       { 0x10, 0x400001f0 },
-       { 0x11, 0x400001f1 },
-       { 0x15, 0x01813122 },
-       { 0x1b, 0x400001f2 },
-       {}
-};
-
-/*
-    STAC 922X pin configs for
-    102801AC
-    102801D0
-*/
-static const struct hda_pintbl dell_922x_d82_pin_configs[] = {
-       { 0x0a, 0x02214030 },
-       { 0x0b, 0x01a19021 },
-       { 0x0c, 0x01111012 },
-       { 0x0d, 0x01114010 },
-       { 0x0e, 0x02a19020 },
-       { 0x0f, 0x01117011 },
-       { 0x10, 0x01451140 },
-       { 0x11, 0x400001f0 },
-       { 0x15, 0x01813122 },
-       { 0x1b, 0x400001f1 },
-       {}
-};
-
-/*
-    STAC 922X pin configs for
-    102801BF
-*/
-static const struct hda_pintbl dell_922x_m81_pin_configs[] = {
-       { 0x0a, 0x0321101f },
-       { 0x0b, 0x01112024 },
-       { 0x0c, 0x01111222 },
-       { 0x0d, 0x91174220 },
-       { 0x0e, 0x03a11050 },
-       { 0x0f, 0x01116221 },
-       { 0x10, 0x90a70330 },
-       { 0x11, 0x01452340 },
-       { 0x15, 0x40C003f1 },
-       { 0x1b, 0x405003f0 },
-       {}
-};
-
-/*
-    STAC 9221 A1 pin configs for
-    102801D7 (Dell XPS M1210)
-*/
-static const struct hda_pintbl dell_922x_m82_pin_configs[] = {
-       { 0x0a, 0x02211211 },
-       { 0x0b, 0x408103ff },
-       { 0x0c, 0x02a1123e },
-       { 0x0d, 0x90100310 },
-       { 0x0e, 0x408003f1 },
-       { 0x0f, 0x0221121f },
-       { 0x10, 0x03451340 },
-       { 0x11, 0x40c003f2 },
-       { 0x15, 0x508003f3 },
-       { 0x1b, 0x405003f4 },
-       {}
-};
-
-static const struct hda_pintbl d945gtp3_pin_configs[] = {
-       { 0x0a, 0x0221401f },
-       { 0x0b, 0x01a19022 },
-       { 0x0c, 0x01813021 },
-       { 0x0d, 0x01014010 },
-       { 0x0e, 0x40000100 },
-       { 0x0f, 0x40000100 },
-       { 0x10, 0x40000100 },
-       { 0x11, 0x40000100 },
-       { 0x15, 0x02a19120 },
-       { 0x1b, 0x40000100 },
-       {}
-};
-
-static const struct hda_pintbl d945gtp5_pin_configs[] = {
-       { 0x0a, 0x0221401f },
-       { 0x0b, 0x01011012 },
-       { 0x0c, 0x01813024 },
-       { 0x0d, 0x01014010 },
-       { 0x0e, 0x01a19021 },
-       { 0x0f, 0x01016011 },
-       { 0x10, 0x01452130 },
-       { 0x11, 0x40000100 },
-       { 0x15, 0x02a19320 },
-       { 0x1b, 0x40000100 },
-       {}
-};
-
-static const struct hda_pintbl intel_mac_v1_pin_configs[] = {
-       { 0x0a, 0x0121e21f },
-       { 0x0b, 0x400000ff },
-       { 0x0c, 0x9017e110 },
-       { 0x0d, 0x400000fd },
-       { 0x0e, 0x400000fe },
-       { 0x0f, 0x0181e020 },
-       { 0x10, 0x1145e030 },
-       { 0x11, 0x11c5e240 },
-       { 0x15, 0x400000fc },
-       { 0x1b, 0x400000fb },
-       {}
-};
-
-static const struct hda_pintbl intel_mac_v2_pin_configs[] = {
-       { 0x0a, 0x0121e21f },
-       { 0x0b, 0x90a7012e },
-       { 0x0c, 0x9017e110 },
-       { 0x0d, 0x400000fd },
-       { 0x0e, 0x400000fe },
-       { 0x0f, 0x0181e020 },
-       { 0x10, 0x1145e230 },
-       { 0x11, 0x500000fa },
-       { 0x15, 0x400000fc },
-       { 0x1b, 0x400000fb },
-       {}
-};
-
-static const struct hda_pintbl intel_mac_v3_pin_configs[] = {
-       { 0x0a, 0x0121e21f },
-       { 0x0b, 0x90a7012e },
-       { 0x0c, 0x9017e110 },
-       { 0x0d, 0x400000fd },
-       { 0x0e, 0x400000fe },
-       { 0x0f, 0x0181e020 },
-       { 0x10, 0x1145e230 },
-       { 0x11, 0x11c5e240 },
-       { 0x15, 0x400000fc },
-       { 0x1b, 0x400000fb },
-       {}
-};
-
-static const struct hda_pintbl intel_mac_v4_pin_configs[] = {
-       { 0x0a, 0x0321e21f },
-       { 0x0b, 0x03a1e02e },
-       { 0x0c, 0x9017e110 },
-       { 0x0d, 0x9017e11f },
-       { 0x0e, 0x400000fe },
-       { 0x0f, 0x0381e020 },
-       { 0x10, 0x1345e230 },
-       { 0x11, 0x13c5e240 },
-       { 0x15, 0x400000fc },
-       { 0x1b, 0x400000fb },
-       {}
-};
-
-static const struct hda_pintbl intel_mac_v5_pin_configs[] = {
-       { 0x0a, 0x0321e21f },
-       { 0x0b, 0x03a1e02e },
-       { 0x0c, 0x9017e110 },
-       { 0x0d, 0x9017e11f },
-       { 0x0e, 0x400000fe },
-       { 0x0f, 0x0381e020 },
-       { 0x10, 0x1345e230 },
-       { 0x11, 0x13c5e240 },
-       { 0x15, 0x400000fc },
-       { 0x1b, 0x400000fb },
-       {}
-};
-
-static const struct hda_pintbl ecs202_pin_configs[] = {
-       { 0x0a, 0x0221401f },
-       { 0x0b, 0x02a19020 },
-       { 0x0c, 0x01a19020 },
-       { 0x0d, 0x01114010 },
-       { 0x0e, 0x408000f0 },
-       { 0x0f, 0x01813022 },
-       { 0x10, 0x074510a0 },
-       { 0x11, 0x40c400f1 },
-       { 0x15, 0x9037012e },
-       { 0x1b, 0x40e000f2 },
-       {}
-};
-
-/* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */
-static const struct hda_quirk stac922x_intel_mac_fixup_tbl[] = {
-       SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3),
-       SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1),
-       SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2),
-       SND_PCI_QUIRK(0x106b, 0x0700, "Mac", STAC_INTEL_MAC_V2),
-       SND_PCI_QUIRK(0x106b, 0x0e00, "Mac", STAC_INTEL_MAC_V3),
-       SND_PCI_QUIRK(0x106b, 0x0f00, "Mac", STAC_INTEL_MAC_V3),
-       SND_PCI_QUIRK(0x106b, 0x1600, "Mac", STAC_INTEL_MAC_V3),
-       SND_PCI_QUIRK(0x106b, 0x1700, "Mac", STAC_INTEL_MAC_V3),
-       SND_PCI_QUIRK(0x106b, 0x0200, "Mac", STAC_INTEL_MAC_V3),
-       SND_PCI_QUIRK(0x106b, 0x1e00, "Mac", STAC_INTEL_MAC_V3),
-       SND_PCI_QUIRK(0x106b, 0x1a00, "Mac", STAC_INTEL_MAC_V4),
-       SND_PCI_QUIRK(0x106b, 0x0a00, "Mac", STAC_INTEL_MAC_V5),
-       SND_PCI_QUIRK(0x106b, 0x2200, "Mac", STAC_INTEL_MAC_V5),
-       {}
-};
-
-static const struct hda_fixup stac922x_fixups[];
-
-/* remap the fixup from codec SSID and apply it */
-static void stac922x_fixup_intel_mac_auto(struct hda_codec *codec,
-                                         const struct hda_fixup *fix,
-                                         int action)
-{
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       codec->fixup_id = HDA_FIXUP_ID_NOT_SET;
-       snd_hda_pick_fixup(codec, NULL, stac922x_intel_mac_fixup_tbl,
-                          stac922x_fixups);
-       if (codec->fixup_id != HDA_FIXUP_ID_NOT_SET)
-               snd_hda_apply_fixup(codec, action);
-}
-
-static void stac922x_fixup_intel_mac_gpio(struct hda_codec *codec,
-                                         const struct hda_fixup *fix,
-                                         int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               spec->gpio_mask = spec->gpio_dir = 0x03;
-               spec->gpio_data = 0x03;
-       }
-}
-
-static const struct hda_fixup stac922x_fixups[] = {
-       [STAC_D945_REF] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = ref922x_pin_configs,
-       },
-       [STAC_D945GTP3] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = d945gtp3_pin_configs,
-       },
-       [STAC_D945GTP5] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = d945gtp5_pin_configs,
-       },
-       [STAC_INTEL_MAC_AUTO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac922x_fixup_intel_mac_auto,
-       },
-       [STAC_INTEL_MAC_V1] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = intel_mac_v1_pin_configs,
-               .chained = true,
-               .chain_id = STAC_922X_INTEL_MAC_GPIO,
-       },
-       [STAC_INTEL_MAC_V2] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = intel_mac_v2_pin_configs,
-               .chained = true,
-               .chain_id = STAC_922X_INTEL_MAC_GPIO,
-       },
-       [STAC_INTEL_MAC_V3] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = intel_mac_v3_pin_configs,
-               .chained = true,
-               .chain_id = STAC_922X_INTEL_MAC_GPIO,
-       },
-       [STAC_INTEL_MAC_V4] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = intel_mac_v4_pin_configs,
-               .chained = true,
-               .chain_id = STAC_922X_INTEL_MAC_GPIO,
-       },
-       [STAC_INTEL_MAC_V5] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = intel_mac_v5_pin_configs,
-               .chained = true,
-               .chain_id = STAC_922X_INTEL_MAC_GPIO,
-       },
-       [STAC_922X_INTEL_MAC_GPIO] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac922x_fixup_intel_mac_gpio,
-       },
-       [STAC_ECS_202] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = ecs202_pin_configs,
-       },
-       [STAC_922X_DELL_D81] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_922x_d81_pin_configs,
-       },
-       [STAC_922X_DELL_D82] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_922x_d82_pin_configs,
-       },
-       [STAC_922X_DELL_M81] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_922x_m81_pin_configs,
-       },
-       [STAC_922X_DELL_M82] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_922x_m82_pin_configs,
-       },
-};
-
-static const struct hda_model_fixup stac922x_models[] = {
-       { .id = STAC_D945_REF, .name = "ref" },
-       { .id = STAC_D945GTP5, .name = "5stack" },
-       { .id = STAC_D945GTP3, .name = "3stack" },
-       { .id = STAC_INTEL_MAC_V1, .name = "intel-mac-v1" },
-       { .id = STAC_INTEL_MAC_V2, .name = "intel-mac-v2" },
-       { .id = STAC_INTEL_MAC_V3, .name = "intel-mac-v3" },
-       { .id = STAC_INTEL_MAC_V4, .name = "intel-mac-v4" },
-       { .id = STAC_INTEL_MAC_V5, .name = "intel-mac-v5" },
-       { .id = STAC_INTEL_MAC_AUTO, .name = "intel-mac-auto" },
-       { .id = STAC_ECS_202, .name = "ecs202" },
-       { .id = STAC_922X_DELL_D81, .name = "dell-d81" },
-       { .id = STAC_922X_DELL_D82, .name = "dell-d82" },
-       { .id = STAC_922X_DELL_M81, .name = "dell-m81" },
-       { .id = STAC_922X_DELL_M82, .name = "dell-m82" },
-       /* for backward compatibility */
-       { .id = STAC_INTEL_MAC_V3, .name = "macmini" },
-       { .id = STAC_INTEL_MAC_V5, .name = "macbook" },
-       { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro-v1" },
-       { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro" },
-       { .id = STAC_INTEL_MAC_V2, .name = "imac-intel" },
-       { .id = STAC_INTEL_MAC_V3, .name = "imac-intel-20" },
-       {}
-};
-
-static const struct hda_quirk stac922x_fixup_tbl[] = {
-       /* SigmaTel reference board */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
-                     "DFI LanParty", STAC_D945_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
-                     "DFI LanParty", STAC_D945_REF),
-       /* Intel 945G based systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0101,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0202,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0606,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0601,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0111,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1115,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1116,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1117,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1118,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x1119,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x8826,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5049,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5055,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x5048,
-                     "Intel D945G", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0110,
-                     "Intel D945G", STAC_D945GTP3),
-       /* Intel D945G 5-stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0404,
-                     "Intel D945G", STAC_D945GTP5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0303,
-                     "Intel D945G", STAC_D945GTP5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0013,
-                     "Intel D945G", STAC_D945GTP5),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0417,
-                     "Intel D945G", STAC_D945GTP5),
-       /* Intel 945P based systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0b0b,
-                     "Intel D945P", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0112,
-                     "Intel D945P", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0d0d,
-                     "Intel D945P", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0909,
-                     "Intel D945P", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0505,
-                     "Intel D945P", STAC_D945GTP3),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0707,
-                     "Intel D945P", STAC_D945GTP5),
-       /* other intel */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204,
-                     "Intel D945", STAC_D945_REF),
-       /* other systems  */
-
-       /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */
-       SND_PCI_QUIRK(0x8384, 0x7680, "Mac", STAC_INTEL_MAC_AUTO),
-
-       /* Dell systems  */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7,
-                     "unknown Dell", STAC_922X_DELL_D81),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a9,
-                     "unknown Dell", STAC_922X_DELL_D81),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ab,
-                     "unknown Dell", STAC_922X_DELL_D81),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ac,
-                     "unknown Dell", STAC_922X_DELL_D82),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01bf,
-                     "unknown Dell", STAC_922X_DELL_M81),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d0,
-                     "unknown Dell", STAC_922X_DELL_D82),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d1,
-                     "unknown Dell", STAC_922X_DELL_D81),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d2,
-                     "unknown Dell", STAC_922X_DELL_D81),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01d7,
-                     "Dell XPS M1210", STAC_922X_DELL_M82),
-       /* ECS/PC Chips boards */
-       SND_PCI_QUIRK_MASK(0x1019, 0xf000, 0x2000,
-                     "ECS/PC chips", STAC_ECS_202),
-       {} /* terminator */
-};
-
-static const struct hda_pintbl ref927x_pin_configs[] = {
-       { 0x0a, 0x02214020 },
-       { 0x0b, 0x02a19080 },
-       { 0x0c, 0x0181304e },
-       { 0x0d, 0x01014010 },
-       { 0x0e, 0x01a19040 },
-       { 0x0f, 0x01011012 },
-       { 0x10, 0x01016011 },
-       { 0x11, 0x0101201f },
-       { 0x12, 0x183301f0 },
-       { 0x13, 0x18a001f0 },
-       { 0x14, 0x18a001f0 },
-       { 0x21, 0x01442070 },
-       { 0x22, 0x01c42190 },
-       { 0x23, 0x40000100 },
-       {}
-};
-
-static const struct hda_pintbl d965_3st_pin_configs[] = {
-       { 0x0a, 0x0221401f },
-       { 0x0b, 0x02a19120 },
-       { 0x0c, 0x40000100 },
-       { 0x0d, 0x01014011 },
-       { 0x0e, 0x01a19021 },
-       { 0x0f, 0x01813024 },
-       { 0x10, 0x40000100 },
-       { 0x11, 0x40000100 },
-       { 0x12, 0x40000100 },
-       { 0x13, 0x40000100 },
-       { 0x14, 0x40000100 },
-       { 0x21, 0x40000100 },
-       { 0x22, 0x40000100 },
-       { 0x23, 0x40000100 },
-       {}
-};
-
-static const struct hda_pintbl d965_5st_pin_configs[] = {
-       { 0x0a, 0x02214020 },
-       { 0x0b, 0x02a19080 },
-       { 0x0c, 0x0181304e },
-       { 0x0d, 0x01014010 },
-       { 0x0e, 0x01a19040 },
-       { 0x0f, 0x01011012 },
-       { 0x10, 0x01016011 },
-       { 0x11, 0x40000100 },
-       { 0x12, 0x40000100 },
-       { 0x13, 0x40000100 },
-       { 0x14, 0x40000100 },
-       { 0x21, 0x01442070 },
-       { 0x22, 0x40000100 },
-       { 0x23, 0x40000100 },
-       {}
-};
-
-static const struct hda_pintbl d965_5st_no_fp_pin_configs[] = {
-       { 0x0a, 0x40000100 },
-       { 0x0b, 0x40000100 },
-       { 0x0c, 0x0181304e },
-       { 0x0d, 0x01014010 },
-       { 0x0e, 0x01a19040 },
-       { 0x0f, 0x01011012 },
-       { 0x10, 0x01016011 },
-       { 0x11, 0x40000100 },
-       { 0x12, 0x40000100 },
-       { 0x13, 0x40000100 },
-       { 0x14, 0x40000100 },
-       { 0x21, 0x01442070 },
-       { 0x22, 0x40000100 },
-       { 0x23, 0x40000100 },
-       {}
-};
-
-static const struct hda_pintbl dell_3st_pin_configs[] = {
-       { 0x0a, 0x02211230 },
-       { 0x0b, 0x02a11220 },
-       { 0x0c, 0x01a19040 },
-       { 0x0d, 0x01114210 },
-       { 0x0e, 0x01111212 },
-       { 0x0f, 0x01116211 },
-       { 0x10, 0x01813050 },
-       { 0x11, 0x01112214 },
-       { 0x12, 0x403003fa },
-       { 0x13, 0x90a60040 },
-       { 0x14, 0x90a60040 },
-       { 0x21, 0x404003fb },
-       { 0x22, 0x40c003fc },
-       { 0x23, 0x40000100 },
-       {}
-};
-
-static void stac927x_fixup_ref_no_jd(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       /* no jack detecion for ref-no-jd model */
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               codec->no_jack_detect = 1;
-}
-
-static void stac927x_fixup_ref(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               snd_hda_apply_pincfgs(codec, ref927x_pin_configs);
-               spec->eapd_mask = spec->gpio_mask = 0;
-               spec->gpio_dir = spec->gpio_data = 0;
-       }
-}
-
-static void stac927x_fixup_dell_dmic(struct hda_codec *codec,
-                                    const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       if (codec->core.subsystem_id != 0x1028022f) {
-               /* GPIO2 High = Enable EAPD */
-               spec->eapd_mask = spec->gpio_mask = 0x04;
-               spec->gpio_dir = spec->gpio_data = 0x04;
-       }
-
-       snd_hda_add_verbs(codec, dell_3st_core_init);
-       spec->volknob_init = 1;
-}
-
-static void stac927x_fixup_volknob(struct hda_codec *codec,
-                                  const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               snd_hda_add_verbs(codec, stac927x_volknob_core_init);
-               spec->volknob_init = 1;
-       }
-}
-
-static const struct hda_fixup stac927x_fixups[] = {
-       [STAC_D965_REF_NO_JD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac927x_fixup_ref_no_jd,
-               .chained = true,
-               .chain_id = STAC_D965_REF,
-       },
-       [STAC_D965_REF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac927x_fixup_ref,
-       },
-       [STAC_D965_3ST] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = d965_3st_pin_configs,
-               .chained = true,
-               .chain_id = STAC_D965_VERBS,
-       },
-       [STAC_D965_5ST] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = d965_5st_pin_configs,
-               .chained = true,
-               .chain_id = STAC_D965_VERBS,
-       },
-       [STAC_D965_VERBS] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = d965_core_init,
-       },
-       [STAC_D965_5ST_NO_FP] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = d965_5st_no_fp_pin_configs,
-       },
-       [STAC_NEMO_DEFAULT] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = nemo_pin_configs,
-       },
-       [STAC_DELL_3ST] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_3st_pin_configs,
-               .chained = true,
-               .chain_id = STAC_927X_DELL_DMIC,
-       },
-       [STAC_DELL_BIOS] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* correct the front output jack as a hp out */
-                       { 0x0f, 0x0221101f },
-                       /* correct the front input jack as a mic */
-                       { 0x0e, 0x02a79130 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = STAC_927X_DELL_DMIC,
-       },
-       [STAC_DELL_BIOS_AMIC] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* configure the analog microphone on some laptops */
-                       { 0x0c, 0x90a79130 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = STAC_DELL_BIOS,
-       },
-       [STAC_DELL_BIOS_SPDIF] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* correct the device field to SPDIF out */
-                       { 0x21, 0x01442070 },
-                       {}
-               },
-               .chained = true,
-               .chain_id = STAC_DELL_BIOS,
-       },
-       [STAC_927X_DELL_DMIC] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac927x_fixup_dell_dmic,
-       },
-       [STAC_927X_VOLKNOB] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac927x_fixup_volknob,
-       },
-};
-
-static const struct hda_model_fixup stac927x_models[] = {
-       { .id = STAC_D965_REF_NO_JD, .name = "ref-no-jd" },
-       { .id = STAC_D965_REF, .name = "ref" },
-       { .id = STAC_D965_3ST, .name = "3stack" },
-       { .id = STAC_D965_5ST, .name = "5stack" },
-       { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" },
-       { .id = STAC_DELL_3ST, .name = "dell-3stack" },
-       { .id = STAC_DELL_BIOS, .name = "dell-bios" },
-       { .id = STAC_NEMO_DEFAULT, .name = "nemo-default" },
-       { .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" },
-       { .id = STAC_927X_VOLKNOB, .name = "volknob" },
-       {}
-};
-
-static const struct hda_quirk stac927x_fixup_tbl[] = {
-       /* SigmaTel reference board */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
-                     "DFI LanParty", STAC_D965_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
-                     "DFI LanParty", STAC_D965_REF),
-        /* Intel 946 based systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x3d01, "Intel D946", STAC_D965_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xa301, "Intel D946", STAC_D965_3ST),
-       /* 965 based 3 stack systems */
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2100,
-                          "Intel D965", STAC_D965_3ST),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2000,
-                          "Intel D965", STAC_D965_3ST),
-       /* Dell 3 stack systems */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01dd, "Dell Dimension E520", STAC_DELL_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01ed, "Dell     ", STAC_DELL_3ST),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f4, "Dell     ", STAC_DELL_3ST),
-       /* Dell 3 stack systems with verb table in BIOS */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x01f7, "Dell XPS M1730", STAC_DELL_BIOS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0227, "Dell Vostro 1400  ", STAC_DELL_BIOS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022e, "Dell     ", STAC_DELL_BIOS_SPDIF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0242, "Dell     ", STAC_DELL_BIOS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0243, "Dell     ", STAC_DELL_BIOS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x02ff, "Dell     ", STAC_DELL_BIOS),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL,  0x0209, "Dell XPS 1330", STAC_DELL_BIOS_SPDIF),
-       /* 965 based 5 stack systems */
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300,
-                          "Intel D965", STAC_D965_5ST),
-       SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2500,
-                          "Intel D965", STAC_D965_5ST),
-       /* Nemo */
-       SND_PCI_QUIRK(0x1888, 0x1000, "AmigaOne X1000", STAC_NEMO_DEFAULT),
-       /* volume-knob fixes */
-       SND_PCI_QUIRK_VENDOR(0x10cf, "FSC", STAC_927X_VOLKNOB),
-       {} /* terminator */
-};
-
-static const struct hda_pintbl ref9205_pin_configs[] = {
-       { 0x0a, 0x40000100 },
-       { 0x0b, 0x40000100 },
-       { 0x0c, 0x01016011 },
-       { 0x0d, 0x01014010 },
-       { 0x0e, 0x01813122 },
-       { 0x0f, 0x01a19021 },
-       { 0x14, 0x01019020 },
-       { 0x16, 0x40000100 },
-       { 0x17, 0x90a000f0 },
-       { 0x18, 0x90a000f0 },
-       { 0x21, 0x01441030 },
-       { 0x22, 0x01c41030 },
-       {}
-};
-
-/*
-    STAC 9205 pin configs for
-    102801F1
-    102801F2
-    102801FC
-    102801FD
-    10280204
-    1028021F
-    10280228 (Dell Vostro 1500)
-    10280229 (Dell Vostro 1700)
-*/
-static const struct hda_pintbl dell_9205_m42_pin_configs[] = {
-       { 0x0a, 0x0321101F },
-       { 0x0b, 0x03A11020 },
-       { 0x0c, 0x400003FA },
-       { 0x0d, 0x90170310 },
-       { 0x0e, 0x400003FB },
-       { 0x0f, 0x400003FC },
-       { 0x14, 0x400003FD },
-       { 0x16, 0x40F000F9 },
-       { 0x17, 0x90A60330 },
-       { 0x18, 0x400003FF },
-       { 0x21, 0x0144131F },
-       { 0x22, 0x40C003FE },
-       {}
-};
-
-/*
-    STAC 9205 pin configs for
-    102801F9
-    102801FA
-    102801FE
-    102801FF (Dell Precision M4300)
-    10280206
-    10280200
-    10280201
-*/
-static const struct hda_pintbl dell_9205_m43_pin_configs[] = {
-       { 0x0a, 0x0321101f },
-       { 0x0b, 0x03a11020 },
-       { 0x0c, 0x90a70330 },
-       { 0x0d, 0x90170310 },
-       { 0x0e, 0x400000fe },
-       { 0x0f, 0x400000ff },
-       { 0x14, 0x400000fd },
-       { 0x16, 0x40f000f9 },
-       { 0x17, 0x400000fa },
-       { 0x18, 0x400000fc },
-       { 0x21, 0x0144131f },
-       { 0x22, 0x40c003f8 },
-       /* Enable SPDIF in/out */
-       { 0x1f, 0x01441030 },
-       { 0x20, 0x1c410030 },
-       {}
-};
-
-static const struct hda_pintbl dell_9205_m44_pin_configs[] = {
-       { 0x0a, 0x0421101f },
-       { 0x0b, 0x04a11020 },
-       { 0x0c, 0x400003fa },
-       { 0x0d, 0x90170310 },
-       { 0x0e, 0x400003fb },
-       { 0x0f, 0x400003fc },
-       { 0x14, 0x400003fd },
-       { 0x16, 0x400003f9 },
-       { 0x17, 0x90a60330 },
-       { 0x18, 0x400003ff },
-       { 0x21, 0x01441340 },
-       { 0x22, 0x40c003fe },
-       {}
-};
-
-static void stac9205_fixup_ref(struct hda_codec *codec,
-                              const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               snd_hda_apply_pincfgs(codec, ref9205_pin_configs);
-               /* SPDIF-In enabled */
-               spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0;
-       }
-}
-
-static void stac9205_fixup_dell_m43(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       struct hda_jack_callback *jack;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs);
-
-               /* Enable unsol response for GPIO4/Dock HP connection */
-               snd_hda_codec_write_cache(codec, codec->core.afg, 0,
-                       AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10);
-               jack = snd_hda_jack_detect_enable_callback(codec, codec->core.afg,
-                                                          stac_vref_event);
-               if (!IS_ERR(jack))
-                       jack->private_data = 0x01;
-
-               spec->gpio_dir = 0x0b;
-               spec->eapd_mask = 0x01;
-               spec->gpio_mask = 0x1b;
-               spec->gpio_mute = 0x10;
-               /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute,
-                * GPIO3 Low = DRM
-                */
-               spec->gpio_data = 0x01;
-       }
-}
-
-static void stac9205_fixup_eapd(struct hda_codec *codec,
-                               const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               spec->eapd_switch = 0;
-}
-
-static const struct hda_fixup stac9205_fixups[] = {
-       [STAC_9205_REF] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac9205_fixup_ref,
-       },
-       [STAC_9205_DELL_M42] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_9205_m42_pin_configs,
-       },
-       [STAC_9205_DELL_M43] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac9205_fixup_dell_m43,
-       },
-       [STAC_9205_DELL_M44] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = dell_9205_m44_pin_configs,
-       },
-       [STAC_9205_EAPD] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac9205_fixup_eapd,
-       },
-       {}
-};
-
-static const struct hda_model_fixup stac9205_models[] = {
-       { .id = STAC_9205_REF, .name = "ref" },
-       { .id = STAC_9205_DELL_M42, .name = "dell-m42" },
-       { .id = STAC_9205_DELL_M43, .name = "dell-m43" },
-       { .id = STAC_9205_DELL_M44, .name = "dell-m44" },
-       { .id = STAC_9205_EAPD, .name = "eapd" },
-       {}
-};
-
-static const struct hda_quirk stac9205_fixup_tbl[] = {
-       /* SigmaTel reference board */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668,
-                     "DFI LanParty", STAC_9205_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30,
-                     "SigmaTel", STAC_9205_REF),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101,
-                     "DFI LanParty", STAC_9205_REF),
-       /* Dell */
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f1,
-                     "unknown Dell", STAC_9205_DELL_M42),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f2,
-                     "unknown Dell", STAC_9205_DELL_M42),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f8,
-                     "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f9,
-                     "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fa,
-                     "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fc,
-                     "unknown Dell", STAC_9205_DELL_M42),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fd,
-                     "unknown Dell", STAC_9205_DELL_M42),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01fe,
-                     "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01ff,
-                     "Dell Precision M4300", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0204,
-                     "unknown Dell", STAC_9205_DELL_M42),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0206,
-                     "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021b,
-                     "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021c,
-                     "Dell Precision", STAC_9205_DELL_M43),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x021f,
-                     "Dell Inspiron", STAC_9205_DELL_M44),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228,
-                     "Dell Vostro 1500", STAC_9205_DELL_M42),
-       SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0229,
-                     "Dell Vostro 1700", STAC_9205_DELL_M42),
-       /* Gateway */
-       SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD),
-       SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD),
-       {} /* terminator */
-};
-
-static void stac92hd95_fixup_hp_led(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       if (action != HDA_FIXUP_ACT_PRE_PROBE)
-               return;
-
-       if (find_mute_led_cfg(codec, spec->default_polarity))
-               codec_dbg(codec, "mute LED gpio %d polarity %d\n",
-                               spec->gpio_led,
-                               spec->gpio_led_polarity);
-}
-
-static const struct hda_fixup stac92hd95_fixups[] = {
-       [STAC_92HD95_HP_LED] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = stac92hd95_fixup_hp_led,
-       },
-       [STAC_92HD95_HP_BASS] = {
-               .type = HDA_FIXUP_VERBS,
-               .v.verbs = (const struct hda_verb[]) {
-                       {0x1a, 0x795, 0x00}, /* HPF to 100Hz */
-                       {}
-               },
-               .chained = true,
-               .chain_id = STAC_92HD95_HP_LED,
-       },
-};
-
-static const struct hda_quirk stac92hd95_fixup_tbl[] = {
-       SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1911, "HP Spectre 13", STAC_92HD95_HP_BASS),
-       {} /* terminator */
-};
-
-static const struct hda_model_fixup stac92hd95_models[] = {
-       { .id = STAC_92HD95_HP_LED, .name = "hp-led" },
-       { .id = STAC_92HD95_HP_BASS, .name = "hp-bass" },
-       {}
-};
-
-
-static int stac_parse_auto_config(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int err;
-       int flags = 0;
-
-       if (spec->headset_jack)
-               flags |= HDA_PINCFG_HEADSET_MIC;
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, flags);
-       if (err < 0)
-               return err;
-
-       /* add hooks */
-       spec->gen.pcm_playback_hook = stac_playback_pcm_hook;
-       spec->gen.pcm_capture_hook = stac_capture_pcm_hook;
-
-       spec->gen.automute_hook = stac_update_outputs;
-
-       if (spec->gpio_led)
-               snd_hda_gen_add_mute_led_cdev(codec, stac_vmaster_hook);
-
-       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
-       if (err < 0)
-               return err;
-
-       if (spec->vref_mute_led_nid) {
-               err = snd_hda_gen_fix_pin_power(codec, spec->vref_mute_led_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       /* setup analog beep controls */
-       if (spec->anabeep_nid > 0) {
-               err = stac_auto_create_beep_ctls(codec,
-                                                spec->anabeep_nid);
-               if (err < 0)
-                       return err;
-       }
-
-       /* setup digital beep controls and input device */
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-       if (spec->gen.beep_nid) {
-               hda_nid_t nid = spec->gen.beep_nid;
-               unsigned int caps;
-
-               err = stac_auto_create_beep_ctls(codec, nid);
-               if (err < 0)
-                       return err;
-               if (codec->beep) {
-                       /* IDT/STAC codecs have linear beep tone parameter */
-                       codec->beep->linear_tone = spec->linear_tone_beep;
-                       /* keep power up while beep is enabled */
-                       codec->beep->keep_power_at_enable = 1;
-                       /* if no beep switch is available, make its own one */
-                       caps = query_amp_caps(codec, nid, HDA_OUTPUT);
-                       if (!(caps & AC_AMPCAP_MUTE)) {
-                               err = stac_beep_switch_ctl(codec);
-                               if (err < 0)
-                                       return err;
-                       }
-               }
-       }
-#endif
-
-       if (spec->aloopback_ctl &&
-           snd_hda_get_bool_hint(codec, "loopback") == 1) {
-               unsigned int wr_verb =
-                       spec->aloopback_ctl->private_value >> 16;
-               if (snd_hdac_regmap_add_vendor_verb(&codec->core, wr_verb))
-                       return -ENOMEM;
-               if (!snd_hda_gen_add_kctl(&spec->gen, NULL, spec->aloopback_ctl))
-                       return -ENOMEM;
-       }
-
-       if (spec->have_spdif_mux) {
-               err = stac_create_spdif_mux_ctls(codec);
-               if (err < 0)
-                       return err;
-       }
-
-       stac_init_power_map(codec);
-
-       return 0;
-}
-
-static int stac_init(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-       int i;
-
-       /* override some hints */
-       stac_store_hints(codec);
-
-       /* set up GPIO */
-       /* turn on EAPD statically when spec->eapd_switch isn't set.
-        * otherwise, unsol event will turn it on/off dynamically
-        */
-       if (!spec->eapd_switch)
-               spec->gpio_data |= spec->eapd_mask;
-       stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data);
-
-       snd_hda_gen_init(codec);
-
-       /* sync the power-map */
-       if (spec->num_pwrs)
-               snd_hda_codec_write(codec, codec->core.afg, 0,
-                                   AC_VERB_IDT_SET_POWER_MAP,
-                                   spec->power_map_bits);
-
-       /* power down inactive ADCs */
-       if (spec->powerdown_adcs) {
-               for (i = 0; i < spec->gen.num_all_adcs; i++) {
-                       if (spec->active_adcs & (1 << i))
-                               continue;
-                       snd_hda_codec_write(codec, spec->gen.all_adcs[i], 0,
-                                           AC_VERB_SET_POWER_STATE,
-                                           AC_PWRST_D3);
-               }
-       }
-
-       return 0;
-}
-
-#define stac_free      snd_hda_gen_free
-
-#ifdef CONFIG_SND_PROC_FS
-static void stac92hd_proc_hook(struct snd_info_buffer *buffer,
-                              struct hda_codec *codec, hda_nid_t nid)
-{
-       if (nid == codec->core.afg)
-               snd_iprintf(buffer, "Power-Map: 0x%02x\n", 
-                           snd_hda_codec_read(codec, nid, 0,
-                                              AC_VERB_IDT_GET_POWER_MAP, 0));
-}
-
-static void analog_loop_proc_hook(struct snd_info_buffer *buffer,
-                                 struct hda_codec *codec,
-                                 unsigned int verb)
-{
-       snd_iprintf(buffer, "Analog Loopback: 0x%02x\n",
-                   snd_hda_codec_read(codec, codec->core.afg, 0, verb, 0));
-}
-
-/* stac92hd71bxx, stac92hd73xx */
-static void stac92hd7x_proc_hook(struct snd_info_buffer *buffer,
-                                struct hda_codec *codec, hda_nid_t nid)
-{
-       stac92hd_proc_hook(buffer, codec, nid);
-       if (nid == codec->core.afg)
-               analog_loop_proc_hook(buffer, codec, 0xfa0);
-}
-
-static void stac9205_proc_hook(struct snd_info_buffer *buffer,
-                              struct hda_codec *codec, hda_nid_t nid)
-{
-       if (nid == codec->core.afg)
-               analog_loop_proc_hook(buffer, codec, 0xfe0);
-}
-
-static void stac927x_proc_hook(struct snd_info_buffer *buffer,
-                              struct hda_codec *codec, hda_nid_t nid)
-{
-       if (nid == codec->core.afg)
-               analog_loop_proc_hook(buffer, codec, 0xfeb);
-}
-#else
-#define stac92hd_proc_hook     NULL
-#define stac92hd7x_proc_hook   NULL
-#define stac9205_proc_hook     NULL
-#define stac927x_proc_hook     NULL
-#endif
-
-static int stac_suspend(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       snd_hda_shutup_pins(codec);
-
-       if (spec->eapd_mask)
-               stac_gpio_set(codec, spec->gpio_mask,
-                               spec->gpio_dir, spec->gpio_data &
-                               ~spec->eapd_mask);
-
-       return 0;
-}
-
-static const struct hda_codec_ops stac_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = stac_init,
-       .free = stac_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .suspend = stac_suspend,
-};
-
-static int alloc_stac_spec(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (!spec)
-               return -ENOMEM;
-       snd_hda_gen_spec_init(&spec->gen);
-       codec->spec = spec;
-       codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */
-       spec->gen.dac_min_mute = true;
-       codec->patch_ops = stac_patch_ops;
-       return 0;
-}
-
-static int patch_stac9200(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->linear_tone_beep = 1;
-       spec->gen.own_eapd_ctl = 1;
-
-       codec->power_filter = snd_hda_codec_eapd_power_filter;
-
-       snd_hda_add_verbs(codec, stac9200_eapd_init);
-
-       snd_hda_pick_fixup(codec, stac9200_models, stac9200_fixup_tbl,
-                          stac9200_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-static int patch_stac925x(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->linear_tone_beep = 1;
-       spec->gen.own_eapd_ctl = 1;
-
-       snd_hda_add_verbs(codec, stac925x_core_init);
-
-       snd_hda_pick_fixup(codec, stac925x_models, stac925x_fixup_tbl,
-                          stac925x_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-static int patch_stac92hd73xx(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-       int num_dacs;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       /* enable power_save_node only for new 92HD89xx chips, as it causes
-        * click noises on old 92HD73xx chips.
-        */
-       if ((codec->core.vendor_id & 0xfffffff0) != 0x111d7670)
-               codec->power_save_node = 1;
-       spec->linear_tone_beep = 0;
-       spec->gen.mixer_nid = 0x1d;
-       spec->have_spdif_mux = 1;
-
-       num_dacs = snd_hda_get_num_conns(codec, 0x0a) - 1;
-       if (num_dacs < 3 || num_dacs > 5) {
-               codec_warn(codec,
-                          "Could not determine number of channels defaulting to DAC count\n");
-               num_dacs = 5;
-       }
-
-       switch (num_dacs) {
-       case 0x3: /* 6 Channel */
-               spec->aloopback_ctl = &stac92hd73xx_6ch_loopback;
-               break;
-       case 0x4: /* 8 Channel */
-               spec->aloopback_ctl = &stac92hd73xx_8ch_loopback;
-               break;
-       case 0x5: /* 10 Channel */
-               spec->aloopback_ctl = &stac92hd73xx_10ch_loopback;
-               break;
-       }
-
-       spec->aloopback_mask = 0x01;
-       spec->aloopback_shift = 8;
-
-       spec->gen.beep_nid = 0x1c; /* digital beep */
-
-       /* GPIO0 High = Enable EAPD */
-       spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
-       spec->gpio_data = 0x01;
-
-       spec->eapd_switch = 1;
-
-       spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids);
-       spec->pwr_nids = stac92hd73xx_pwr_nids;
-
-       spec->gen.own_eapd_ctl = 1;
-       spec->gen.power_down_unused = 1;
-
-       snd_hda_pick_fixup(codec, stac92hd73xx_models, stac92hd73xx_fixup_tbl,
-                          stac92hd73xx_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       if (!spec->volknob_init)
-               snd_hda_add_verbs(codec, stac92hd73xx_core_init);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       /* Don't GPIO-mute speakers if there are no internal speakers, because
-        * the GPIO might be necessary for Headphone
-        */
-       if (spec->eapd_switch && !has_builtin_speaker(codec))
-               spec->eapd_switch = 0;
-
-       codec->proc_widget_hook = stac92hd7x_proc_hook;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-static void stac_setup_gpio(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec = codec->spec;
-
-       spec->gpio_mask |= spec->eapd_mask;
-       if (spec->gpio_led) {
-               if (!spec->vref_mute_led_nid) {
-                       spec->gpio_mask |= spec->gpio_led;
-                       spec->gpio_dir |= spec->gpio_led;
-                       spec->gpio_data |= spec->gpio_led;
-               } else {
-                       codec->power_filter = stac_vref_led_power_filter;
-               }
-       }
-
-       if (spec->mic_mute_led_gpio) {
-               spec->gpio_mask |= spec->mic_mute_led_gpio;
-               spec->gpio_dir |= spec->mic_mute_led_gpio;
-               spec->mic_enabled = 0;
-               spec->gpio_data |= spec->mic_mute_led_gpio;
-               snd_hda_gen_add_micmute_led_cdev(codec, stac_capture_led_update);
-       }
-}
-
-static int patch_stac92hd83xxx(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       /* longer delay needed for D3 */
-       codec->core.power_caps &= ~AC_PWRST_EPSS;
-
-       spec = codec->spec;
-       codec->power_save_node = 1;
-       spec->linear_tone_beep = 0;
-       spec->gen.own_eapd_ctl = 1;
-       spec->gen.power_down_unused = 1;
-       spec->gen.mixer_nid = 0x1b;
-
-       spec->gen.beep_nid = 0x21; /* digital beep */
-       spec->pwr_nids = stac92hd83xxx_pwr_nids;
-       spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids);
-       spec->default_polarity = -1; /* no default cfg */
-
-       snd_hda_add_verbs(codec, stac92hd83xxx_core_init);
-
-       snd_hda_pick_fixup(codec, stac92hd83xxx_models, stac92hd83xxx_fixup_tbl,
-                          stac92hd83xxx_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       stac_setup_gpio(codec);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       codec->proc_widget_hook = stac92hd_proc_hook;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-static const hda_nid_t stac92hd95_pwr_nids[] = {
-       0x0a, 0x0b, 0x0c, 0x0d
-};
-
-static int patch_stac92hd95(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       /* longer delay needed for D3 */
-       codec->core.power_caps &= ~AC_PWRST_EPSS;
-
-       spec = codec->spec;
-       codec->power_save_node = 1;
-       spec->linear_tone_beep = 0;
-       spec->gen.own_eapd_ctl = 1;
-       spec->gen.power_down_unused = 1;
-
-       spec->gen.beep_nid = 0x19; /* digital beep */
-       spec->pwr_nids = stac92hd95_pwr_nids;
-       spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids);
-       spec->default_polarity = 0;
-
-       snd_hda_pick_fixup(codec, stac92hd95_models, stac92hd95_fixup_tbl,
-                          stac92hd95_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       stac_setup_gpio(codec);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       codec->proc_widget_hook = stac92hd_proc_hook;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-static int patch_stac92hd71bxx(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       const hda_nid_t *unmute_nids = stac92hd71bxx_unmute_nids;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       /* disabled power_save_node since it causes noises on a Dell machine */
-       /* codec->power_save_node = 1; */
-       spec->linear_tone_beep = 0;
-       spec->gen.own_eapd_ctl = 1;
-       spec->gen.power_down_unused = 1;
-       spec->gen.mixer_nid = 0x17;
-       spec->have_spdif_mux = 1;
-
-       /* GPIO0 = EAPD */
-       spec->gpio_mask = 0x01;
-       spec->gpio_dir = 0x01;
-       spec->gpio_data = 0x01;
-
-       switch (codec->core.vendor_id) {
-       case 0x111d76b6: /* 4 Port without Analog Mixer */
-       case 0x111d76b7:
-               unmute_nids++;
-               break;
-       case 0x111d7608: /* 5 Port with Analog Mixer */
-               if ((codec->core.revision_id & 0xf) == 0 ||
-                   (codec->core.revision_id & 0xf) == 1)
-                       spec->stream_delay = 40; /* 40 milliseconds */
-
-               /* disable VSW */
-               unmute_nids++;
-               snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0);
-               snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3);
-               break;
-       case 0x111d7603: /* 6 Port with Analog Mixer */
-               if ((codec->core.revision_id & 0xf) == 1)
-                       spec->stream_delay = 40; /* 40 milliseconds */
-
-               break;
-       }
-
-       if (get_wcaps_type(get_wcaps(codec, 0x28)) == AC_WID_VOL_KNB)
-               snd_hda_add_verbs(codec, stac92hd71bxx_core_init);
-
-       if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) {
-               const hda_nid_t *p;
-               for (p = unmute_nids; *p; p++)
-                       snd_hda_codec_amp_init_stereo(codec, *p, HDA_INPUT, 0,
-                                                     0xff, 0x00);
-       }
-
-       spec->aloopback_ctl = &stac92hd71bxx_loopback;
-       spec->aloopback_mask = 0x50;
-       spec->aloopback_shift = 0;
-
-       spec->powerdown_adcs = 1;
-       spec->gen.beep_nid = 0x26; /* digital beep */
-       spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids);
-       spec->pwr_nids = stac92hd71bxx_pwr_nids;
-
-       snd_hda_pick_fixup(codec, stac92hd71bxx_models, stac92hd71bxx_fixup_tbl,
-                          stac92hd71bxx_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       stac_setup_gpio(codec);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       codec->proc_widget_hook = stac92hd7x_proc_hook;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-static int patch_stac922x(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->linear_tone_beep = 1;
-       spec->gen.own_eapd_ctl = 1;
-
-       snd_hda_add_verbs(codec, stac922x_core_init);
-
-       /* Fix Mux capture level; max to 2 */
-       snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT,
-                                 (0 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (2 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (0 << AC_AMPCAP_MUTE_SHIFT));
-
-       snd_hda_pick_fixup(codec, stac922x_models, stac922x_fixup_tbl,
-                          stac922x_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-static const char * const stac927x_spdif_labels[] = {
-       "Digital Playback", "ADAT", "Analog Mux 1",
-       "Analog Mux 2", "Analog Mux 3", NULL
-};
-
-static int patch_stac927x(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->linear_tone_beep = 1;
-       spec->gen.own_eapd_ctl = 1;
-       spec->have_spdif_mux = 1;
-       spec->spdif_labels = stac927x_spdif_labels;
-
-       spec->gen.beep_nid = 0x23; /* digital beep */
-
-       /* GPIO0 High = Enable EAPD */
-       spec->eapd_mask = spec->gpio_mask = 0x01;
-       spec->gpio_dir = spec->gpio_data = 0x01;
-
-       spec->aloopback_ctl = &stac927x_loopback;
-       spec->aloopback_mask = 0x40;
-       spec->aloopback_shift = 0;
-       spec->eapd_switch = 1;
-
-       snd_hda_pick_fixup(codec, stac927x_models, stac927x_fixup_tbl,
-                          stac927x_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       if (!spec->volknob_init)
-               snd_hda_add_verbs(codec, stac927x_core_init);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       codec->proc_widget_hook = stac927x_proc_hook;
-
-       /*
-        * !!FIXME!!
-        * The STAC927x seem to require fairly long delays for certain
-        * command sequences.  With too short delays (even if the answer
-        * is set to RIRB properly), it results in the silence output
-        * on some hardwares like Dell.
-        *
-        * The below flag enables the longer delay (see get_response
-        * in hda_intel.c).
-        */
-       codec->bus->core.needs_damn_long_delay = 1;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-static int patch_stac9205(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->linear_tone_beep = 1;
-       spec->gen.own_eapd_ctl = 1;
-       spec->have_spdif_mux = 1;
-
-       spec->gen.beep_nid = 0x23; /* digital beep */
-
-       snd_hda_add_verbs(codec, stac9205_core_init);
-       spec->aloopback_ctl = &stac9205_loopback;
-
-       spec->aloopback_mask = 0x40;
-       spec->aloopback_shift = 0;
-       
-       /* GPIO0 High = EAPD */
-       spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1;
-       spec->gpio_data = 0x01;
-
-       /* Turn on/off EAPD per HP plugging */
-       spec->eapd_switch = 1;
-
-       snd_hda_pick_fixup(codec, stac9205_models, stac9205_fixup_tbl,
-                          stac9205_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return err;
-       }
-
-       codec->proc_widget_hook = stac9205_proc_hook;
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-/*
- * STAC9872 hack
- */
-
-static const struct hda_verb stac9872_core_init[] = {
-       {0x15, AC_VERB_SET_CONNECT_SEL, 0x1}, /* mic-sel: 0a,0d,14,02 */
-       {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Mic-in -> 0x9 */
-       {}
-};
-
-static const struct hda_pintbl stac9872_vaio_pin_configs[] = {
-       { 0x0a, 0x03211020 },
-       { 0x0b, 0x411111f0 },
-       { 0x0c, 0x411111f0 },
-       { 0x0d, 0x03a15030 },
-       { 0x0e, 0x411111f0 },
-       { 0x0f, 0x90170110 },
-       { 0x11, 0x411111f0 },
-       { 0x13, 0x411111f0 },
-       { 0x14, 0x90a7013e },
-       {}
-};
-
-static const struct hda_model_fixup stac9872_models[] = {
-       { .id = STAC_9872_VAIO, .name = "vaio" },
-       {}
-};
-
-static const struct hda_fixup stac9872_fixups[] = {
-       [STAC_9872_VAIO] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = stac9872_vaio_pin_configs,
-       },
-};
-
-static const struct hda_quirk stac9872_fixup_tbl[] = {
-       SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0,
-                          "Sony VAIO F/S", STAC_9872_VAIO),
-       {} /* terminator */
-};
-
-static int patch_stac9872(struct hda_codec *codec)
-{
-       struct sigmatel_spec *spec;
-       int err;
-
-       err = alloc_stac_spec(codec);
-       if (err < 0)
-               return err;
-
-       spec = codec->spec;
-       spec->linear_tone_beep = 1;
-       spec->gen.own_eapd_ctl = 1;
-
-       snd_hda_add_verbs(codec, stac9872_core_init);
-
-       snd_hda_pick_fixup(codec, stac9872_models, stac9872_fixup_tbl,
-                          stac9872_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       err = stac_parse_auto_config(codec);
-       if (err < 0) {
-               stac_free(codec);
-               return -EINVAL;
-       }
-
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE);
-
-       return 0;
-}
-
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_sigmatel[] = {
-       HDA_CODEC_ENTRY(0x83847690, "STAC9200", patch_stac9200),
-       HDA_CODEC_ENTRY(0x83847882, "STAC9220 A1", patch_stac922x),
-       HDA_CODEC_ENTRY(0x83847680, "STAC9221 A1", patch_stac922x),
-       HDA_CODEC_ENTRY(0x83847880, "STAC9220 A2", patch_stac922x),
-       HDA_CODEC_ENTRY(0x83847681, "STAC9220D/9223D A2", patch_stac922x),
-       HDA_CODEC_ENTRY(0x83847682, "STAC9221 A2", patch_stac922x),
-       HDA_CODEC_ENTRY(0x83847683, "STAC9221D A2", patch_stac922x),
-       HDA_CODEC_ENTRY(0x83847618, "STAC9227", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847619, "STAC9227", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847638, "STAC92HD700", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847616, "STAC9228", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847617, "STAC9228", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847614, "STAC9229", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847615, "STAC9229", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847620, "STAC9274", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847621, "STAC9274D", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847622, "STAC9273X", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847623, "STAC9273D", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847624, "STAC9272X", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847625, "STAC9272D", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847626, "STAC9271X", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847627, "STAC9271D", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847628, "STAC9274X5NH", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847629, "STAC9274D5NH", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847632, "STAC9202",  patch_stac925x),
-       HDA_CODEC_ENTRY(0x83847633, "STAC9202D", patch_stac925x),
-       HDA_CODEC_ENTRY(0x83847634, "STAC9250", patch_stac925x),
-       HDA_CODEC_ENTRY(0x83847635, "STAC9250D", patch_stac925x),
-       HDA_CODEC_ENTRY(0x83847636, "STAC9251", patch_stac925x),
-       HDA_CODEC_ENTRY(0x83847637, "STAC9250D", patch_stac925x),
-       HDA_CODEC_ENTRY(0x83847645, "92HD206X", patch_stac927x),
-       HDA_CODEC_ENTRY(0x83847646, "92HD206D", patch_stac927x),
-       /* The following does not take into account .id=0x83847661 when subsys =
-        * 104D0C00 which is STAC9225s. Because of this, some SZ Notebooks are
-        * currently not fully supported.
-        */
-       HDA_CODEC_ENTRY(0x83847661, "CXD9872RD/K", patch_stac9872),
-       HDA_CODEC_ENTRY(0x83847662, "STAC9872AK", patch_stac9872),
-       HDA_CODEC_ENTRY(0x83847664, "CXD9872AKD", patch_stac9872),
-       HDA_CODEC_ENTRY(0x83847698, "STAC9205", patch_stac9205),
-       HDA_CODEC_ENTRY(0x838476a0, "STAC9205", patch_stac9205),
-       HDA_CODEC_ENTRY(0x838476a1, "STAC9205D", patch_stac9205),
-       HDA_CODEC_ENTRY(0x838476a2, "STAC9204", patch_stac9205),
-       HDA_CODEC_ENTRY(0x838476a3, "STAC9204D", patch_stac9205),
-       HDA_CODEC_ENTRY(0x838476a4, "STAC9255", patch_stac9205),
-       HDA_CODEC_ENTRY(0x838476a5, "STAC9255D", patch_stac9205),
-       HDA_CODEC_ENTRY(0x838476a6, "STAC9254", patch_stac9205),
-       HDA_CODEC_ENTRY(0x838476a7, "STAC9254D", patch_stac9205),
-       HDA_CODEC_ENTRY(0x111d7603, "92HD75B3X5", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d7604, "92HD83C1X5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76d4, "92HD83C1C5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d7605, "92HD81B1X5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76d5, "92HD81B1C5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76d1, "92HD87B1/3", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76d9, "92HD87B2/4", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d7666, "92HD88B3", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d7667, "92HD88B1", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d7668, "92HD88B2", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d7669, "92HD88B4", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d7608, "92HD75B2X5", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d7674, "92HD73D1X5", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d7675, "92HD73C1X5", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d7676, "92HD73E1X5", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d7695, "92HD95", patch_stac92hd95),
-       HDA_CODEC_ENTRY(0x111d76b0, "92HD71B8X", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d76b1, "92HD71B8X", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d76b2, "92HD71B7X", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d76b3, "92HD71B7X", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d76b4, "92HD71B6X", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d76b5, "92HD71B6X", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d76b6, "92HD71B5X", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d76b7, "92HD71B5X", patch_stac92hd71bxx),
-       HDA_CODEC_ENTRY(0x111d76c0, "92HD89C3", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c1, "92HD89C2", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c2, "92HD89C1", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c3, "92HD89B3", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c4, "92HD89B2", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c5, "92HD89B1", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c6, "92HD89E3", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c7, "92HD89E2", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c8, "92HD89E1", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76c9, "92HD89D3", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76ca, "92HD89D2", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76cb, "92HD89D1", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76cc, "92HD89F3", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76cd, "92HD89F2", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76ce, "92HD89F1", patch_stac92hd73xx),
-       HDA_CODEC_ENTRY(0x111d76df, "92HD93BXX", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76e0, "92HD91BXX", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76e3, "92HD98BXX", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76e5, "92HD99BXX", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76e7, "92HD90BXX", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76e8, "92HD66B1X5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76e9, "92HD66B2X5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76ea, "92HD66B3X5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76eb, "92HD66C1X5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76ec, "92HD66C2X5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76ed, "92HD66C3X5", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76ee, "92HD66B1X3", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76ef, "92HD66B2X3", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76f0, "92HD66B3X3", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76f1, "92HD66C1X3", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76f2, "92HD66C2X3", patch_stac92hd83xxx),
-       HDA_CODEC_ENTRY(0x111d76f3, "92HD66C3/65", patch_stac92hd83xxx),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_sigmatel);
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("IDT/Sigmatel HD-audio codec");
-
-static struct hda_codec_driver sigmatel_driver = {
-       .id = snd_hda_id_sigmatel,
-};
-
-module_hda_codec_driver(sigmatel_driver);
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
deleted file mode 100644 (file)
index d089305..0000000
+++ /dev/null
@@ -1,1247 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * Universal Interface for Intel High Definition Audio Codec
- *
- * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec
- *
- *  (C) 2006-2009 VIA Technology, Inc.
- *  (C) 2006-2008 Takashi Iwai <tiwai@suse.de>
- */
-
-/* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */
-/*                                                                          */
-/* 2006-03-03  Lydia Wang  Create the basic patch to support VT1708 codec    */
-/* 2006-03-14  Lydia Wang  Modify hard code for some pin widget nid         */
-/* 2006-08-02  Lydia Wang  Add support to VT1709 codec                      */
-/* 2006-09-08  Lydia Wang  Fix internal loopback recording source select bug */
-/* 2007-09-12  Lydia Wang  Add EAPD enable during driver initialization             */
-/* 2007-09-17  Lydia Wang  Add VT1708B codec support                       */
-/* 2007-11-14  Lydia Wang  Add VT1708A codec HP and CD pin connect config    */
-/* 2008-02-03  Lydia Wang  Fix Rear channels and Back channels inverse issue */
-/* 2008-03-06  Lydia Wang  Add VT1702 codec and VT1708S codec support       */
-/* 2008-04-09  Lydia Wang  Add mute front speaker when HP plugin            */
-/* 2008-04-09  Lydia Wang  Add Independent HP feature                       */
-/* 2008-05-28  Lydia Wang  Add second S/PDIF Out support for VT1702         */
-/* 2008-09-15  Logan Li           Add VT1708S Mic Boost workaround/backdoor         */
-/* 2009-02-16  Logan Li           Add support for VT1718S                           */
-/* 2009-03-13  Logan Li           Add support for VT1716S                           */
-/* 2009-04-14  Lydai Wang  Add support for VT1828S and VT2020               */
-/* 2009-07-08  Lydia Wang  Add support for VT2002P                          */
-/* 2009-07-21  Lydia Wang  Add support for VT1812                           */
-/* 2009-09-19  Lydia Wang  Add support for VT1818S                          */
-/*                                                                          */
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-
-
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <sound/core.h>
-#include <sound/asoundef.h>
-#include <sound/hda_codec.h>
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-
-/* Pin Widget NID */
-#define VT1708_HP_PIN_NID      0x20
-#define VT1708_CD_PIN_NID      0x24
-
-enum VIA_HDA_CODEC {
-       UNKNOWN = -1,
-       VT1708,
-       VT1709_10CH,
-       VT1709_6CH,
-       VT1708B_8CH,
-       VT1708B_4CH,
-       VT1708S,
-       VT1708BCE,
-       VT1702,
-       VT1718S,
-       VT1716S,
-       VT2002P,
-       VT1812,
-       VT1802,
-       VT1705CF,
-       VT1808,
-       CODEC_TYPES,
-};
-
-#define VT2002P_COMPATIBLE(spec) \
-       ((spec)->codec_type == VT2002P ||\
-        (spec)->codec_type == VT1812 ||\
-        (spec)->codec_type == VT1802)
-
-struct via_spec {
-       struct hda_gen_spec gen;
-
-       /* HP mode source */
-       unsigned int dmic_enabled;
-       enum VIA_HDA_CODEC codec_type;
-
-       /* analog low-power control */
-       bool alc_mode;
-
-       /* work to check hp jack state */
-       int hp_work_active;
-       int vt1708_jack_detect;
-};
-
-static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec);
-static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 struct snd_pcm_substream *substream,
-                                 int action);
-
-static const struct hda_codec_ops via_patch_ops; /* defined below */
-
-static struct via_spec *via_new_spec(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-
-       spec = kzalloc(sizeof(*spec), GFP_KERNEL);
-       if (spec == NULL)
-               return NULL;
-
-       codec->spec = spec;
-       snd_hda_gen_spec_init(&spec->gen);
-       spec->codec_type = get_codec_type(codec);
-       /* VT1708BCE & VT1708S are almost same */
-       if (spec->codec_type == VT1708BCE)
-               spec->codec_type = VT1708S;
-       spec->gen.indep_hp = 1;
-       spec->gen.keep_eapd_on = 1;
-       spec->gen.dac_min_mute = 1;
-       spec->gen.pcm_playback_hook = via_playback_pcm_hook;
-       spec->gen.add_stereo_mix_input = HDA_HINT_STEREO_MIX_AUTO;
-       codec->power_save_node = 1;
-       spec->gen.power_down_unused = 1;
-       codec->patch_ops = via_patch_ops;
-       return spec;
-}
-
-static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec)
-{
-       u32 vendor_id = codec->core.vendor_id;
-       u16 ven_id = vendor_id >> 16;
-       u16 dev_id = vendor_id & 0xffff;
-       enum VIA_HDA_CODEC codec_type;
-
-       /* get codec type */
-       if (ven_id != 0x1106)
-               codec_type = UNKNOWN;
-       else if (dev_id >= 0x1708 && dev_id <= 0x170b)
-               codec_type = VT1708;
-       else if (dev_id >= 0xe710 && dev_id <= 0xe713)
-               codec_type = VT1709_10CH;
-       else if (dev_id >= 0xe714 && dev_id <= 0xe717)
-               codec_type = VT1709_6CH;
-       else if (dev_id >= 0xe720 && dev_id <= 0xe723) {
-               codec_type = VT1708B_8CH;
-               if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7)
-                       codec_type = VT1708BCE;
-       } else if (dev_id >= 0xe724 && dev_id <= 0xe727)
-               codec_type = VT1708B_4CH;
-       else if ((dev_id & 0xfff) == 0x397
-                && (dev_id >> 12) < 8)
-               codec_type = VT1708S;
-       else if ((dev_id & 0xfff) == 0x398
-                && (dev_id >> 12) < 8)
-               codec_type = VT1702;
-       else if ((dev_id & 0xfff) == 0x428
-                && (dev_id >> 12) < 8)
-               codec_type = VT1718S;
-       else if (dev_id == 0x0433 || dev_id == 0xa721)
-               codec_type = VT1716S;
-       else if (dev_id == 0x0441 || dev_id == 0x4441)
-               codec_type = VT1718S;
-       else if (dev_id == 0x0438 || dev_id == 0x4438)
-               codec_type = VT2002P;
-       else if (dev_id == 0x0448)
-               codec_type = VT1812;
-       else if (dev_id == 0x0440)
-               codec_type = VT1708S;
-       else if ((dev_id & 0xfff) == 0x446)
-               codec_type = VT1802;
-       else if (dev_id == 0x4760)
-               codec_type = VT1705CF;
-       else if (dev_id == 0x4761 || dev_id == 0x4762)
-               codec_type = VT1808;
-       else
-               codec_type = UNKNOWN;
-       return codec_type;
-};
-
-static void analog_low_current_mode(struct hda_codec *codec);
-static bool is_aa_path_mute(struct hda_codec *codec);
-
-#define hp_detect_with_aa(codec) \
-       (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1 && \
-        !is_aa_path_mute(codec))
-
-static void vt1708_stop_hp_work(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs)
-               return;
-       if (spec->hp_work_active) {
-               snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1);
-               codec->jackpoll_interval = 0;
-               cancel_delayed_work_sync(&codec->jackpoll_work);
-               spec->hp_work_active = false;
-       }
-}
-
-static void vt1708_update_hp_work(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs)
-               return;
-       if (spec->vt1708_jack_detect) {
-               if (!spec->hp_work_active) {
-                       codec->jackpoll_interval = msecs_to_jiffies(100);
-                       snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0);
-                       schedule_delayed_work(&codec->jackpoll_work, 0);
-                       spec->hp_work_active = true;
-               }
-       } else if (!hp_detect_with_aa(codec))
-               vt1708_stop_hp_work(codec);
-}
-
-static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_info *uinfo)
-{
-       return snd_hda_enum_bool_helper_info(kcontrol, uinfo);
-}
-
-static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-
-       ucontrol->value.enumerated.item[0] = spec->gen.power_down_unused;
-       return 0;
-}
-
-static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       bool val = !!ucontrol->value.enumerated.item[0];
-
-       if (val == spec->gen.power_down_unused)
-               return 0;
-       /* codec->power_save_node = val; */ /* widget PM seems yet broken */
-       spec->gen.power_down_unused = val;
-       analog_low_current_mode(codec);
-       return 1;
-}
-
-static const struct snd_kcontrol_new via_pin_power_ctl_enum = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Dynamic Power-Control",
-       .info = via_pin_power_ctl_info,
-       .get = via_pin_power_ctl_get,
-       .put = via_pin_power_ctl_put,
-};
-
-#ifdef CONFIG_SND_HDA_INPUT_BEEP
-/* additional beep mixers; the actual parameters are overwritten at build */
-static const struct snd_kcontrol_new via_beep_mixer[] = {
-       HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT),
-       HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT),
-};
-
-static int set_beep_amp(struct via_spec *spec, hda_nid_t nid,
-                       int idx, int dir)
-{
-       struct snd_kcontrol_new *knew;
-       unsigned int beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir);
-       int i;
-
-       spec->gen.beep_nid = nid;
-       for (i = 0; i < ARRAY_SIZE(via_beep_mixer); i++) {
-               knew = snd_hda_gen_add_kctl(&spec->gen, NULL,
-                                           &via_beep_mixer[i]);
-               if (!knew)
-                       return -ENOMEM;
-               knew->private_value = beep_amp;
-       }
-       return 0;
-}
-
-static int auto_parse_beep(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       hda_nid_t nid;
-
-       for_each_hda_codec_node(nid, codec)
-               if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP)
-                       return set_beep_amp(spec, nid, 0, HDA_OUTPUT);
-       return 0;
-}
-#else
-#define auto_parse_beep(codec) 0
-#endif
-
-/* check AA path's mute status */
-static bool is_aa_path_mute(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       const struct hda_amp_list *p;
-       int ch, v;
-
-       p = spec->gen.loopback.amplist;
-       if (!p)
-               return true;
-       for (; p->nid; p++) {
-               for (ch = 0; ch < 2; ch++) {
-                       v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir,
-                                                  p->idx);
-                       if (!(v & HDA_AMP_MUTE) && v > 0)
-                               return false;
-               }
-       }
-       return true;
-}
-
-/* enter/exit analog low-current mode */
-static void __analog_low_current_mode(struct hda_codec *codec, bool force)
-{
-       struct via_spec *spec = codec->spec;
-       bool enable;
-       unsigned int verb, parm;
-
-       if (!codec->power_save_node)
-               enable = false;
-       else
-               enable = is_aa_path_mute(codec) && !spec->gen.active_streams;
-       if (enable == spec->alc_mode && !force)
-               return;
-       spec->alc_mode = enable;
-
-       /* decide low current mode's verb & parameter */
-       switch (spec->codec_type) {
-       case VT1708B_8CH:
-       case VT1708B_4CH:
-               verb = 0xf70;
-               parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */
-               break;
-       case VT1708S:
-       case VT1718S:
-       case VT1716S:
-               verb = 0xf73;
-               parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */
-               break;
-       case VT1702:
-               verb = 0xf73;
-               parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */
-               break;
-       case VT2002P:
-       case VT1812:
-       case VT1802:
-               verb = 0xf93;
-               parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */
-               break;
-       case VT1705CF:
-       case VT1808:
-               verb = 0xf82;
-               parm = enable ? 0x00 : 0xe0;  /* 0x00: 4/40x, 0xe0: 1x */
-               break;
-       default:
-               return;         /* other codecs are not supported */
-       }
-       /* send verb */
-       snd_hda_codec_write(codec, codec->core.afg, 0, verb, parm);
-}
-
-static void analog_low_current_mode(struct hda_codec *codec)
-{
-       return __analog_low_current_mode(codec, false);
-}
-
-static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo,
-                                 struct hda_codec *codec,
-                                 struct snd_pcm_substream *substream,
-                                 int action)
-{
-       analog_low_current_mode(codec);
-       vt1708_update_hp_work(codec);
-}
-
-static void via_free(struct hda_codec *codec)
-{
-       vt1708_stop_hp_work(codec);
-       snd_hda_gen_free(codec);
-}
-
-static int via_suspend(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       vt1708_stop_hp_work(codec);
-
-       /* Fix pop noise on headphones */
-       if (spec->codec_type == VT1802)
-               snd_hda_shutup_pins(codec);
-
-       return 0;
-}
-
-static int via_resume(struct hda_codec *codec)
-{
-       /* some delay here to make jack detection working (bko#98921) */
-       msleep(10);
-       codec->patch_ops.init(codec);
-       snd_hda_regmap_sync(codec);
-       return 0;
-}
-
-static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid)
-{
-       struct via_spec *spec = codec->spec;
-       analog_low_current_mode(codec);
-       vt1708_update_hp_work(codec);
-       return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid);
-}
-
-/*
- */
-
-static int via_init(struct hda_codec *codec);
-
-static const struct hda_codec_ops via_patch_ops = {
-       .build_controls = snd_hda_gen_build_controls,
-       .build_pcms = snd_hda_gen_build_pcms,
-       .init = via_init,
-       .free = via_free,
-       .unsol_event = snd_hda_jack_unsol_event,
-       .suspend = via_suspend,
-       .resume = via_resume,
-       .check_power_status = via_check_power_status,
-};
-
-
-static const struct hda_verb vt1708_init_verbs[] = {
-       /* power down jack detect function */
-       {0x1, 0xf81, 0x1},
-       { }
-};
-static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid)
-{
-       unsigned int def_conf;
-       unsigned char seqassoc;
-
-       def_conf = snd_hda_codec_get_pincfg(codec, nid);
-       seqassoc = (unsigned char) get_defcfg_association(def_conf);
-       seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf);
-       if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE
-           && (seqassoc == 0xf0 || seqassoc == 0xff)) {
-               def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30));
-               snd_hda_codec_set_pincfg(codec, nid, def_conf);
-       }
-}
-
-static int vt1708_jack_detect_get(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-
-       if (spec->codec_type != VT1708)
-               return 0;
-       ucontrol->value.integer.value[0] = spec->vt1708_jack_detect;
-       return 0;
-}
-
-static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol,
-                                    struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       int val;
-
-       if (spec->codec_type != VT1708)
-               return 0;
-       val = !!ucontrol->value.integer.value[0];
-       if (spec->vt1708_jack_detect == val)
-               return 0;
-       spec->vt1708_jack_detect = val;
-       vt1708_update_hp_work(codec);
-       return 1;
-}
-
-static const struct snd_kcontrol_new vt1708_jack_detect_ctl = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Jack Detect",
-       .count = 1,
-       .info = snd_ctl_boolean_mono_info,
-       .get = vt1708_jack_detect_get,
-       .put = vt1708_jack_detect_put,
-};
-
-static const struct badness_table via_main_out_badness = {
-       .no_primary_dac = 0x10000,
-       .no_dac = 0x4000,
-       .shared_primary = 0x10000,
-       .shared_surr = 0x20,
-       .shared_clfe = 0x20,
-       .shared_surr_main = 0x20,
-};
-static const struct badness_table via_extra_out_badness = {
-       .no_primary_dac = 0x4000,
-       .no_dac = 0x4000,
-       .shared_primary = 0x12,
-       .shared_surr = 0x20,
-       .shared_clfe = 0x20,
-       .shared_surr_main = 0x10,
-};
-
-static int via_parse_auto_config(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int err;
-
-       spec->gen.main_out_badness = &via_main_out_badness;
-       spec->gen.extra_out_badness = &via_extra_out_badness;
-
-       err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0);
-       if (err < 0)
-               return err;
-
-       err = auto_parse_beep(codec);
-       if (err < 0)
-               return err;
-
-       err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg);
-       if (err < 0)
-               return err;
-
-       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &via_pin_power_ctl_enum))
-               return -ENOMEM;
-
-       /* disable widget PM at start for compatibility */
-       codec->power_save_node = 0;
-       spec->gen.power_down_unused = 0;
-       return 0;
-}
-
-static int via_init(struct hda_codec *codec)
-{
-       /* init power states */
-       __analog_low_current_mode(codec, true);
-
-       snd_hda_gen_init(codec);
-
-       vt1708_update_hp_work(codec);
-
-       return 0;
-}
-
-static int vt1708_build_controls(struct hda_codec *codec)
-{
-       /* In order not to create "Phantom Jack" controls,
-          temporary enable jackpoll */
-       int err;
-       int old_interval = codec->jackpoll_interval;
-       codec->jackpoll_interval = msecs_to_jiffies(100);
-       err = snd_hda_gen_build_controls(codec);
-       codec->jackpoll_interval = old_interval;
-       return err;
-}
-
-static int vt1708_build_pcms(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int i, err;
-
-       err = snd_hda_gen_build_pcms(codec);
-       if (err < 0 || codec->core.vendor_id != 0x11061708)
-               return err;
-
-       /* We got noisy outputs on the right channel on VT1708 when
-        * 24bit samples are used.  Until any workaround is found,
-        * disable the 24bit format, so far.
-        */
-       for (i = 0; i < ARRAY_SIZE(spec->gen.pcm_rec); i++) {
-               struct hda_pcm *info = spec->gen.pcm_rec[i];
-               if (!info)
-                       continue;
-               if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams ||
-                   info->pcm_type != HDA_PCM_TYPE_AUDIO)
-                       continue;
-               info->stream[SNDRV_PCM_STREAM_PLAYBACK].formats =
-                       SNDRV_PCM_FMTBIT_S16_LE;
-       }
-
-       return 0;
-}
-
-static int patch_vt1708(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       /* override some patch_ops */
-       codec->patch_ops.build_controls = vt1708_build_controls;
-       codec->patch_ops.build_pcms = vt1708_build_pcms;
-       spec->gen.mixer_nid = 0x17;
-
-       /* set jackpoll_interval while parsing the codec */
-       codec->jackpoll_interval = msecs_to_jiffies(100);
-       spec->vt1708_jack_detect = 1;
-
-       /* don't support the input jack switching due to lack of unsol event */
-       /* (it may work with polling, though, but it needs testing) */
-       spec->gen.suppress_auto_mic = 1;
-       /* Some machines show the broken speaker mute */
-       spec->gen.auto_mute_via_amp = 1;
-
-       /* Add HP and CD pin config connect bit re-config action */
-       vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);
-       vt1708_set_pinconfig_connect(codec, VT1708_CD_PIN_NID);
-
-       err = snd_hda_add_verbs(codec, vt1708_init_verbs);
-       if (err < 0)
-               goto error;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       /* add jack detect on/off control */
-       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1708_jack_detect_ctl)) {
-               err = -ENOMEM;
-               goto error;
-       }
-
-       /* clear jackpoll_interval again; it's set dynamically */
-       codec->jackpoll_interval = 0;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-static int patch_vt1709(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x18;
-
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-static int patch_vt1708S(struct hda_codec *codec);
-static int patch_vt1708B(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       if (get_codec_type(codec) == VT1708BCE)
-               return patch_vt1708S(codec);
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x16;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-/* Patch for VT1708S */
-static const struct hda_verb vt1708S_init_verbs[] = {
-       /* Enable Mic Boost Volume backdoor */
-       {0x1, 0xf98, 0x1},
-       /* don't bybass mixer */
-       {0x1, 0xf88, 0xc0},
-       { }
-};
-
-static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin,
-                              int offset, int num_steps, int step_size)
-{
-       snd_hda_override_wcaps(codec, pin,
-                              get_wcaps(codec, pin) | AC_WCAP_IN_AMP);
-       snd_hda_override_amp_caps(codec, pin, HDA_INPUT,
-                                 (offset << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (0 << AC_AMPCAP_MUTE_SHIFT));
-}
-
-static int patch_vt1708S(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x16;
-       override_mic_boost(codec, 0x1a, 0, 3, 40);
-       override_mic_boost(codec, 0x1e, 0, 3, 40);
-
-       /* correct names for VT1708BCE */
-       if (get_codec_type(codec) == VT1708BCE)
-               snd_hda_codec_set_name(codec, "VT1708BCE");
-       /* correct names for VT1705 */
-       if (codec->core.vendor_id == 0x11064397)
-               snd_hda_codec_set_name(codec, "VT1705");
-
-       err = snd_hda_add_verbs(codec, vt1708S_init_verbs);
-       if (err < 0)
-               goto error;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-/* Patch for VT1702 */
-
-static const struct hda_verb vt1702_init_verbs[] = {
-       /* mixer enable */
-       {0x1, 0xF88, 0x3},
-       /* GPIO 0~2 */
-       {0x1, 0xF82, 0x3F},
-       { }
-};
-
-static int patch_vt1702(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x1a;
-
-       /* limit AA path volume to 0 dB */
-       snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT,
-                                 (0x17 << AC_AMPCAP_OFFSET_SHIFT) |
-                                 (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) |
-                                 (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) |
-                                 (1 << AC_AMPCAP_MUTE_SHIFT));
-
-       err = snd_hda_add_verbs(codec, vt1702_init_verbs);
-       if (err < 0)
-               goto error;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-/* Patch for VT1718S */
-
-static const struct hda_verb vt1718S_init_verbs[] = {
-       /* Enable MW0 adjust Gain 5 */
-       {0x1, 0xfb2, 0x10},
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xf88, 0x8},
-
-       { }
-};
-
-/* Add a connection to the primary DAC from AA-mixer for some codecs
- * This isn't listed from the raw info, but the chip has a secret connection.
- */
-static int add_secret_dac_path(struct hda_codec *codec)
-{
-       struct via_spec *spec = codec->spec;
-       int i, nums;
-       hda_nid_t conn[8];
-       hda_nid_t nid;
-
-       if (!spec->gen.mixer_nid)
-               return 0;
-       nums = snd_hda_get_connections(codec, spec->gen.mixer_nid, conn,
-                                      ARRAY_SIZE(conn) - 1);
-       if (nums < 0)
-               return nums;
-
-       for (i = 0; i < nums; i++) {
-               if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT)
-                       return 0;
-       }
-
-       /* find the primary DAC and add to the connection list */
-       for_each_hda_codec_node(nid, codec) {
-               unsigned int caps = get_wcaps(codec, nid);
-               if (get_wcaps_type(caps) == AC_WID_AUD_OUT &&
-                   !(caps & AC_WCAP_DIGITAL)) {
-                       conn[nums++] = nid;
-                       return snd_hda_override_conn_list(codec,
-                                                         spec->gen.mixer_nid,
-                                                         nums, conn);
-               }
-       }
-       return 0;
-}
-
-
-static int patch_vt1718S(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x21;
-       override_mic_boost(codec, 0x2b, 0, 3, 40);
-       override_mic_boost(codec, 0x29, 0, 3, 40);
-       add_secret_dac_path(codec);
-
-       err = snd_hda_add_verbs(codec, vt1718S_init_verbs);
-       if (err < 0)
-               goto error;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-/* Patch for VT1716S */
-
-static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol,
-                           struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
-}
-
-static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       int index = 0;
-
-       index = snd_hda_codec_read(codec, 0x26, 0,
-                                              AC_VERB_GET_CONNECT_SEL, 0);
-       if (index != -1)
-               *ucontrol->value.integer.value = index;
-
-       return 0;
-}
-
-static int vt1716s_dmic_put(struct snd_kcontrol *kcontrol,
-                          struct snd_ctl_elem_value *ucontrol)
-{
-       struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
-       struct via_spec *spec = codec->spec;
-       int index = *ucontrol->value.integer.value;
-
-       snd_hda_codec_write(codec, 0x26, 0,
-                                              AC_VERB_SET_CONNECT_SEL, index);
-       spec->dmic_enabled = index;
-       return 1;
-}
-
-static const struct snd_kcontrol_new vt1716s_dmic_mixer_vol =
-       HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT);
-static const struct snd_kcontrol_new vt1716s_dmic_mixer_sw = {
-        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-        .name = "Digital Mic Capture Switch",
-        .subdevice = HDA_SUBDEV_NID_FLAG | 0x26,
-        .count = 1,
-        .info = vt1716s_dmic_info,
-        .get = vt1716s_dmic_get,
-        .put = vt1716s_dmic_put,
-};
-
-
-/* mono-out mixer elements */
-static const struct snd_kcontrol_new vt1716S_mono_out_mixer =
-       HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT);
-
-static const struct hda_verb vt1716S_init_verbs[] = {
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xf8a, 0x80},
-       /* don't bybass mixer */
-       {0x1, 0xf88, 0xc0},
-       /* Enable mono output */
-       {0x1, 0xf90, 0x08},
-       { }
-};
-
-static int patch_vt1716S(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x16;
-       override_mic_boost(codec, 0x1a, 0, 3, 40);
-       override_mic_boost(codec, 0x1e, 0, 3, 40);
-
-       err = snd_hda_add_verbs(codec, vt1716S_init_verbs);
-       if (err < 0)
-               goto error;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_vol) ||
-           !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716s_dmic_mixer_sw) ||
-           !snd_hda_gen_add_kctl(&spec->gen, NULL, &vt1716S_mono_out_mixer)) {
-               err = -ENOMEM;
-               goto error;
-       }
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-/* for vt2002P */
-
-static const struct hda_verb vt2002P_init_verbs[] = {
-       /* Class-D speaker related verbs */
-       {0x1, 0xfe0, 0x4},
-       {0x1, 0xfe9, 0x80},
-       {0x1, 0xfe2, 0x22},
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xfb9, 0x24},
-       /* Enable AOW0 to MW9 */
-       {0x1, 0xfb8, 0x88},
-       { }
-};
-
-static const struct hda_verb vt1802_init_verbs[] = {
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xfb9, 0x24},
-       /* Enable AOW0 to MW9 */
-       {0x1, 0xfb8, 0x88},
-       { }
-};
-
-/*
- * pin fix-up
- */
-enum {
-       VIA_FIXUP_INTMIC_BOOST,
-       VIA_FIXUP_ASUS_G75,
-       VIA_FIXUP_POWER_SAVE,
-};
-
-static void via_fixup_intmic_boost(struct hda_codec *codec,
-                                 const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               override_mic_boost(codec, 0x30, 0, 2, 40);
-}
-
-static void via_fixup_power_save(struct hda_codec *codec,
-                                const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE)
-               codec->power_save_node = 0;
-}
-
-static const struct hda_fixup via_fixups[] = {
-       [VIA_FIXUP_INTMIC_BOOST] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = via_fixup_intmic_boost,
-       },
-       [VIA_FIXUP_ASUS_G75] = {
-               .type = HDA_FIXUP_PINS,
-               .v.pins = (const struct hda_pintbl[]) {
-                       /* set 0x24 and 0x33 as speakers */
-                       { 0x24, 0x991301f0 },
-                       { 0x33, 0x991301f1 }, /* subwoofer */
-                       { }
-               }
-       },
-       [VIA_FIXUP_POWER_SAVE] = {
-               .type = HDA_FIXUP_FUNC,
-               .v.func = via_fixup_power_save,
-       },
-};
-
-static const struct hda_quirk vt2002p_fixups[] = {
-       SND_PCI_QUIRK(0x1043, 0x13f7, "Asus B23E", VIA_FIXUP_POWER_SAVE),
-       SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75),
-       SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST),
-       SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", VIA_FIXUP_POWER_SAVE),
-       {}
-};
-
-/* NIDs 0x24 and 0x33 on VT1802 have connections to non-existing NID 0x3e
- * Replace this with mixer NID 0x1c
- */
-static void fix_vt1802_connections(struct hda_codec *codec)
-{
-       static const hda_nid_t conn_24[] = { 0x14, 0x1c };
-       static const hda_nid_t conn_33[] = { 0x1c };
-
-       snd_hda_override_conn_list(codec, 0x24, ARRAY_SIZE(conn_24), conn_24);
-       snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33);
-}
-
-/* patch for vt2002P */
-static int patch_vt2002P(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x21;
-       override_mic_boost(codec, 0x2b, 0, 3, 40);
-       override_mic_boost(codec, 0x29, 0, 3, 40);
-       if (spec->codec_type == VT1802)
-               fix_vt1802_connections(codec);
-       add_secret_dac_path(codec);
-
-       snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups);
-       snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE);
-
-       if (spec->codec_type == VT1802)
-               err = snd_hda_add_verbs(codec, vt1802_init_verbs);
-       else
-               err = snd_hda_add_verbs(codec, vt2002P_init_verbs);
-       if (err < 0)
-               goto error;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-/* for vt1812 */
-
-static const struct hda_verb vt1812_init_verbs[] = {
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xfb9, 0x24},
-       /* Enable AOW0 to MW9 */
-       {0x1, 0xfb8, 0xa8},
-       { }
-};
-
-/* patch for vt1812 */
-static int patch_vt1812(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x21;
-       override_mic_boost(codec, 0x2b, 0, 3, 40);
-       override_mic_boost(codec, 0x29, 0, 3, 40);
-       add_secret_dac_path(codec);
-
-       err = snd_hda_add_verbs(codec, vt1812_init_verbs);
-       if (err < 0)
-               goto error;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-/* patch for vt3476 */
-
-static const struct hda_verb vt3476_init_verbs[] = {
-       /* Enable DMic 8/16/32K */
-       {0x1, 0xF7B, 0x30},
-       /* Enable Boost Volume backdoor */
-       {0x1, 0xFB9, 0x20},
-       /* Enable AOW-MW9 path */
-       {0x1, 0xFB8, 0x10},
-       { }
-};
-
-static int patch_vt3476(struct hda_codec *codec)
-{
-       struct via_spec *spec;
-       int err;
-
-       /* create a codec specific record */
-       spec = via_new_spec(codec);
-       if (spec == NULL)
-               return -ENOMEM;
-
-       spec->gen.mixer_nid = 0x3f;
-       add_secret_dac_path(codec);
-
-       err = snd_hda_add_verbs(codec, vt3476_init_verbs);
-       if (err < 0)
-               goto error;
-
-       /* automatic parse from the BIOS config */
-       err = via_parse_auto_config(codec);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
- error:
-       via_free(codec);
-       return err;
-}
-
-/*
- * patch entries
- */
-static const struct hda_device_id snd_hda_id_via[] = {
-       HDA_CODEC_ENTRY(0x11061708, "VT1708", patch_vt1708),
-       HDA_CODEC_ENTRY(0x11061709, "VT1708", patch_vt1708),
-       HDA_CODEC_ENTRY(0x1106170a, "VT1708", patch_vt1708),
-       HDA_CODEC_ENTRY(0x1106170b, "VT1708", patch_vt1708),
-       HDA_CODEC_ENTRY(0x1106e710, "VT1709 10-Ch", patch_vt1709),
-       HDA_CODEC_ENTRY(0x1106e711, "VT1709 10-Ch", patch_vt1709),
-       HDA_CODEC_ENTRY(0x1106e712, "VT1709 10-Ch", patch_vt1709),
-       HDA_CODEC_ENTRY(0x1106e713, "VT1709 10-Ch", patch_vt1709),
-       HDA_CODEC_ENTRY(0x1106e714, "VT1709 6-Ch", patch_vt1709),
-       HDA_CODEC_ENTRY(0x1106e715, "VT1709 6-Ch", patch_vt1709),
-       HDA_CODEC_ENTRY(0x1106e716, "VT1709 6-Ch", patch_vt1709),
-       HDA_CODEC_ENTRY(0x1106e717, "VT1709 6-Ch", patch_vt1709),
-       HDA_CODEC_ENTRY(0x1106e720, "VT1708B 8-Ch", patch_vt1708B),
-       HDA_CODEC_ENTRY(0x1106e721, "VT1708B 8-Ch", patch_vt1708B),
-       HDA_CODEC_ENTRY(0x1106e722, "VT1708B 8-Ch", patch_vt1708B),
-       HDA_CODEC_ENTRY(0x1106e723, "VT1708B 8-Ch", patch_vt1708B),
-       HDA_CODEC_ENTRY(0x1106e724, "VT1708B 4-Ch", patch_vt1708B),
-       HDA_CODEC_ENTRY(0x1106e725, "VT1708B 4-Ch", patch_vt1708B),
-       HDA_CODEC_ENTRY(0x1106e726, "VT1708B 4-Ch", patch_vt1708B),
-       HDA_CODEC_ENTRY(0x1106e727, "VT1708B 4-Ch", patch_vt1708B),
-       HDA_CODEC_ENTRY(0x11060397, "VT1708S", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11061397, "VT1708S", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11062397, "VT1708S", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11063397, "VT1708S", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11064397, "VT1705", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11065397, "VT1708S", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11066397, "VT1708S", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11067397, "VT1708S", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11060398, "VT1702", patch_vt1702),
-       HDA_CODEC_ENTRY(0x11061398, "VT1702", patch_vt1702),
-       HDA_CODEC_ENTRY(0x11062398, "VT1702", patch_vt1702),
-       HDA_CODEC_ENTRY(0x11063398, "VT1702", patch_vt1702),
-       HDA_CODEC_ENTRY(0x11064398, "VT1702", patch_vt1702),
-       HDA_CODEC_ENTRY(0x11065398, "VT1702", patch_vt1702),
-       HDA_CODEC_ENTRY(0x11066398, "VT1702", patch_vt1702),
-       HDA_CODEC_ENTRY(0x11067398, "VT1702", patch_vt1702),
-       HDA_CODEC_ENTRY(0x11060428, "VT1718S", patch_vt1718S),
-       HDA_CODEC_ENTRY(0x11064428, "VT1718S", patch_vt1718S),
-       HDA_CODEC_ENTRY(0x11060441, "VT2020", patch_vt1718S),
-       HDA_CODEC_ENTRY(0x11064441, "VT1828S", patch_vt1718S),
-       HDA_CODEC_ENTRY(0x11060433, "VT1716S", patch_vt1716S),
-       HDA_CODEC_ENTRY(0x1106a721, "VT1716S", patch_vt1716S),
-       HDA_CODEC_ENTRY(0x11060438, "VT2002P", patch_vt2002P),
-       HDA_CODEC_ENTRY(0x11064438, "VT2002P", patch_vt2002P),
-       HDA_CODEC_ENTRY(0x11060448, "VT1812", patch_vt1812),
-       HDA_CODEC_ENTRY(0x11060440, "VT1818S", patch_vt1708S),
-       HDA_CODEC_ENTRY(0x11060446, "VT1802", patch_vt2002P),
-       HDA_CODEC_ENTRY(0x11068446, "VT1802", patch_vt2002P),
-       HDA_CODEC_ENTRY(0x11064760, "VT1705CF", patch_vt3476),
-       HDA_CODEC_ENTRY(0x11064761, "VT1708SCE", patch_vt3476),
-       HDA_CODEC_ENTRY(0x11064762, "VT1808", patch_vt3476),
-       {} /* terminator */
-};
-MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_via);
-
-static struct hda_codec_driver via_driver = {
-       .id = snd_hda_id_via,
-};
-
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("VIA HD-audio codec");
-
-module_hda_codec_driver(via_driver);
diff --git a/sound/pci/hda/tas2781_hda.c b/sound/pci/hda/tas2781_hda.c
deleted file mode 100644 (file)
index 34217ce..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// TAS2781 HDA Shared Lib for I2C&SPI driver
-//
-// Copyright 2025 Texas Instruments, Inc.
-//
-// Author: Shenghao Ding <shenghao-ding@ti.com>
-
-#include <linux/component.h>
-#include <linux/crc8.h>
-#include <linux/crc32.h>
-#include <linux/efi.h>
-#include <linux/firmware.h>
-#include <linux/i2c.h>
-#include <linux/pm_runtime.h>
-#include <sound/soc.h>
-#include <sound/tas2781.h>
-
-#include "tas2781_hda.h"
-
-const efi_guid_t tasdev_fct_efi_guid[] = {
-       /* DELL */
-       EFI_GUID(0xcc92382d, 0x6337, 0x41cb, 0xa8, 0x8b, 0x8e, 0xce, 0x74,
-               0x91, 0xea, 0x9f),
-       /* HP */
-       EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a,
-               0xa3, 0x5d, 0xb3),
-       /* LENOVO & OTHERS */
-       EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, 0x43, 0xa3, 0xf4,
-               0x31, 0x0a, 0x92),
-};
-EXPORT_SYMBOL_NS_GPL(tasdev_fct_efi_guid, "SND_HDA_SCODEC_TAS2781");
-
-static void tas2781_apply_calib(struct tasdevice_priv *p)
-{
-       struct calidata *cali_data = &p->cali_data;
-       struct cali_reg *r = &cali_data->cali_reg_array;
-       unsigned char *data = cali_data->data;
-       unsigned int *tmp_val = (unsigned int *)data;
-       unsigned int cali_reg[TASDEV_CALIB_N] = {
-               TASDEVICE_REG(0, 0x17, 0x74),
-               TASDEVICE_REG(0, 0x18, 0x0c),
-               TASDEVICE_REG(0, 0x18, 0x14),
-               TASDEVICE_REG(0, 0x13, 0x70),
-               TASDEVICE_REG(0, 0x18, 0x7c),
-       };
-       unsigned int crc, oft, node_num;
-       unsigned char *buf;
-       int i, j, k, l;
-
-       if (tmp_val[0] == 2781) {
-               /*
-                * New features were added in calibrated Data V3:
-                *     1. Added calibration registers address define in
-                *          a node, marked as Device id == 0x80.
-                * New features were added in calibrated Data V2:
-                *     1. Added some the fields to store the link_id and
-                *          uniqie_id for multi-link solutions
-                *     2. Support flexible number of devices instead of
-                *          fixed one in V1.
-                * Layout of calibrated data V2 in UEFI(total 256 bytes):
-                *     ChipID (2781, 4 bytes)
-                *     Data-Group-Sum (4 bytes)
-                *     TimeStamp of Calibration (4 bytes)
-                *     for (i = 0; i < Data-Group-Sum; i++) {
-                *          if (Data type != 0x80) (4 bytes)
-                *               Calibrated Data of Device #i (20 bytes)
-                *          else
-                *               Calibration registers address (5*4 = 20 bytes)
-                *               # V2: No reg addr in data grp section.
-                *               # V3: Normally the last grp is the reg addr.
-                *     }
-                *     CRC (4 bytes)
-                *     Reserved (the rest)
-                */
-               crc = crc32(~0, data, (3 + tmp_val[1] * 6) * 4) ^ ~0;
-
-               if (crc != tmp_val[3 + tmp_val[1] * 6]) {
-                       cali_data->total_sz = 0;
-                       dev_err(p->dev, "%s: CRC error\n", __func__);
-                       return;
-               }
-               node_num = tmp_val[1];
-
-               for (j = 0, k = 0; j < node_num; j++) {
-                       oft = j * 6 + 3;
-                       if (tmp_val[oft] == TASDEV_UEFI_CALI_REG_ADDR_FLG) {
-                               for (i = 0; i < TASDEV_CALIB_N; i++) {
-                                       buf = &data[(oft + i + 1) * 4];
-                                       cali_reg[i] = TASDEVICE_REG(buf[1],
-                                               buf[2], buf[3]);
-                               }
-                       } else {
-                               l = j * (cali_data->cali_dat_sz_per_dev + 1);
-                               if (k >= p->ndev || l > oft * 4) {
-                                       dev_err(p->dev, "%s: dev sum error\n",
-                                               __func__);
-                                       cali_data->total_sz = 0;
-                                       return;
-                               }
-
-                               data[l] = k;
-                               oft++;
-                               for (i = 0; i < TASDEV_CALIB_N * 4; i++)
-                                       data[l + i + 1] = data[4 * oft + i];
-                               k++;
-                       }
-               }
-       } else {
-               /*
-                * Calibration data is in V1 format.
-                * struct cali_data {
-                *     char cali_data[20];
-                * }
-                *
-                * struct {
-                *     struct cali_data cali_data[4];
-                *     int  TimeStamp of Calibration (4 bytes)
-                *     int CRC (4 bytes)
-                * } ueft;
-                */
-               crc = crc32(~0, data, 84) ^ ~0;
-               if (crc != tmp_val[21]) {
-                       cali_data->total_sz = 0;
-                       dev_err(p->dev, "%s: V1 CRC error\n", __func__);
-                       return;
-               }
-
-               for (j = p->ndev - 1; j >= 0; j--) {
-                       l = j * (cali_data->cali_dat_sz_per_dev + 1);
-                       for (i = TASDEV_CALIB_N * 4; i > 0 ; i--)
-                               data[l + i] = data[p->index * 5 + i];
-                       data[l+i] = j;
-               }
-       }
-
-       if (p->dspbin_typ == TASDEV_BASIC) {
-               r->r0_reg = cali_reg[0];
-               r->invr0_reg = cali_reg[1];
-               r->r0_low_reg = cali_reg[2];
-               r->pow_reg = cali_reg[3];
-               r->tlimit_reg = cali_reg[4];
-       }
-
-       p->is_user_space_calidata = true;
-       cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
-}
-
-/*
- * Update the calibration data, including speaker impedance, f0, etc,
- * into algo. Calibrate data is done by manufacturer in the factory.
- * The data is used by Algo for calculating the speaker temperature,
- * speaker membrane excursion and f0 in real time during playback.
- * Calibration data format in EFI is V2, since 2024.
- */
-int tas2781_save_calibration(struct tas2781_hda *hda)
-{
-       /*
-        * GUID was used for data access in BIOS, it was provided by board
-        * manufactory.
-        */
-       efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
-       static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME;
-       struct tasdevice_priv *p = hda->priv;
-       struct calidata *cali_data = &p->cali_data;
-       unsigned long total_sz = 0;
-       unsigned int attr, size;
-       unsigned char *data;
-       efi_status_t status;
-
-       if (hda->catlog_id < LENOVO)
-               efi_guid = tasdev_fct_efi_guid[hda->catlog_id];
-
-       cali_data->cali_dat_sz_per_dev = 20;
-       size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
-       /* Get real size of UEFI variable */
-       status = efi.get_variable(efi_name, &efi_guid, &attr, &total_sz, NULL);
-       cali_data->total_sz = total_sz > size ? total_sz : size;
-       if (status == EFI_BUFFER_TOO_SMALL) {
-               /* Allocate data buffer of data_size bytes */
-               data = p->cali_data.data = devm_kzalloc(p->dev,
-                       p->cali_data.total_sz, GFP_KERNEL);
-               if (!data) {
-                       p->cali_data.total_sz = 0;
-                       return -ENOMEM;
-               }
-               /* Get variable contents into buffer */
-               status = efi.get_variable(efi_name, &efi_guid, &attr,
-                       &p->cali_data.total_sz, data);
-       }
-       if (status != EFI_SUCCESS) {
-               p->cali_data.total_sz = 0;
-               return status;
-       }
-
-       tas2781_apply_calib(p);
-
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781");
-
-void tas2781_hda_remove(struct device *dev,
-       const struct component_ops *ops)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-
-       component_del(tas_hda->dev, ops);
-
-       pm_runtime_get_sync(tas_hda->dev);
-       pm_runtime_disable(tas_hda->dev);
-
-       pm_runtime_put_noidle(tas_hda->dev);
-
-       tasdevice_remove(tas_hda->priv);
-}
-EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
-
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
-
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_info_config(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct tasdevice_fw *tas_fw = tas_priv->fmw;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_fw->nr_configurations - 1;
-
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
-               kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
-
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       int profile_id = ucontrol->value.integer.value[0];
-       int max = tas_priv->rcabin.ncfgs - 1;
-       int val, ret = 0;
-
-       val = clamp(profile_id, 0, max);
-
-       guard(mutex)(&tas_priv->codec_lock);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
-               kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
-
-       if (tas_priv->rcabin.profile_cfg_id != val) {
-               tas_priv->rcabin.profile_cfg_id = val;
-               ret = 1;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_program_get(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = tas_priv->cur_prog;
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
-               kcontrol->id.name, tas_priv->cur_prog);
-
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_program_put(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct tasdevice_fw *tas_fw = tas_priv->fmw;
-       int nr_program = ucontrol->value.integer.value[0];
-       int max = tas_fw->nr_programs - 1;
-       int val, ret = 0;
-
-       val = clamp(nr_program, 0, max);
-
-       guard(mutex)(&tas_priv->codec_lock);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
-               kcontrol->id.name, tas_priv->cur_prog, val);
-
-       if (tas_priv->cur_prog != val) {
-               tas_priv->cur_prog = val;
-               ret = 1;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_config_get(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = tas_priv->cur_conf;
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
-               kcontrol->id.name, tas_priv->cur_conf);
-
-       return 0;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
-
-int tasdevice_config_put(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct tasdevice_fw *tas_fw = tas_priv->fmw;
-       int nr_config = ucontrol->value.integer.value[0];
-       int max = tas_fw->nr_configurations - 1;
-       int val, ret = 0;
-
-       val = clamp(nr_config, 0, max);
-
-       guard(mutex)(&tas_priv->codec_lock);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
-               kcontrol->id.name, tas_priv->cur_conf, val);
-
-       if (tas_priv->cur_conf != val) {
-               tas_priv->cur_conf = val;
-               ret = 1;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
-
-MODULE_DESCRIPTION("TAS2781 HDA Driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
diff --git a/sound/pci/hda/tas2781_hda.h b/sound/pci/hda/tas2781_hda.h
deleted file mode 100644 (file)
index 575a701..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only
- *
- * HDA audio driver for Texas Instruments TAS2781 smart amp
- *
- * Copyright (C) 2025 Texas Instruments, Inc.
- */
-#ifndef __TAS2781_HDA_H__
-#define __TAS2781_HDA_H__
-
-#include <sound/asound.h>
-
-/* Flag of calibration registers address. */
-#define TASDEV_UEFI_CALI_REG_ADDR_FLG  BIT(7)
-#define TASDEVICE_CALIBRATION_DATA_NAME        L"CALI_DATA"
-#define TASDEV_CALIB_N                 5
-
-/*
- * No standard control callbacks for SNDRV_CTL_ELEM_IFACE_CARD
- * Define two controls, one is Volume control callbacks, the other is
- * flag setting control callbacks.
- */
-
-/* Volume control callbacks for tas2781 */
-#define ACARD_SINGLE_RANGE_EXT_TLV(xname, xreg, xshift, xmin, xmax, xinvert, \
-       xhandler_get, xhandler_put, tlv_array) { \
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = (xname), \
-       .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
-               SNDRV_CTL_ELEM_ACCESS_READWRITE, \
-       .tlv.p = (tlv_array), \
-       .info = snd_soc_info_volsw, \
-       .get = xhandler_get, .put = xhandler_put, \
-       .private_value = (unsigned long)&(struct soc_mixer_control) { \
-               .reg = xreg, .rreg = xreg, \
-               .shift = xshift, .rshift = xshift,\
-               .min = xmin, .max = xmax, .invert = xinvert, \
-       } \
-}
-
-/* Flag control callbacks for tas2781 */
-#define ACARD_SINGLE_BOOL_EXT(xname, xdata, xhandler_get, xhandler_put) { \
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD, \
-       .name = xname, \
-       .info = snd_ctl_boolean_mono_info, \
-       .get = xhandler_get, \
-       .put = xhandler_put, \
-       .private_value = xdata, \
-}
-
-enum device_catlog_id {
-       DELL = 0,
-       HP,
-       LENOVO,
-       OTHERS
-};
-
-struct tas2781_hda {
-       struct device *dev;
-       struct tasdevice_priv *priv;
-       struct snd_kcontrol *dsp_prog_ctl;
-       struct snd_kcontrol *dsp_conf_ctl;
-       struct snd_kcontrol *prof_ctl;
-       enum device_catlog_id catlog_id;
-       void *hda_priv;
-};
-
-extern const efi_guid_t tasdev_fct_efi_guid[];
-
-int tas2781_save_calibration(struct tas2781_hda *p);
-void tas2781_hda_remove(struct device *dev,
-       const struct component_ops *ops);
-int tasdevice_info_profile(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_info *uctl);
-int tasdevice_info_programs(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_info *uctl);
-int tasdevice_info_config(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_info *uctl);
-int tasdevice_set_profile_id(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_value *uctl);
-int tasdevice_get_profile_id(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_value *uctl);
-int tasdevice_program_get(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_value *uctl);
-int tasdevice_program_put(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_value *uctl);
-int tasdevice_config_put(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_value *uctl);
-int tasdevice_config_get(struct snd_kcontrol *kctl,
-       struct snd_ctl_elem_value *uctl);
-
-#endif
diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c
deleted file mode 100644 (file)
index b7ee228..0000000
+++ /dev/null
@@ -1,751 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// TAS2781 HDA I2C driver
-//
-// Copyright 2023 - 2025 Texas Instruments, Inc.
-//
-// Author: Shenghao Ding <shenghao-ding@ti.com>
-// Current maintainer: Baojun Xu <baojun.xu@ti.com>
-
-#include <linux/unaligned.h>
-#include <linux/acpi.h>
-#include <linux/crc8.h>
-#include <linux/crc32.h>
-#include <linux/efi.h>
-#include <linux/firmware.h>
-#include <linux/i2c.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/pci_ids.h>
-#include <linux/pm_runtime.h>
-#include <linux/regmap.h>
-#include <sound/hda_codec.h>
-#include <sound/soc.h>
-#include <sound/tas2781.h>
-#include <sound/tas2781-comlib-i2c.h>
-#include <sound/tlv.h>
-#include <sound/tas2781-tlv.h>
-
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_component.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-#include "tas2781_hda.h"
-
-#define TAS2563_CAL_VAR_NAME_MAX       16
-#define TAS2563_CAL_ARRAY_SIZE         80
-#define TAS2563_CAL_DATA_SIZE          4
-#define TAS2563_MAX_CHANNELS           4
-#define TAS2563_CAL_CH_SIZE            20
-
-#define TAS2563_CAL_R0_LOW             TASDEVICE_REG(0, 0x0f, 0x48)
-#define TAS2563_CAL_POWER              TASDEVICE_REG(0, 0x0d, 0x3c)
-#define TAS2563_CAL_INVR0              TASDEVICE_REG(0, 0x0f, 0x40)
-#define TAS2563_CAL_TLIM               TASDEVICE_REG(0, 0x10, 0x14)
-#define TAS2563_CAL_R0                 TASDEVICE_REG(0, 0x0f, 0x34)
-
-struct tas2781_hda_i2c_priv {
-       struct snd_kcontrol *snd_ctls[2];
-       int (*save_calibration)(struct tas2781_hda *h);
-};
-
-static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data)
-{
-       struct tasdevice_priv *tas_priv = data;
-       struct acpi_resource_i2c_serialbus *sb;
-
-       if (i2c_acpi_get_i2c_resource(ares, &sb)) {
-               if (tas_priv->ndev < TASDEVICE_MAX_CHANNELS &&
-                       sb->slave_address != tas_priv->global_addr) {
-                       tas_priv->tasdevice[tas_priv->ndev].dev_addr =
-                               (unsigned int)sb->slave_address;
-                       tas_priv->ndev++;
-               }
-       }
-       return 1;
-}
-
-static const struct acpi_gpio_params speakerid_gpios = { 0, 0, false };
-
-static const struct acpi_gpio_mapping tas2781_speaker_id_gpios[] = {
-       { "speakerid-gpios", &speakerid_gpios, 1 },
-       { }
-};
-
-static int tas2781_read_acpi(struct tasdevice_priv *p, const char *hid)
-{
-       struct acpi_device *adev;
-       struct device *physdev;
-       LIST_HEAD(resources);
-       const char *sub;
-       uint32_t subid;
-       int ret;
-
-       adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
-       if (!adev) {
-               dev_err(p->dev,
-                       "Failed to find an ACPI device for %s\n", hid);
-               return -ENODEV;
-       }
-
-       physdev = get_device(acpi_get_first_physical_node(adev));
-       ret = acpi_dev_get_resources(adev, &resources, tas2781_get_i2c_res, p);
-       if (ret < 0) {
-               dev_err(p->dev, "Failed to get ACPI resource.\n");
-               goto err;
-       }
-       sub = acpi_get_subsystem_id(ACPI_HANDLE(physdev));
-       if (IS_ERR(sub)) {
-               /* No subsys id in older tas2563 projects. */
-               if (!strncmp(hid, "INT8866", sizeof("INT8866")))
-                       goto end_2563;
-               dev_err(p->dev, "Failed to get SUBSYS ID.\n");
-               ret = PTR_ERR(sub);
-               goto err;
-       }
-       /* Speaker id was needed for ASUS projects. */
-       ret = kstrtou32(sub, 16, &subid);
-       if (!ret && upper_16_bits(subid) == PCI_VENDOR_ID_ASUSTEK) {
-               ret = devm_acpi_dev_add_driver_gpios(p->dev,
-                       tas2781_speaker_id_gpios);
-               if (ret < 0)
-                       dev_err(p->dev, "Failed to add driver gpio %d.\n",
-                               ret);
-               p->speaker_id = devm_gpiod_get(p->dev, "speakerid", GPIOD_IN);
-               if (IS_ERR(p->speaker_id)) {
-                       dev_err(p->dev, "Failed to get Speaker id.\n");
-                       ret = PTR_ERR(p->speaker_id);
-                       goto err;
-               }
-       } else {
-               p->speaker_id = NULL;
-       }
-
-end_2563:
-       acpi_dev_free_resource_list(&resources);
-       strscpy(p->dev_name, hid, sizeof(p->dev_name));
-       put_device(physdev);
-       acpi_dev_put(adev);
-
-       return 0;
-
-err:
-       dev_err(p->dev, "read acpi error, ret: %d\n", ret);
-       put_device(physdev);
-       acpi_dev_put(adev);
-
-       return ret;
-}
-
-static void tas2781_hda_playback_hook(struct device *dev, int action)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-
-       dev_dbg(tas_hda->dev, "%s: action = %d\n", __func__, action);
-       switch (action) {
-       case HDA_GEN_PCM_ACT_OPEN:
-               pm_runtime_get_sync(dev);
-               mutex_lock(&tas_hda->priv->codec_lock);
-               tasdevice_tuning_switch(tas_hda->priv, 0);
-               tas_hda->priv->playback_started = true;
-               mutex_unlock(&tas_hda->priv->codec_lock);
-               break;
-       case HDA_GEN_PCM_ACT_CLOSE:
-               mutex_lock(&tas_hda->priv->codec_lock);
-               tasdevice_tuning_switch(tas_hda->priv, 1);
-               tas_hda->priv->playback_started = false;
-               mutex_unlock(&tas_hda->priv->codec_lock);
-
-               pm_runtime_put_autosuspend(dev);
-               break;
-       default:
-               break;
-       }
-}
-
-static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       int ret;
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       ret = tasdevice_amp_getvol(tas_priv, ucontrol, mc);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %ld\n",
-               __func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return ret;
-}
-
-static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-       int ret;
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: -> %ld\n",
-               __func__, kcontrol->id.name, ucontrol->value.integer.value[0]);
-
-       /* The check of the given value is in tasdevice_amp_putvol. */
-       ret = tasdevice_amp_putvol(tas_priv, ucontrol, mc);
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return ret;
-}
-
-static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
-               __func__, kcontrol->id.name, tas_priv->force_fwload_status);
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return 0;
-}
-
-static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       bool change, val = (bool)ucontrol->value.integer.value[0];
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
-               __func__, kcontrol->id.name,
-               tas_priv->force_fwload_status, val);
-
-       if (tas_priv->force_fwload_status == val)
-               change = false;
-       else {
-               change = true;
-               tas_priv->force_fwload_status = val;
-       }
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return change;
-}
-
-static const struct snd_kcontrol_new tas2781_snd_controls[] = {
-       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL,
-               1, 0, 20, 0, tas2781_amp_getvol,
-               tas2781_amp_putvol, amp_vol_tlv),
-       ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
-               tas2781_force_fwload_get, tas2781_force_fwload_put),
-};
-
-static const struct snd_kcontrol_new tas2781_prof_ctrl = {
-       .name = "Speaker Profile Id",
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_profile,
-       .get = tasdevice_get_profile_id,
-       .put = tasdevice_set_profile_id,
-};
-
-static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = {
-       .name = "Speaker Program Id",
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_programs,
-       .get = tasdevice_program_get,
-       .put = tasdevice_program_put,
-};
-
-static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = {
-       .name = "Speaker Config Id",
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_config,
-       .get = tasdevice_config_get,
-       .put = tasdevice_config_put,
-};
-
-static int tas2563_save_calibration(struct tas2781_hda *h)
-{
-       efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
-       char *vars[TASDEV_CALIB_N] = {
-               "R0_%d", "InvR0_%d", "R0_Low_%d", "Power_%d", "TLim_%d"
-       };
-       efi_char16_t efi_name[TAS2563_CAL_VAR_NAME_MAX];
-       unsigned long max_size = TAS2563_CAL_DATA_SIZE;
-       unsigned char var8[TAS2563_CAL_VAR_NAME_MAX];
-       struct tasdevice_priv *p = h->hda_priv;
-       struct calidata *cd = &p->cali_data;
-       struct cali_reg *r = &cd->cali_reg_array;
-       unsigned int offset = 0;
-       unsigned char *data;
-       efi_status_t status;
-       unsigned int attr;
-       int ret, i, j, k;
-
-       cd->cali_dat_sz_per_dev = TAS2563_CAL_DATA_SIZE * TASDEV_CALIB_N;
-
-       /* extra byte for each device is the device number */
-       cd->total_sz = (cd->cali_dat_sz_per_dev + 1) * p->ndev;
-       data = cd->data = devm_kzalloc(p->dev, cd->total_sz,
-               GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       for (i = 0; i < p->ndev; ++i) {
-               data[offset] = i;
-               offset++;
-               for (j = 0; j < TASDEV_CALIB_N; ++j) {
-                       ret = snprintf(var8, sizeof(var8), vars[j], i);
-
-                       if (ret < 0 || ret >= sizeof(var8) - 1) {
-                               dev_err(p->dev, "%s: Read %s failed\n",
-                                       __func__, var8);
-                               return -EINVAL;
-                       }
-                       /*
-                        * Our variable names are ASCII by construction, but
-                        * EFI names are wide chars.  Convert and zero-pad.
-                        */
-                       memset(efi_name, 0, sizeof(efi_name));
-                       for (k = 0; k < sizeof(var8) && var8[k]; k++)
-                               efi_name[k] = var8[k];
-                       status = efi.get_variable(efi_name,
-                               &efi_guid, &attr, &max_size,
-                               &data[offset]);
-                       if (status != EFI_SUCCESS ||
-                               max_size != TAS2563_CAL_DATA_SIZE) {
-                               dev_warn(p->dev,
-                                       "Dev %d: Caldat[%d] read failed %ld\n",
-                                       i, j, status);
-                               return -EINVAL;
-                       }
-                       offset += TAS2563_CAL_DATA_SIZE;
-               }
-       }
-
-       if (cd->total_sz != offset) {
-               dev_err(p->dev, "%s: tot_size(%lu) and offset(%u) dismatch\n",
-                       __func__, cd->total_sz, offset);
-               return -EINVAL;
-       }
-
-       r->r0_reg = TAS2563_CAL_R0;
-       r->invr0_reg = TAS2563_CAL_INVR0;
-       r->r0_low_reg = TAS2563_CAL_R0_LOW;
-       r->pow_reg = TAS2563_CAL_POWER;
-       r->tlimit_reg = TAS2563_CAL_TLIM;
-
-       /*
-        * TAS2781_FMWLIB supports two solutions of calibrated data. One is
-        * from the driver itself: driver reads the calibrated files directly
-        * during probe; The other from user space: during init of audio hal,
-        * the audio hal will pass the calibrated data via kcontrol interface.
-        * Driver will store this data in "struct calidata" for use. For hda
-        * device, calibrated data are usunally saved into UEFI. So Hda side
-        * codec driver use the mixture of these two solutions, driver reads
-        * the data from UEFI, then store this data in "struct calidata" for
-        * use.
-        */
-       p->is_user_space_calidata = true;
-
-       return 0;
-}
-
-static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
-{
-       struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
-       struct hda_codec *codec = tas_hda->priv->codec;
-
-       snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
-       snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
-
-       for (int i = ARRAY_SIZE(hda_priv->snd_ctls) - 1; i >= 0; i--)
-               snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]);
-
-       snd_ctl_remove(codec->card, tas_hda->prof_ctl);
-}
-
-static void tasdev_fw_ready(const struct firmware *fmw, void *context)
-{
-       struct tasdevice_priv *tas_priv = context;
-       struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
-       struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
-       struct hda_codec *codec = tas_priv->codec;
-       int i, ret, spk_id;
-
-       pm_runtime_get_sync(tas_priv->dev);
-       mutex_lock(&tas_priv->codec_lock);
-
-       ret = tasdevice_rca_parser(tas_priv, fmw);
-       if (ret)
-               goto out;
-
-       tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl, tas_priv);
-       ret = snd_ctl_add(codec->card, tas_hda->prof_ctl);
-       if (ret) {
-               dev_err(tas_priv->dev,
-                       "Failed to add KControl %s = %d\n",
-                       tas2781_prof_ctrl.name, ret);
-               goto out;
-       }
-
-       for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) {
-               hda_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i],
-                       tas_priv);
-               ret = snd_ctl_add(codec->card, hda_priv->snd_ctls[i]);
-               if (ret) {
-                       dev_err(tas_priv->dev,
-                               "Failed to add KControl %s = %d\n",
-                               tas2781_snd_controls[i].name, ret);
-                       goto out;
-               }
-       }
-
-       tasdevice_dsp_remove(tas_priv);
-
-       tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
-       if (tas_priv->speaker_id != NULL) {
-               // Speaker id need to be checked for ASUS only.
-               spk_id = gpiod_get_value(tas_priv->speaker_id);
-               if (spk_id < 0) {
-                       // Speaker id is not valid, use default.
-                       dev_dbg(tas_priv->dev, "Wrong spk_id = %d\n", spk_id);
-                       spk_id = 0;
-               }
-               snprintf(tas_priv->coef_binaryname,
-                         sizeof(tas_priv->coef_binaryname),
-                         "TAS2XXX%04X%d.bin",
-                         lower_16_bits(codec->core.subsystem_id),
-                         spk_id);
-       } else {
-               snprintf(tas_priv->coef_binaryname,
-                         sizeof(tas_priv->coef_binaryname),
-                         "TAS2XXX%04X.bin",
-                         lower_16_bits(codec->core.subsystem_id));
-       }
-       ret = tasdevice_dsp_parser(tas_priv);
-       if (ret) {
-               dev_err(tas_priv->dev, "dspfw load %s error\n",
-                       tas_priv->coef_binaryname);
-               tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
-               goto out;
-       }
-
-       tas_hda->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_prog_ctrl,
-               tas_priv);
-       ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl);
-       if (ret) {
-               dev_err(tas_priv->dev,
-                       "Failed to add KControl %s = %d\n",
-                       tas2781_dsp_prog_ctrl.name, ret);
-               goto out;
-       }
-
-       tas_hda->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_conf_ctrl,
-               tas_priv);
-       ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl);
-       if (ret) {
-               dev_err(tas_priv->dev,
-                       "Failed to add KControl %s = %d\n",
-                       tas2781_dsp_conf_ctrl.name, ret);
-               goto out;
-       }
-
-       tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
-       tasdevice_prmg_load(tas_priv, 0);
-       if (tas_priv->fmw->nr_programs > 0)
-               tas_priv->cur_prog = 0;
-       if (tas_priv->fmw->nr_configurations > 0)
-               tas_priv->cur_conf = 0;
-
-       /* If calibrated data occurs error, dsp will still works with default
-        * calibrated data inside algo.
-        */
-       hda_priv->save_calibration(tas_hda);
-
-       tasdevice_tuning_switch(tas_hda->priv, 0);
-       tas_hda->priv->playback_started = true;
-
-out:
-       mutex_unlock(&tas_hda->priv->codec_lock);
-       release_firmware(fmw);
-       pm_runtime_put_autosuspend(tas_hda->dev);
-}
-
-static int tas2781_hda_bind(struct device *dev, struct device *master,
-       void *master_data)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct hda_component_parent *parent = master_data;
-       struct hda_component *comp;
-       struct hda_codec *codec;
-       unsigned int subid;
-       int ret;
-
-       comp = hda_component_from_index(parent, tas_hda->priv->index);
-       if (!comp)
-               return -EINVAL;
-
-       if (comp->dev)
-               return -EBUSY;
-
-       codec = parent->codec;
-       subid = codec->core.subsystem_id >> 16;
-
-       switch (subid) {
-       case 0x1028:
-               tas_hda->catlog_id = DELL;
-               break;
-       default:
-               tas_hda->catlog_id = LENOVO;
-               break;
-       }
-
-       pm_runtime_get_sync(dev);
-
-       comp->dev = dev;
-
-       strscpy(comp->name, dev_name(dev), sizeof(comp->name));
-
-       ret = tascodec_init(tas_hda->priv, codec, THIS_MODULE, tasdev_fw_ready);
-       if (!ret)
-               comp->playback_hook = tas2781_hda_playback_hook;
-
-       pm_runtime_put_autosuspend(dev);
-
-       return ret;
-}
-
-static void tas2781_hda_unbind(struct device *dev,
-       struct device *master, void *master_data)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct hda_component_parent *parent = master_data;
-       struct hda_component *comp;
-
-       comp = hda_component_from_index(parent, tas_hda->priv->index);
-       if (comp && (comp->dev == dev)) {
-               comp->dev = NULL;
-               memset(comp->name, 0, sizeof(comp->name));
-               comp->playback_hook = NULL;
-       }
-
-       tas2781_hda_remove_controls(tas_hda);
-
-       tasdevice_config_info_remove(tas_hda->priv);
-       tasdevice_dsp_remove(tas_hda->priv);
-
-       tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING;
-}
-
-static const struct component_ops tas2781_hda_comp_ops = {
-       .bind = tas2781_hda_bind,
-       .unbind = tas2781_hda_unbind,
-};
-
-static int tas2781_hda_i2c_probe(struct i2c_client *clt)
-{
-       struct tas2781_hda_i2c_priv *hda_priv;
-       struct tas2781_hda *tas_hda;
-       const char *device_name;
-       int ret;
-
-       tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL);
-       if (!tas_hda)
-               return -ENOMEM;
-
-       hda_priv = devm_kzalloc(&clt->dev, sizeof(*hda_priv), GFP_KERNEL);
-       if (!hda_priv)
-               return -ENOMEM;
-
-       tas_hda->hda_priv = hda_priv;
-
-       dev_set_drvdata(&clt->dev, tas_hda);
-       tas_hda->dev = &clt->dev;
-
-       tas_hda->priv = tasdevice_kzalloc(clt);
-       if (!tas_hda->priv)
-               return -ENOMEM;
-
-       if (strstr(dev_name(&clt->dev), "TIAS2781")) {
-               device_name = "TIAS2781";
-               hda_priv->save_calibration = tas2781_save_calibration;
-               tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
-       } else if (strstarts(dev_name(&clt->dev),
-                            "i2c-TXNW2781:00-tas2781-hda.0")) {
-               device_name = "TXNW2781";
-               hda_priv->save_calibration = tas2781_save_calibration;
-               tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
-       } else if (strstr(dev_name(&clt->dev), "INT8866")) {
-               device_name = "INT8866";
-               hda_priv->save_calibration = tas2563_save_calibration;
-               tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
-       } else {
-               return -ENODEV;
-       }
-
-       tas_hda->priv->irq = clt->irq;
-       ret = tas2781_read_acpi(tas_hda->priv, device_name);
-       if (ret)
-               return dev_err_probe(tas_hda->dev, ret,
-                       "Platform not supported\n");
-
-       ret = tasdevice_init(tas_hda->priv);
-       if (ret)
-               goto err;
-
-       pm_runtime_set_autosuspend_delay(tas_hda->dev, 3000);
-       pm_runtime_use_autosuspend(tas_hda->dev);
-       pm_runtime_mark_last_busy(tas_hda->dev);
-       pm_runtime_set_active(tas_hda->dev);
-       pm_runtime_enable(tas_hda->dev);
-
-       tasdevice_reset(tas_hda->priv);
-
-       ret = component_add(tas_hda->dev, &tas2781_hda_comp_ops);
-       if (ret) {
-               dev_err(tas_hda->dev, "Register component failed: %d\n", ret);
-               pm_runtime_disable(tas_hda->dev);
-       }
-
-err:
-       if (ret)
-               tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
-       return ret;
-}
-
-static void tas2781_hda_i2c_remove(struct i2c_client *clt)
-{
-       tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
-}
-
-static int tas2781_runtime_suspend(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-
-       dev_dbg(tas_hda->dev, "Runtime Suspend\n");
-
-       mutex_lock(&tas_hda->priv->codec_lock);
-
-       /* The driver powers up the amplifiers at module load time.
-        * Stop the playback if it's unused.
-        */
-       if (tas_hda->priv->playback_started) {
-               tasdevice_tuning_switch(tas_hda->priv, 1);
-               tas_hda->priv->playback_started = false;
-       }
-
-       mutex_unlock(&tas_hda->priv->codec_lock);
-
-       return 0;
-}
-
-static int tas2781_runtime_resume(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-
-       dev_dbg(tas_hda->dev, "Runtime Resume\n");
-
-       mutex_lock(&tas_hda->priv->codec_lock);
-
-       tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
-
-       mutex_unlock(&tas_hda->priv->codec_lock);
-
-       return 0;
-}
-
-static int tas2781_system_suspend(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-
-       dev_dbg(tas_hda->priv->dev, "System Suspend\n");
-
-       mutex_lock(&tas_hda->priv->codec_lock);
-
-       /* Shutdown chip before system suspend */
-       if (tas_hda->priv->playback_started)
-               tasdevice_tuning_switch(tas_hda->priv, 1);
-
-       mutex_unlock(&tas_hda->priv->codec_lock);
-
-       /*
-        * Reset GPIO may be shared, so cannot reset here.
-        * However beyond this point, amps may be powered down.
-        */
-       return 0;
-}
-
-static int tas2781_system_resume(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       int i;
-
-       dev_dbg(tas_hda->priv->dev, "System Resume\n");
-
-       mutex_lock(&tas_hda->priv->codec_lock);
-
-       for (i = 0; i < tas_hda->priv->ndev; i++) {
-               tas_hda->priv->tasdevice[i].cur_book = -1;
-               tas_hda->priv->tasdevice[i].cur_prog = -1;
-               tas_hda->priv->tasdevice[i].cur_conf = -1;
-       }
-       tasdevice_reset(tas_hda->priv);
-       tasdevice_prmg_load(tas_hda->priv, tas_hda->priv->cur_prog);
-
-       if (tas_hda->priv->playback_started)
-               tasdevice_tuning_switch(tas_hda->priv, 0);
-
-       mutex_unlock(&tas_hda->priv->codec_lock);
-
-       return 0;
-}
-
-static const struct dev_pm_ops tas2781_hda_pm_ops = {
-       RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL)
-       SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume)
-};
-
-static const struct i2c_device_id tas2781_hda_i2c_id[] = {
-       { "tas2781-hda" },
-       {}
-};
-
-static const struct acpi_device_id tas2781_acpi_hda_match[] = {
-       {"INT8866", 0 },
-       {"TIAS2781", 0 },
-       {"TXNW2781", 0 },
-       {}
-};
-MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
-
-static struct i2c_driver tas2781_hda_i2c_driver = {
-       .driver = {
-               .name           = "tas2781-hda",
-               .acpi_match_table = tas2781_acpi_hda_match,
-               .pm             = &tas2781_hda_pm_ops,
-       },
-       .id_table       = tas2781_hda_i2c_id,
-       .probe          = tas2781_hda_i2c_probe,
-       .remove         = tas2781_hda_i2c_remove,
-};
-module_i2c_driver(tas2781_hda_i2c_driver);
-
-MODULE_DESCRIPTION("TAS2781 HDA Driver");
-MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
-MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
-MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/pci/hda/tas2781_hda_spi.c
deleted file mode 100644 (file)
index c4b9a3c..0000000
+++ /dev/null
@@ -1,954 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-//
-// TAS2781 HDA SPI driver
-//
-// Copyright 2024 - 2025 Texas Instruments, Inc.
-//
-// Author: Baojun Xu <baojun.xu@ti.com>
-
-#include <linux/acpi.h>
-#include <linux/array_size.h>
-#include <linux/bits.h>
-#include <linux/cleanup.h>
-#include <linux/crc8.h>
-#include <linux/crc32.h>
-#include <linux/efi.h>
-#include <linux/firmware.h>
-#include <linux/mod_devicetable.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/pm_runtime.h>
-#include <linux/property.h>
-#include <linux/regmap.h>
-#include <linux/spi/spi.h>
-#include <linux/time.h>
-#include <linux/types.h>
-#include <linux/units.h>
-
-#include <sound/hda_codec.h>
-#include <sound/soc.h>
-#include <sound/tas2781.h>
-#include <sound/tlv.h>
-#include <sound/tas2781-tlv.h>
-
-#include "hda_local.h"
-#include "hda_auto_parser.h"
-#include "hda_component.h"
-#include "hda_jack.h"
-#include "hda_generic.h"
-#include "tas2781_hda.h"
-
-#define TASDEVICE_RANGE_MAX_SIZE       (256 * 128)
-#define TASDEVICE_WIN_LEN              128
-#define TAS2781_SPI_MAX_FREQ           (4 * HZ_PER_MHZ)
-/* Flag of calibration registers address. */
-#define TASDEVICE_CALIBRATION_REG_ADDRESS      BIT(7)
-#define TASDEV_UEFI_CALI_REG_ADDR_FLG  BIT(7)
-
-/* System Reset Check Register */
-#define TAS2781_REG_CLK_CONFIG         TASDEVICE_REG(0x0, 0x0, 0x5c)
-#define TAS2781_REG_CLK_CONFIG_RESET   0x19
-
-struct tas2781_hda_spi_priv {
-       struct snd_kcontrol *snd_ctls[3];
-};
-
-static const struct regmap_range_cfg tasdevice_ranges[] = {
-       {
-               .range_min = 0,
-               .range_max = TASDEVICE_RANGE_MAX_SIZE,
-               .selector_reg = TASDEVICE_PAGE_SELECT,
-               .selector_mask = GENMASK(7, 0),
-               .selector_shift = 0,
-               .window_start = 0,
-               .window_len = TASDEVICE_WIN_LEN,
-       },
-};
-
-static const struct regmap_config tasdevice_regmap = {
-       .reg_bits = 8,
-       .val_bits = 8,
-       .zero_flag_mask = true,
-       .read_flag_mask = 0x01,
-       .reg_shift = -1,
-       .cache_type = REGCACHE_NONE,
-       .ranges = tasdevice_ranges,
-       .num_ranges = ARRAY_SIZE(tasdevice_ranges),
-       .max_register = TASDEVICE_RANGE_MAX_SIZE,
-};
-
-static int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
-       unsigned short chn, unsigned int reg, unsigned int *val)
-{
-       int ret;
-
-       /*
-        * In our TAS2781 SPI mode, if read from other book (not book 0),
-        * or read from page number larger than 1 in book 0, one more byte
-        * read is needed, and first byte is a dummy byte, need to be ignored.
-        */
-       if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
-               unsigned char data[2];
-
-               ret = tasdevice_dev_bulk_read(tas_priv, chn, reg,
-                       data, sizeof(data));
-               *val = data[1];
-       } else {
-               ret = tasdevice_dev_read(tas_priv, chn, reg, val);
-       }
-       if (ret < 0)
-               dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
-
-       return ret;
-}
-
-static int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
-       unsigned short chn, unsigned int reg, unsigned char *data,
-       unsigned int len)
-{
-       int ret;
-
-       /*
-        * In our TAS2781 SPI mode, if read from other book (not book 0),
-        * or read from page number larger than 1 in book 0, one more byte
-        * read is needed, and first byte is a dummy byte, need to be ignored.
-        */
-       if ((TASDEVICE_BOOK_ID(reg) > 0) || (TASDEVICE_PAGE_ID(reg) > 1)) {
-               unsigned char buf[TASDEVICE_WIN_LEN + 1];
-
-               ret = tasdevice_dev_bulk_read(tas_priv, chn, reg,
-                       buf, len + 1);
-               memcpy(data, buf + 1, len);
-       } else {
-               ret = tasdevice_dev_bulk_read(tas_priv, chn, reg, data, len);
-       }
-       if (ret < 0)
-               dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
-
-       return ret;
-}
-
-static int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tas_priv,
-       unsigned short chn, unsigned int reg, unsigned int mask,
-       unsigned int value)
-{
-       int ret, val;
-
-       /*
-        * In our TAS2781 SPI mode, read/write was masked in last bit of
-        * address, it cause regmap_update_bits() not work as expected.
-        */
-       ret = tasdevice_dev_read(tas_priv, chn, reg, &val);
-       if (ret < 0) {
-               dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
-               return ret;
-       }
-
-       ret = tasdevice_dev_write(tas_priv, chn, TASDEVICE_PAGE_REG(reg),
-               (val & ~mask) | (mask & value));
-       if (ret < 0)
-               dev_err(tas_priv->dev, "%s, E=%d\n", __func__, ret);
-
-       return ret;
-}
-
-static int tasdevice_spi_change_chn_book(struct tasdevice_priv *p,
-       unsigned short chn, int book)
-{
-       int ret = 0;
-
-       if (chn == p->index) {
-               struct tasdevice *tasdev = &p->tasdevice[chn];
-               struct regmap *map = p->regmap;
-
-               if (tasdev->cur_book != book) {
-                       ret = regmap_write(map, TASDEVICE_BOOKCTL_REG, book);
-                       if (ret < 0)
-                               dev_err(p->dev, "%s, E=%d\n", __func__, ret);
-                       else
-                               tasdev->cur_book = book;
-               }
-       } else {
-               ret = -EXDEV;
-               dev_dbg(p->dev, "Not error, %s ignore channel(%d)\n",
-                       __func__, chn);
-       }
-
-       return ret;
-}
-
-static void tas2781_spi_reset(struct tasdevice_priv *tas_dev)
-{
-       int ret;
-
-       if (tas_dev->reset) {
-               gpiod_set_value_cansleep(tas_dev->reset, 0);
-               fsleep(800);
-               gpiod_set_value_cansleep(tas_dev->reset, 1);
-       } else {
-               ret = tasdevice_dev_write(tas_dev, tas_dev->index,
-                       TASDEVICE_REG_SWRESET, TASDEVICE_REG_SWRESET_RESET);
-               if (ret < 0) {
-                       dev_err(tas_dev->dev, "dev sw-reset fail, %d\n", ret);
-                       return;
-               }
-               fsleep(1000);
-       }
-}
-
-static int tascodec_spi_init(struct tasdevice_priv *tas_priv,
-       void *codec, struct module *module,
-       void (*cont)(const struct firmware *fw, void *context))
-{
-       int ret;
-
-       /*
-        * Codec Lock Hold to ensure that codec_probe and firmware parsing and
-        * loading do not simultaneously execute.
-        */
-       guard(mutex)(&tas_priv->codec_lock);
-
-       scnprintf(tas_priv->rca_binaryname,
-               sizeof(tas_priv->rca_binaryname), "%sRCA%d.bin",
-               tas_priv->dev_name, tas_priv->ndev);
-       crc8_populate_msb(tas_priv->crc8_lkp_tbl, TASDEVICE_CRC8_POLYNOMIAL);
-       tas_priv->codec = codec;
-       ret = request_firmware_nowait(module, FW_ACTION_UEVENT,
-               tas_priv->rca_binaryname, tas_priv->dev, GFP_KERNEL, tas_priv,
-               cont);
-       if (ret)
-               dev_err(tas_priv->dev, "request_firmware_nowait err:0x%08x\n",
-                       ret);
-
-       return ret;
-}
-
-static void tasdevice_spi_init(struct tasdevice_priv *tas_priv)
-{
-       tas_priv->tasdevice[tas_priv->index].cur_book = -1;
-       tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
-       tas_priv->tasdevice[tas_priv->index].cur_prog = -1;
-
-       tas_priv->isspi = true;
-
-       tas_priv->update_bits = tasdevice_spi_dev_update_bits;
-       tas_priv->change_chn_book = tasdevice_spi_change_chn_book;
-       tas_priv->dev_read = tasdevice_spi_dev_read;
-       tas_priv->dev_bulk_read = tasdevice_spi_dev_bulk_read;
-
-       mutex_init(&tas_priv->codec_lock);
-}
-
-static int tasdevice_spi_amp_putvol(struct tasdevice_priv *tas_priv,
-       struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
-{
-       unsigned int invert = mc->invert;
-       unsigned char mask;
-       int max = mc->max;
-       int val, ret;
-
-       mask = rounddown_pow_of_two(max);
-       mask <<= mc->shift;
-       val =  clamp(invert ? max - ucontrol->value.integer.value[0] :
-               ucontrol->value.integer.value[0], 0, max);
-
-       ret = tasdevice_spi_dev_update_bits(tas_priv, tas_priv->index,
-               mc->reg, mask, (unsigned int)(val << mc->shift));
-       if (ret)
-               dev_err(tas_priv->dev, "set AMP vol error in dev %d\n",
-                       tas_priv->index);
-
-       return ret;
-}
-
-static int tasdevice_spi_amp_getvol(struct tasdevice_priv *tas_priv,
-       struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
-{
-       unsigned int invert = mc->invert;
-       unsigned char mask = 0;
-       int max = mc->max;
-       int ret, val;
-
-       ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index, mc->reg, &val);
-       if (ret) {
-               dev_err(tas_priv->dev, "%s, get AMP vol error\n", __func__);
-               return ret;
-       }
-
-       mask = rounddown_pow_of_two(max);
-       mask <<= mc->shift;
-       val = (val & mask) >> mc->shift;
-       val = clamp(invert ? max - val : val, 0, max);
-       ucontrol->value.integer.value[0] = val;
-
-       return ret;
-}
-
-static int tasdevice_spi_digital_putvol(struct tasdevice_priv *p,
-       struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
-{
-       unsigned int invert = mc->invert;
-       int max = mc->max;
-       int val, ret;
-
-       val = clamp(invert ? max - ucontrol->value.integer.value[0] :
-               ucontrol->value.integer.value[0], 0, max);
-       ret = tasdevice_dev_write(p, p->index, mc->reg, (unsigned int)val);
-       if (ret)
-               dev_err(p->dev, "set digital vol err in dev %d\n", p->index);
-
-       return ret;
-}
-
-static int tasdevice_spi_digital_getvol(struct tasdevice_priv *p,
-       struct snd_ctl_elem_value *ucontrol, struct soc_mixer_control *mc)
-{
-       unsigned int invert = mc->invert;
-       int max = mc->max;
-       int ret, val;
-
-       ret = tasdevice_spi_dev_read(p, p->index, mc->reg, &val);
-       if (ret) {
-               dev_err(p->dev, "%s, get digital vol err\n", __func__);
-               return ret;
-       }
-
-       val = clamp(invert ? max - val : val, 0, max);
-       ucontrol->value.integer.value[0] = val;
-
-       return ret;
-}
-
-static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
-       const char *hid, int id)
-{
-       struct tasdevice_priv *p = tas_hda->priv;
-       struct acpi_device *adev;
-       struct device *physdev;
-       u32 values[HDA_MAX_COMPONENTS];
-       const char *property;
-       size_t nval;
-       int ret, i;
-
-       adev = acpi_dev_get_first_match_dev(hid, NULL, -1);
-       if (!adev) {
-               dev_err(p->dev, "Failed to find ACPI device: %s\n", hid);
-               return -ENODEV;
-       }
-
-       strscpy(p->dev_name, hid, sizeof(p->dev_name));
-       physdev = get_device(acpi_get_first_physical_node(adev));
-       acpi_dev_put(adev);
-
-       property = "ti,dev-index";
-       ret = device_property_count_u32(physdev, property);
-       if (ret <= 0 || ret > ARRAY_SIZE(values)) {
-               ret = -EINVAL;
-               goto err;
-       }
-       p->ndev = nval = ret;
-
-       ret = device_property_read_u32_array(physdev, property, values, nval);
-       if (ret)
-               goto err;
-
-       p->index = U8_MAX;
-       for (i = 0; i < nval; i++) {
-               if (values[i] == id) {
-                       p->index = i;
-                       break;
-               }
-       }
-       if (p->index == U8_MAX) {
-               dev_dbg(p->dev, "No index found in %s\n", property);
-               ret = -ENODEV;
-               goto err;
-       }
-
-       if (p->index == 0) {
-               /* All of amps share same RESET pin. */
-               p->reset = devm_gpiod_get_index_optional(physdev, "reset",
-                       p->index, GPIOD_OUT_LOW);
-               if (IS_ERR(p->reset)) {
-                       ret = PTR_ERR(p->reset);
-                       dev_err_probe(p->dev, ret, "Failed on reset GPIO\n");
-                       goto err;
-               }
-       }
-       put_device(physdev);
-
-       return 0;
-err:
-       dev_err(p->dev, "read acpi error, ret: %d\n", ret);
-       put_device(physdev);
-       acpi_dev_put(adev);
-
-       return ret;
-}
-
-static void tas2781_hda_playback_hook(struct device *dev, int action)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct tasdevice_priv *tas_priv = tas_hda->priv;
-
-       if (action == HDA_GEN_PCM_ACT_OPEN) {
-               pm_runtime_get_sync(dev);
-               guard(mutex)(&tas_priv->codec_lock);
-               if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)
-                       tasdevice_tuning_switch(tas_hda->priv, 0);
-       } else if (action == HDA_GEN_PCM_ACT_CLOSE) {
-               guard(mutex)(&tas_priv->codec_lock);
-               if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK)
-                       tasdevice_tuning_switch(tas_priv, 1);
-               pm_runtime_put_autosuspend(dev);
-       }
-}
-
-/*
- * tas2781_digital_getvol - get the volum control
- * @kcontrol: control pointer
- * @ucontrol: User data
- *
- * Customer Kcontrol for tas2781 is primarily for regmap booking, paging
- * depends on internal regmap mechanism.
- * tas2781 contains book and page two-level register map, especially
- * book switching will set the register BXXP00R7F, after switching to the
- * correct book, then leverage the mechanism for paging to access the
- * register.
- *
- * Return 0 if succeeded.
- */
-static int tas2781_digital_getvol(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-
-       guard(mutex)(&tas_priv->codec_lock);
-       return tasdevice_spi_digital_getvol(tas_priv, ucontrol, mc);
-}
-
-static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-
-       guard(mutex)(&tas_priv->codec_lock);
-       return tasdevice_spi_amp_getvol(tas_priv, ucontrol, mc);
-}
-
-static int tas2781_digital_putvol(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-
-       guard(mutex)(&tas_priv->codec_lock);
-       return tasdevice_spi_digital_putvol(tas_priv, ucontrol, mc);
-}
-
-static int tas2781_amp_putvol(struct snd_kcontrol *kcontrol,
-                             struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct soc_mixer_control *mc =
-               (struct soc_mixer_control *)kcontrol->private_value;
-
-       guard(mutex)(&tas_priv->codec_lock);
-       return tasdevice_spi_amp_putvol(tas_priv, ucontrol, mc);
-}
-
-static int tas2781_force_fwload_get(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = (int)tas_priv->force_fwload_status;
-       dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
-               str_on_off(tas_priv->force_fwload_status));
-
-       return 0;
-}
-
-static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       bool change, val = (bool)ucontrol->value.integer.value[0];
-
-       if (tas_priv->force_fwload_status == val) {
-               change = false;
-       } else {
-               change = true;
-               tas_priv->force_fwload_status = val;
-       }
-       dev_dbg(tas_priv->dev, "%s : Force FWload %s\n", __func__,
-               str_on_off(tas_priv->force_fwload_status));
-
-       return change;
-}
-
-static struct snd_kcontrol_new tas2781_snd_ctls[] = {
-       ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_AMP_LEVEL, 1, 0, 20, 0,
-               tas2781_amp_getvol, tas2781_amp_putvol, amp_vol_tlv),
-       ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_DVC_LVL, 0, 0, 200, 1,
-               tas2781_digital_getvol, tas2781_digital_putvol, dvc_tlv),
-       ACARD_SINGLE_BOOL_EXT(NULL, 0, tas2781_force_fwload_get,
-               tas2781_force_fwload_put),
-};
-
-static struct snd_kcontrol_new tas2781_prof_ctl = {
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_profile,
-       .get = tasdevice_get_profile_id,
-       .put = tasdevice_set_profile_id,
-};
-
-static struct snd_kcontrol_new tas2781_dsp_ctls[] = {
-       /* Speaker Program */
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-               .info = tasdevice_info_programs,
-               .get = tasdevice_program_get,
-               .put = tasdevice_program_put,
-       },
-       /* Speaker Config */
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-               .info = tasdevice_info_config,
-               .get = tasdevice_config_get,
-               .put = tasdevice_config_put,
-       },
-};
-
-static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
-{
-       struct hda_codec *codec = tas_hda->priv->codec;
-       struct tas2781_hda_spi_priv *h_priv = tas_hda->hda_priv;
-
-       snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
-
-       snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
-
-       for (int i = ARRAY_SIZE(h_priv->snd_ctls) - 1; i >= 0; i--)
-               snd_ctl_remove(codec->card, h_priv->snd_ctls[i]);
-
-       snd_ctl_remove(codec->card, tas_hda->prof_ctl);
-}
-
-static int tas2781_hda_spi_prf_ctl(struct tas2781_hda *h)
-{
-       struct tasdevice_priv *p = h->priv;
-       struct hda_codec *c = p->codec;
-       char name[64];
-       int rc;
-
-       snprintf(name, sizeof(name), "Speaker-%d Profile Id", p->index);
-       tas2781_prof_ctl.name = name;
-       h->prof_ctl = snd_ctl_new1(&tas2781_prof_ctl, p);
-       rc = snd_ctl_add(c->card, h->prof_ctl);
-       if (rc)
-               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
-                       tas2781_prof_ctl.name, rc);
-       return rc;
-}
-
-static int tas2781_hda_spi_snd_ctls(struct tas2781_hda *h)
-{
-       struct tas2781_hda_spi_priv *h_priv = h->hda_priv;
-       struct tasdevice_priv *p = h->priv;
-       struct hda_codec *c = p->codec;
-       char name[64];
-       int i = 0;
-       int rc;
-
-       snprintf(name, sizeof(name), "Speaker-%d Analog Volume", p->index);
-       tas2781_snd_ctls[i].name = name;
-       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
-       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
-       if (rc) {
-               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
-                       tas2781_snd_ctls[i].name, rc);
-               return rc;
-       }
-       i++;
-       snprintf(name, sizeof(name), "Speaker-%d Digital Volume", p->index);
-       tas2781_snd_ctls[i].name = name;
-       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
-       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
-       if (rc) {
-               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
-                       tas2781_snd_ctls[i].name, rc);
-               return rc;
-       }
-       i++;
-       snprintf(name, sizeof(name), "Froce Speaker-%d FW Load", p->index);
-       tas2781_snd_ctls[i].name = name;
-       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
-       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
-       if (rc) {
-               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
-                       tas2781_snd_ctls[i].name, rc);
-       }
-       return rc;
-}
-
-static int tas2781_hda_spi_dsp_ctls(struct tas2781_hda *h)
-{
-       struct tasdevice_priv *p = h->priv;
-       struct hda_codec *c = p->codec;
-       char name[64];
-       int i = 0;
-       int rc;
-
-       snprintf(name, sizeof(name), "Speaker-%d Program Id", p->index);
-       tas2781_dsp_ctls[i].name = name;
-       h->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
-       rc = snd_ctl_add(c->card, h->dsp_prog_ctl);
-       if (rc) {
-               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
-                       tas2781_dsp_ctls[i].name, rc);
-               return rc;
-       }
-       i++;
-       snprintf(name, sizeof(name), "Speaker-%d Config Id", p->index);
-       tas2781_dsp_ctls[i].name = name;
-       h->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
-       rc = snd_ctl_add(c->card, h->dsp_conf_ctl);
-       if (rc) {
-               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
-                       tas2781_dsp_ctls[i].name, rc);
-       }
-
-       return rc;
-}
-
-static void tasdev_fw_ready(const struct firmware *fmw, void *context)
-{
-       struct tasdevice_priv *tas_priv = context;
-       struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
-       struct hda_codec *codec = tas_priv->codec;
-       int ret, val;
-
-       pm_runtime_get_sync(tas_priv->dev);
-       guard(mutex)(&tas_priv->codec_lock);
-
-       ret = tasdevice_rca_parser(tas_priv, fmw);
-       if (ret)
-               goto out;
-
-       /* Add control one time only. */
-       ret = tas2781_hda_spi_prf_ctl(tas_hda);
-       if (ret)
-               goto out;
-
-       ret = tas2781_hda_spi_snd_ctls(tas_hda);
-       if (ret)
-               goto out;
-
-       tasdevice_dsp_remove(tas_priv);
-
-       tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
-       scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X-%01d.bin",
-               lower_16_bits(codec->core.subsystem_id), tas_priv->index);
-       ret = tasdevice_dsp_parser(tas_priv);
-       if (ret) {
-               dev_err(tas_priv->dev, "dspfw load %s error\n",
-                       tas_priv->coef_binaryname);
-               tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL;
-               goto out;
-       }
-
-       ret = tas2781_hda_spi_dsp_ctls(tas_hda);
-       if (ret)
-               goto out;
-       /* Perform AMP reset before firmware download. */
-       tas2781_spi_reset(tas_priv);
-       tas_priv->rcabin.profile_cfg_id = 0;
-
-       tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
-       ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index,
-               TAS2781_REG_CLK_CONFIG, &val);
-       if (ret < 0)
-               goto out;
-
-       if (val == TAS2781_REG_CLK_CONFIG_RESET) {
-               ret = tasdevice_prmg_load(tas_priv, 0);
-               if (ret < 0) {
-                       dev_err(tas_priv->dev, "FW download failed = %d\n",
-                               ret);
-                       goto out;
-               }
-               tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
-       }
-       if (tas_priv->fmw->nr_programs > 0)
-               tas_priv->tasdevice[tas_priv->index].cur_prog = 0;
-       if (tas_priv->fmw->nr_configurations > 0)
-               tas_priv->tasdevice[tas_priv->index].cur_conf = 0;
-
-       /*
-        * If calibrated data occurs error, dsp will still works with default
-        * calibrated data inside algo.
-        */
-       tas2781_save_calibration(tas_hda);
-out:
-       release_firmware(fmw);
-       pm_runtime_put_autosuspend(tas_hda->priv->dev);
-}
-
-static int tas2781_hda_bind(struct device *dev, struct device *master,
-       void *master_data)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct hda_component_parent *parent = master_data;
-       struct hda_component *comp;
-       struct hda_codec *codec;
-       int ret;
-
-       comp = hda_component_from_index(parent, tas_hda->priv->index);
-       if (!comp)
-               return -EINVAL;
-
-       if (comp->dev)
-               return -EBUSY;
-
-       codec = parent->codec;
-
-       pm_runtime_get_sync(dev);
-
-       comp->dev = dev;
-
-       strscpy(comp->name, dev_name(dev), sizeof(comp->name));
-
-       ret = tascodec_spi_init(tas_hda->priv, codec, THIS_MODULE,
-               tasdev_fw_ready);
-       if (!ret)
-               comp->playback_hook = tas2781_hda_playback_hook;
-
-       pm_runtime_put_autosuspend(dev);
-
-       return ret;
-}
-
-static void tas2781_hda_unbind(struct device *dev, struct device *master,
-                              void *master_data)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct hda_component_parent *parent = master_data;
-       struct tasdevice_priv *tas_priv = tas_hda->priv;
-       struct hda_component *comp;
-
-       comp = hda_component_from_index(parent, tas_priv->index);
-       if (comp && (comp->dev == dev)) {
-               comp->dev = NULL;
-               memset(comp->name, 0, sizeof(comp->name));
-               comp->playback_hook = NULL;
-       }
-
-       tas2781_hda_remove_controls(tas_hda);
-
-       tasdevice_config_info_remove(tas_priv);
-       tasdevice_dsp_remove(tas_priv);
-
-       tas_hda->priv->fw_state = TASDEVICE_DSP_FW_PENDING;
-}
-
-static const struct component_ops tas2781_hda_comp_ops = {
-       .bind = tas2781_hda_bind,
-       .unbind = tas2781_hda_unbind,
-};
-
-static int tas2781_hda_spi_probe(struct spi_device *spi)
-{
-       struct tas2781_hda_spi_priv *hda_priv;
-       struct tasdevice_priv *tas_priv;
-       struct tas2781_hda *tas_hda;
-       const char *device_name;
-       int ret = 0;
-
-       tas_hda = devm_kzalloc(&spi->dev, sizeof(*tas_hda), GFP_KERNEL);
-       if (!tas_hda)
-               return -ENOMEM;
-
-       hda_priv = devm_kzalloc(&spi->dev, sizeof(*hda_priv), GFP_KERNEL);
-       if (!hda_priv)
-               return -ENOMEM;
-
-       tas_hda->hda_priv = hda_priv;
-       spi->max_speed_hz = TAS2781_SPI_MAX_FREQ;
-
-       tas_priv = devm_kzalloc(&spi->dev, sizeof(*tas_priv), GFP_KERNEL);
-       if (!tas_priv)
-               return -ENOMEM;
-       tas_priv->dev = &spi->dev;
-       tas_hda->priv = tas_priv;
-       tas_priv->regmap = devm_regmap_init_spi(spi, &tasdevice_regmap);
-       if (IS_ERR(tas_priv->regmap)) {
-               ret = PTR_ERR(tas_priv->regmap);
-               dev_err(tas_priv->dev, "Failed to allocate regmap: %d\n",
-                       ret);
-               return ret;
-       }
-       if (strstr(dev_name(&spi->dev), "TXNW2781")) {
-               device_name = "TXNW2781";
-       } else {
-               dev_err(tas_priv->dev, "Unmatched spi dev %s\n",
-                       dev_name(&spi->dev));
-               return -ENODEV;
-       }
-
-       tas_priv->irq = spi->irq;
-       dev_set_drvdata(&spi->dev, tas_hda);
-       ret = tas2781_read_acpi(tas_hda, device_name,
-                               spi_get_chipselect(spi, 0));
-       if (ret)
-               return dev_err_probe(tas_priv->dev, ret,
-                               "Platform not supported\n");
-
-       tasdevice_spi_init(tas_priv);
-
-       pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000);
-       pm_runtime_use_autosuspend(tas_priv->dev);
-       pm_runtime_set_active(tas_priv->dev);
-       pm_runtime_get_noresume(tas_priv->dev);
-       pm_runtime_enable(tas_priv->dev);
-
-       pm_runtime_put_autosuspend(tas_priv->dev);
-
-       ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
-       if (ret) {
-               dev_err(tas_priv->dev, "Register component fail: %d\n", ret);
-               pm_runtime_disable(tas_priv->dev);
-               tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
-       }
-
-       return ret;
-}
-
-static void tas2781_hda_spi_remove(struct spi_device *spi)
-{
-       tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
-}
-
-static int tas2781_runtime_suspend(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct tasdevice_priv *tas_priv = tas_hda->priv;
-
-       guard(mutex)(&tas_priv->codec_lock);
-
-       if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
-               && tas_priv->playback_started)
-               tasdevice_tuning_switch(tas_priv, 1);
-
-       tas_priv->tasdevice[tas_priv->index].cur_book = -1;
-       tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
-
-       return 0;
-}
-
-static int tas2781_runtime_resume(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct tasdevice_priv *tas_priv = tas_hda->priv;
-
-       guard(mutex)(&tas_priv->codec_lock);
-
-       if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
-               && tas_priv->playback_started)
-               tasdevice_tuning_switch(tas_priv, 0);
-
-       return 0;
-}
-
-static int tas2781_system_suspend(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct tasdevice_priv *tas_priv = tas_hda->priv;
-       int ret;
-
-       ret = pm_runtime_force_suspend(dev);
-       if (ret)
-               return ret;
-
-       /* Shutdown chip before system suspend */
-       if (tas_priv->fw_state == TASDEVICE_DSP_FW_ALL_OK
-               && tas_priv->playback_started)
-               tasdevice_tuning_switch(tas_priv, 1);
-
-       return 0;
-}
-
-static int tas2781_system_resume(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-       struct tasdevice_priv *tas_priv = tas_hda->priv;
-       int ret, val;
-
-       ret = pm_runtime_force_resume(dev);
-       if (ret)
-               return ret;
-
-       guard(mutex)(&tas_priv->codec_lock);
-       ret = tas_priv->dev_read(tas_priv, tas_priv->index,
-               TAS2781_REG_CLK_CONFIG, &val);
-       if (ret < 0)
-               return ret;
-
-       if (val == TAS2781_REG_CLK_CONFIG_RESET) {
-               tas_priv->tasdevice[tas_priv->index].cur_book = -1;
-               tas_priv->tasdevice[tas_priv->index].cur_conf = -1;
-               tas_priv->tasdevice[tas_priv->index].cur_prog = -1;
-
-               ret = tasdevice_prmg_load(tas_priv, 0);
-               if (ret < 0) {
-                       dev_err(tas_priv->dev,
-                               "FW download failed = %d\n", ret);
-                       return ret;
-               }
-               tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
-
-               if (tas_priv->playback_started)
-                       tasdevice_tuning_switch(tas_priv, 0);
-       }
-
-       return ret;
-}
-
-static const struct dev_pm_ops tas2781_hda_pm_ops = {
-       RUNTIME_PM_OPS(tas2781_runtime_suspend, tas2781_runtime_resume, NULL)
-       SYSTEM_SLEEP_PM_OPS(tas2781_system_suspend, tas2781_system_resume)
-};
-
-static const struct spi_device_id tas2781_hda_spi_id[] = {
-       { "tas2781-hda", },
-       {}
-};
-
-static const struct acpi_device_id tas2781_acpi_hda_match[] = {
-       {"TXNW2781", },
-       {}
-};
-MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
-
-static struct spi_driver tas2781_hda_spi_driver = {
-       .driver = {
-               .name           = "tas2781-hda",
-               .acpi_match_table = tas2781_acpi_hda_match,
-               .pm             = &tas2781_hda_pm_ops,
-       },
-       .id_table       = tas2781_hda_spi_id,
-       .probe          = tas2781_hda_spi_probe,
-       .remove         = tas2781_hda_spi_remove,
-};
-module_spi_driver(tas2781_hda_spi_driver);
-
-MODULE_DESCRIPTION("TAS2781 HDA SPI Driver");
-MODULE_AUTHOR("Baojun, Xu, <baojun.xug@ti.com>");
-MODULE_LICENSE("GPL");
-MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
-MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c
deleted file mode 100644 (file)
index de4d8de..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/* Helper functions for Thinkpad LED control;
- * to be included from codec driver
- */
-
-#if IS_ENABLED(CONFIG_THINKPAD_ACPI)
-
-#include <linux/acpi.h>
-#include <linux/leds.h>
-
-static bool is_thinkpad(struct hda_codec *codec)
-{
-       return (codec->core.subsystem_id >> 16 == 0x17aa) &&
-              (acpi_dev_found("LEN0068") || acpi_dev_found("LEN0268") ||
-               acpi_dev_found("IBM0068"));
-}
-
-static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-       if (action == HDA_FIXUP_ACT_PRE_PROBE) {
-               if (!is_thinkpad(codec))
-                       return;
-               snd_hda_gen_add_mute_led_cdev(codec, NULL);
-               snd_hda_gen_add_micmute_led_cdev(codec, NULL);
-       }
-}
-
-#else /* CONFIG_THINKPAD_ACPI */
-
-static void hda_fixup_thinkpad_acpi(struct hda_codec *codec,
-                                   const struct hda_fixup *fix, int action)
-{
-}
-
-#endif /* CONFIG_THINKPAD_ACPI */