lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20251210080458.3973-1-antivirus621@gmail.com>
Date: Wed, 10 Dec 2025 16:04:58 +0800
From: Leo Tsai <antivirus621@...il.com>
To: perex@...ex.cz,
	tiwai@...e.com,
	rf@...nsource.cirrus.com
Cc: leo.tsai@...dia.com.tw,
	linux-sound@...r.kernel.org,
	linux-kernel@...r.kernel.org,
	Leo Tsai <antivirus621@...il.com>
Subject: [PATCH] ALSA: hda/cm9825: Add DFI and NCR new projects

Add DFI(IBP, ASL051, ARH171) and NCR(GENE_TWL7) projects.

Signed-off-by: Leo Tsai <antivirus621@...il.com>
---
 sound/hda/codecs/cm9825.c | 1318 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 1299 insertions(+), 19 deletions(-)

diff --git a/sound/hda/codecs/cm9825.c b/sound/hda/codecs/cm9825.c
index 5c474ce44348..6b8410cf77c2 100644
--- a/sound/hda/codecs/cm9825.c
+++ b/sound/hda/codecs/cm9825.c
@@ -13,6 +13,15 @@
 #include "hda_jack.h"
 #include "generic.h"
 
+enum {
+	QUIRK_CM_STD = 0x0,
+	QUIRK_NCR_SSID = 0x104388f0,
+	QUIRK_ASL051_SSID = 0x15bd3274,
+	QUIRK_IBP_SSID = 0x15bd3275,
+	QUIRK_ARH171_SSID = 0x15bd3276,
+	QUIRK_GENE_TWL7_SSID = 0x160dc000,
+};
+
 /* CM9825 Offset Definitions */
 
 #define CM9825_VERB_SET_HPF_1 0x781
@@ -22,11 +31,14 @@
 #define CM9825_VERB_SET_ADCL 0x7a2
 #define CM9825_VERB_SET_DACL 0x7a3
 #define CM9825_VERB_SET_MBIAS 0x7a4
+#define CM9825_VERB_SET_WIGCAP 0x7a6
 #define CM9825_VERB_SET_VNEG 0x7a8
 #define CM9825_VERB_SET_D2S 0x7a9
 #define CM9825_VERB_SET_DACTRL 0x7aa
+#define CM9825_VERB_SET_P37CAP 0x7ab
 #define CM9825_VERB_SET_PDNEG 0x7ac
 #define CM9825_VERB_SET_VDO 0x7ad
+#define CM9825_VERB_SET_BYPASSDIGGAIN 0x7ae
 #define CM9825_VERB_SET_CDALR 0x7b0
 #define CM9825_VERB_SET_MTCBA 0x7b1
 #define CM9825_VERB_SET_OTP 0x7b2
@@ -34,16 +46,48 @@
 #define CM9825_VERB_SET_GAD 0x7b4
 #define CM9825_VERB_SET_TMOD 0x7b5
 #define CM9825_VERB_SET_SNR 0x7b6
+#define CM9825_VERB_SET_VW11TSMODE 0x7b7
 
 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;
+	const struct hda_verb *chip_playback_start_verbs;
+	const struct hda_verb *chip_playback_stop_verbs;
+	const struct hda_verb *chip_0x34_playback_start_verbs;
+	const struct hda_verb *chip_0x34_playback_stop_verbs;
+	const struct hda_verb *chip_0x34_present_verbs;
+	const struct hda_verb *chip_0x34_remove_verbs;
+	const struct hda_verb *chip_0x3b_present_verbs;
+	const struct hda_verb *chip_0x3b_remove_verbs;
+	const struct hda_verb *chip_0x36_present_verbs;
+	const struct hda_verb *chip_0x36_remove_verbs;
+	const struct hda_verb *chip_0x37_present_verbs;
+	const struct hda_verb *chip_0x37_remove_verbs;
+	const struct hda_verb *chip_lineout_retasking_trig_verbs;
+	const struct hda_verb *chip_lineout_retasking_remove_verbs;
+	const struct hda_verb *chip_linein_retasking_trig_verbs;
+	const struct hda_verb *chip_linein_retasking_remove_verbs;
+	const struct hda_verb *chip_hp_retasking_trig_verbs;
+	const struct hda_verb *chip_hp_retasking_remove_verbs;
+	const struct hda_verb *chip_mic_retasking_trig_verbs;
+	const struct hda_verb *chip_mic_retasking_remove_verbs;
 	struct hda_codec *codec;
+	struct delayed_work unsol_line_work;
 	struct delayed_work unsol_hp_work;
 	int quirk;
+	unsigned int playback_started:1;
+	unsigned int capture_started:1;
+	unsigned int retasking_line:1;
+	unsigned int retasking_hp:1;
+	hda_nid_t dacs[AUTO_CFG_MAX_OUTS];
+	struct snd_pcm_substream *substream;
+};
+
+static const struct snd_kcontrol_new arh171_mixer[] = {
+	HDA_CODEC_VOLUME("Capture Volume", 0x33, 0, HDA_INPUT),
+	HDA_CODEC_MUTE("Capture Switch", 0x33, 0, HDA_INPUT),
+	{}			/* end */
 };
 
 static const struct hda_verb cm9825_std_d3_verbs[] = {
@@ -80,15 +124,326 @@ static const struct hda_verb cm9825_std_d0_verbs[] = {
 	{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 */
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0xa0, 0x2d},	/* Gain set */
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 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_ncr_d3_verbs[] = {
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_PLL, 0x01},
+	{0x43, CM9825_VERB_SET_NEG, 0xc2},
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_VNEG, 0x50},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x04},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf6},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{}
+};
+
+static const struct hda_verb cm9825_ncr_d0_verbs[] = {
+	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+	{0x43, CM9825_VERB_SET_SNR, 0x30},
+	{0x43, CM9825_VERB_SET_PLL, 0x00},
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{0x43, CM9825_VERB_SET_VNEG, 0x56},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x0c},
+	{0x43, CM9825_VERB_SET_VDO, 0xc4},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf4},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{0x43, CM9825_VERB_SET_MTCBA, 0x61},
+	{0x43, CM9825_VERB_SET_OCP, 0x33},
+	{0x43, CM9825_VERB_SET_GAD, 0x07},
+	{0x43, CM9825_VERB_SET_TMOD, 0x26},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0xa0, 0x2d},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 0x2d},
+	{0x43, CM9825_VERB_SET_HPF_1, 0x40},
+	{0x43, CM9825_VERB_SET_HPF_2, 0x40},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x41, 0x80},
+	{0x01, 0x720, 0xf0},
+	{0x01, 0x721, 0x88},
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x40, 0x00},
+	{}
+};
+
+static const struct hda_verb cm9825_ibp_d3_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_ibp_d0_verbs[] = {
+	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},	/* EAPD set */
+	{0x43, CM9825_VERB_SET_SNR, 0x38},	/* 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_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 | 0xa0, 0x2d},	/* Gain set */
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 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_asl051_d3_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_asl051_d0_verbs[] = {
+	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},	/* EAPD set */
+	{0x43, CM9825_VERB_SET_SNR, 0x38},	/* 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_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 | 0xa0, 0x2d},	/* Gain set */
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 0x2d},	/* Gain set */
+	{0x43, CM9825_VERB_SET_HPF_1, 0x40},	/* HPF set */
+	{0x43, CM9825_VERB_SET_HPF_2, 0x40},	/* HPF set */
+	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE | 0x20, 0x11},
+	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE | 0x10, 0x11},
+	{0x39, AC_VERB_SET_AMP_GAIN_MUTE | 0x20, 0x11},
+	{0x39, AC_VERB_SET_AMP_GAIN_MUTE | 0x10, 0x11},
+	{0x43, CM9825_VERB_SET_BYPASSDIGGAIN, 0x10},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_tp_verbs[] = {
+	{0x46, CM9825_VERB_SET_WIGCAP, 0x8b},
+	{0x46, CM9825_VERB_SET_NEG, 0x10},
+	{0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01},
+	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE | 0x20, 0x11},
+	{0x3a, AC_VERB_SET_AMP_GAIN_MUTE | 0x10, 0x11},
+	{0x43, CM9825_VERB_SET_BYPASSDIGGAIN, 0x10},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_d3_verbs[] = {
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_VDO, 0x90},
+	{0x43, CM9825_VERB_SET_VW11TSMODE, 0x00},
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{0x43, CM9825_VERB_SET_PLL, 0x01},
+	{0x43, CM9825_VERB_SET_NEG, 0xc2},
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{0x43, CM9825_VERB_SET_VNEG, 0x50},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x04},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf6},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_d0_verbs[] = {
+	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+	{0x43, CM9825_VERB_SET_SNR, 0x30},
+	{0x43, CM9825_VERB_SET_VW11TSMODE, 0x08},
+	{0x43, CM9825_VERB_SET_PLL, 0x00},
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{0x43, CM9825_VERB_SET_VNEG, 0x56},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x0c},
+	{0x43, CM9825_VERB_SET_VDO, 0x90},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf4},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{0x43, CM9825_VERB_SET_MTCBA, 0x61},
+	{0x43, CM9825_VERB_SET_OCP, 0x33},
+	{0x43, CM9825_VERB_SET_GAD, 0x07},
+	{0x43, CM9825_VERB_SET_TMOD, 0x26},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0xa0, 0x2d},
+	{0x3c, AC_VERB_SET_AMP_GAIN_MUTE | 0x90, 0x2d},
+	{0x43, CM9825_VERB_SET_HPF_1, 0x40},
+	{0x43, CM9825_VERB_SET_HPF_2, 0x40},
+	{}
+};
+
+static const struct hda_verb cm9825_gene_twl7_d3_verbs[] = {
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_PLL, 0x01},
+	{0x43, CM9825_VERB_SET_NEG, 0xc2},
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{0x43, CM9825_VERB_SET_VNEG, 0x50},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x04},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf6},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{}
+};
+
+static const struct hda_verb cm9825_gene_twl7_d0_verbs[] = {
+	{0x34, AC_VERB_SET_EAPD_BTLENABLE, 0x02},
+	{0x43, CM9825_VERB_SET_SNR, 0x38},
+	{0x43, CM9825_VERB_SET_PLL, 0x00},
+	{0x43, CM9825_VERB_SET_ADCL, 0xcf},
+	{0x43, CM9825_VERB_SET_DACL, 0xaa},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x1c},
+	{0x43, CM9825_VERB_SET_VNEG, 0x56},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{0x43, CM9825_VERB_SET_PDNEG, 0x0c},
+	{0x43, CM9825_VERB_SET_CDALR, 0xf4},
+	{0x43, CM9825_VERB_SET_OTP, 0xcd},
+	{0x43, CM9825_VERB_SET_MTCBA, 0x61},
+	{0x43, CM9825_VERB_SET_OCP, 0x33},
+	{0x43, CM9825_VERB_SET_GAD, 0x07},
+	{0x43, CM9825_VERB_SET_TMOD, 0x26},
+	{0x43, CM9825_VERB_SET_HPF_1, 0x40},
+	{0x43, CM9825_VERB_SET_HPF_2, 0x40},
+	{0x40, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x3d, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x46, CM9825_VERB_SET_P37CAP, 0x20},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_hp_present_verbs[] = {
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_hp_remove_verbs[] = {
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_micin_present_verbs[] = {
+	{0x40, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x3a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_micin_remove_verbs[] = {
+	{0x40, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x3a, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_spk_playback_start_verbs[] = {
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x01},
+	{0x43, CM9825_VERB_SET_DACTRL, 0xe0},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_spk_playback_stop_verbs[] = {
+	{0x01, AC_VERB_SET_GPIO_DATA, 0x00},
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_hp_playback_start_verbs[] = {
+	{0x43, CM9825_VERB_SET_D2S, 0xf2},
+	{0x43, CM9825_VERB_SET_VDO, 0xd4},
+	{}
+};
+
+static const struct hda_verb cm9825_arh171_hp_playback_stop_verbs[] = {
+	{0x43, CM9825_VERB_SET_VDO, 0xc0},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_VDO, 0x90},
+	{}
+};
+
+static const struct hda_verb cm9825_ncr_playback_start_verbs[] = {
+	{0x43, CM9825_VERB_SET_DACL, 0xAE},
+	{0x43, CM9825_VERB_SET_D2S, 0xF2},
+	{0x43, CM9825_VERB_SET_VDO, 0xC4},
+	{0x43, CM9825_VERB_SET_DACTRL, 0xE0},
+	{}
+};
+
+static const struct hda_verb cm9825_ncr_playback_stop_verbs[] = {
+	{0x43, CM9825_VERB_SET_VDO, 0xC0},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_VDO, 0x80},
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{}
+};
+
+static const struct hda_verb cm9825_ibp_playback_start_verbs[] = {
+	{0x43, CM9825_VERB_SET_DACL, 0xaa},
+	{0x43, CM9825_VERB_SET_D2S, 0xf2},
+	{0x43, CM9825_VERB_SET_VDO, 0xc4},
+	{0x43, CM9825_VERB_SET_SNR, 0x30},
+	{}
+};
+
+static const struct hda_verb cm9825_ibp_playback_stop_verbs[] = {
+	{0x43, CM9825_VERB_SET_VDO, 0xc0},
+	{0x43, CM9825_VERB_SET_DACL, 0x02},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_VDO, 0x80},
+	{0x43, CM9825_VERB_SET_SNR, 0x38},
+	{}
+};
+
+static const struct hda_verb cm9825_gene_twl7_playback_start_verbs[] = {
+	{0x43, CM9825_VERB_SET_D2S, 0xf2},
+	{0x43, CM9825_VERB_SET_VDO, 0xd4},
+	{0x43, CM9825_VERB_SET_SNR, 0x30},
+	{}
+};
+
+static const struct hda_verb cm9825_gene_twl7_playback_stop_verbs[] = {
+	{0x43, CM9825_VERB_SET_VDO, 0xc0},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_VDO, 0xd0},
+	{0x43, CM9825_VERB_SET_SNR, 0x38},
+	{}
+};
+
 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 */
@@ -111,12 +466,206 @@ static const struct hda_verb cm9825_hp_remove_verbs[] = {
 	{}
 };
 
+static const struct hda_verb cm9825_ibp_hp_present_verbs[] = {
+	{0x43, CM9825_VERB_SET_ADCL, 0x8c},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x10},
+	{}
+};
+
+static const struct hda_verb cm9825_ibp_hp_remove_verbs[] = {
+	{0x43, CM9825_VERB_SET_ADCL, 0x00},
+	{0x43, CM9825_VERB_SET_MBIAS, 0x00},
+	{}
+};
+
+static const struct hda_verb asl051_retasking_lineout_trig_verbs[] = {
+	{0x43, CM9825_VERB_SET_DACTRL, 0xe0},
+	{0x43, CM9825_VERB_SET_SNR, 0x30},
+	{}
+};
+
+static const struct hda_verb asl051_retasking_lineout_remove_verbs[] = {
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{0x43, CM9825_VERB_SET_SNR, 0x38},
+	{}
+};
+
+static const struct hda_verb asl051_retasking_linein_trig_verbs[] = {
+	{0x40, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x43, CM9825_VERB_SET_DACTRL, 0x00},
+	{}
+};
+
+static const struct hda_verb asl051_retasking_linein_remove_verbs[] = {
+	{0x40, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{}
+};
+
+static const struct hda_verb asl051_retasking_hp_trig_verbs[] = {
+	{0x43, CM9825_VERB_SET_D2S, 0xf2},
+	{0x43, CM9825_VERB_SET_VDO, 0xc4},
+	{0x43, CM9825_VERB_SET_SNR, 0x30},
+	{}
+};
+
+static const struct hda_verb asl051_retasking_hp_remove_verbs[] = {
+	{0x43, CM9825_VERB_SET_VDO, 0xc0},
+	{0x43, CM9825_VERB_SET_D2S, 0x62},
+	{0x43, CM9825_VERB_SET_VDO, 0x80},
+	{0x43, CM9825_VERB_SET_SNR, 0x38},
+	{}
+};
+
+static const struct hda_verb asl051_retasking_mic_trig_verbs[] = {
+	{0x3d, AC_VERB_SET_CONNECT_SEL, 0x01},
+	{0x43, CM9825_VERB_SET_VDO, 0x90},
+	{}
+};
+
+static const struct hda_verb asl051_retasking_mic_remove_verbs[] = {
+	{0x3d, AC_VERB_SET_CONNECT_SEL, 0x00},
+	{0x43, CM9825_VERB_SET_VDO, 0x80},
+	{}
+};
+
+static struct hda_multi_out asl051_multi_out = {
+	.num_dacs = 2,
+	.dac_nids = (hda_nid_t[]){0x31, 0x30},
+	.max_channels = 2,
+	.dig_out_nid = 0,
+	.share_spdif = false,
+};
+
+static void asl051_retasking_bias2_sw(struct hda_codec *codec, int en)
+{
+	unsigned int val;
+
+	if (en) {
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa4, 0x0);
+		val = (val & 0xff) | 0x08;
+	} else {
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa4, 0x0);
+		val = (val & 0xf7);
+	}
+
+	snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_MBIAS, val);
+}
+
+static void asl051_retasking_bias1_sw(struct hda_codec *codec, int en)
+{
+	unsigned int val;
+
+	if (en) {
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa4, 0x0);
+		val = (val & 0xff) | 0x10;
+	} else {
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa4, 0x0);
+		val = val & 0xfb;
+	}
+
+	snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_MBIAS, val);
+}
+
+static void asl051_retasking_mic(struct hda_codec *codec, int trig)
+{
+	struct cmi_spec *spec = codec->spec;
+	unsigned int val;
+
+	codec_dbg(codec, "%s trig %d\n", __func__, trig);
+
+	if (trig) {
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = ((val >> 16) & 0xff) | 0x8c;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_ADCL, val);
+		asl051_retasking_bias2_sw(codec, 1);
+		snd_hda_sequence_write(codec,
+				       spec->chip_mic_retasking_trig_verbs);
+	} else {
+		snd_hda_sequence_write(codec,
+				       spec->chip_mic_retasking_remove_verbs);
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = (val >> 16) & 0x73;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_ADCL, val);
+		asl051_retasking_bias2_sw(codec, 0);
+	}
+}
+
+static void asl051_retasking_hp(struct hda_codec *codec, int trig)
+{
+	struct cmi_spec *spec = codec->spec;
+	unsigned int val;
+
+	if (trig) {
+		asl051_retasking_bias2_sw(codec, 0);
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = (val >> 24) | 0xa8;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_DACL, val);
+		snd_hda_sequence_write(codec,
+				       spec->chip_hp_retasking_trig_verbs);
+	} else {
+		snd_hda_sequence_write(codec,
+				       spec->chip_hp_retasking_remove_verbs);
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = (val >> 24) & 0x57;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_DACL, val);
+	}
+}
+
+static void asl051_retasking_lineout(struct hda_codec *codec, int trig)
+{
+	struct cmi_spec *spec = codec->spec;
+	unsigned int val;
+
+	if (trig) {
+		asl051_retasking_bias1_sw(codec, 0);
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = (val >> 16) & 0xbc;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_ADCL, val);
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = (val >> 24) | 0x54;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_DACL, val);
+		snd_hda_sequence_write(codec,
+				       spec->chip_lineout_retasking_trig_verbs);
+	} else {
+		snd_hda_sequence_write(codec,
+				       spec->chip_lineout_retasking_remove_verbs);
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = (val >> 24) & 0xab;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_DACL, val);
+	}
+}
+
+static void asl051_retasking_linein(struct hda_codec *codec, int trig)
+{
+	struct cmi_spec *spec = codec->spec;
+	unsigned int val;
+
+	if (trig) {
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = (val >> 24) | 0x54;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_DACL, val);
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = ((val >> 16) & 0xff) | 0x43;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_ADCL, val);
+		snd_hda_sequence_write(codec,
+				       spec->chip_linein_retasking_trig_verbs);
+		asl051_retasking_bias1_sw(codec, 1);
+	} else {
+		val = snd_hda_codec_read(codec, 0x43, 0, 0xfa0, 0x0);
+		val = (val >> 16) & 0xbc;
+		snd_hda_codec_write(codec, 0x43, 0, CM9825_VERB_SET_ADCL, val);
+		snd_hda_sequence_write(codec,
+				       spec->chip_linein_retasking_remove_verbs);
+		asl051_retasking_bias1_sw(codec, 0);
+	}
+}
+
 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];
+	hda_nid_t hp_pin = 0x36;
 	bool hp_jack_plugin = false;
 	int err = 0;
 
@@ -126,23 +675,42 @@ static void cm9825_unsol_hp_delayed(struct work_struct *work)
 		  (int)hp_jack_plugin, hp_pin);
 
 	if (!hp_jack_plugin) {
+		spec->gen.hp_jack_present = false;
+
 		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);
+		if (spec->codec->core.subsystem_id != QUIRK_ASL051_SSID) {
+			if (spec->chip_0x36_remove_verbs) {
+				snd_hda_sequence_write(spec->codec,
+						       spec->chip_0x36_remove_verbs);
+			}
+		}
 	} else {
-		snd_hda_sequence_write(spec->codec,
-				       spec->chip_hp_present_verbs);
+		if (spec->codec->core.subsystem_id != QUIRK_ASL051_SSID) {
+			if (spec->chip_0x36_present_verbs) {
+				snd_hda_sequence_write(spec->codec,
+						       spec->chip_0x36_present_verbs);
+			}
+		}
 	}
 
 	jack = snd_hda_jack_tbl_get(spec->codec, hp_pin);
 	if (jack) {
 		jack->block_report = 0;
+		jack->jack_dirty = 1;
+		jack->gated_jack = 1;
 		snd_hda_jack_report_sync(spec->codec);
 	}
+
+	snd_hda_gen_update_outputs(spec->codec);
+
+	if (spec->playback_started)
+		if (spec->substream)
+			snd_pcm_stop_xrun(spec->substream);
 }
 
 static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
@@ -162,13 +730,256 @@ static void hp_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
 	schedule_delayed_work(&spec->unsol_hp_work, msecs_to_jiffies(200));
 }
 
+static void cm9825_unsol_line_delayed(struct work_struct *work)
+{
+	struct cmi_spec *spec =
+	    container_of(to_delayed_work(work), struct cmi_spec,
+			 unsol_line_work);
+	struct hda_jack_tbl *jack;
+	hda_nid_t lineout_pin = 0x3b;
+	bool lineout_jack_plugin = false;
+	unsigned int val = 0;
+
+	lineout_jack_plugin = snd_hda_jack_detect(spec->codec, 0x3b);
+
+	if (!lineout_jack_plugin) {
+		spec->gen.line_jack_present = false;
+		if (spec->codec->core.subsystem_id == QUIRK_ARH171_SSID) {
+			val =
+			    snd_hda_codec_read(spec->codec, 0x43, 0, 0xfa0,
+					       0x0);
+			val = (val >> 16) & 0xbc;	// adc2 off<6,1,0>=0
+			snd_hda_codec_write(spec->codec, 0x43, 0,
+					    CM9825_VERB_SET_ADCL, val);
+			val =
+			    snd_hda_codec_read(spec->codec, 0x43, 0, 0xfa4,
+					       0x0);
+			val = (val & 0xff) & 0xed;	// bias1 off<4>=0
+			snd_hda_codec_write(spec->codec, 0x43, 0,
+					    CM9825_VERB_SET_MBIAS, val);
+			if (spec->chip_0x37_remove_verbs) {
+				snd_hda_sequence_write(spec->codec,
+						       spec->chip_0x37_remove_verbs);
+			}
+		}
+	} else {
+		spec->gen.line_jack_present = true;
+		if (spec->codec->core.subsystem_id == QUIRK_ARH171_SSID) {
+			val =
+			    snd_hda_codec_read(spec->codec, 0x43, 0, 0xfa0,
+					       0x0);
+			val = ((val >> 16) & 0xff) | 0x43;	// <6,1,0>=1
+			snd_hda_codec_write(spec->codec, 0x43, 0,
+					    CM9825_VERB_SET_ADCL, val);
+			val =
+			    snd_hda_codec_read(spec->codec, 0x43, 0, 0xfa4,
+					       0x0);
+			val = (val & 0xff) | 0x10;	// BIAS1 on<4>=1
+			val = val & 0xbc;	// <6,1,0> = 0
+			snd_hda_codec_write(spec->codec, 0x43, 0,
+					    CM9825_VERB_SET_MBIAS, val);
+			if (spec->chip_0x37_present_verbs) {
+				snd_hda_sequence_write(spec->codec,
+						       spec->chip_0x37_present_verbs);
+			}
+		}
+	}
+
+	jack = snd_hda_jack_tbl_get(spec->codec, lineout_pin);
+
+	if (jack) {
+		jack->block_report = 0;
+		jack->jack_dirty = 1;
+		jack->gated_jack = 1;
+		snd_hda_jack_report_sync(spec->codec);
+	}
+
+	snd_hda_gen_update_outputs(spec->codec);
+}
+
+static void line_callback(struct hda_codec *codec, struct hda_jack_callback *cb)
+{
+	struct cmi_spec *spec = codec->spec;
+	struct hda_jack_tbl *tbl;
+
+	/* Delay enabling the lineout amp, to let the linein-detection
+	 * state machine run.
+	 */
+
+	codec_dbg(codec, "%s, cb->nid 0x%X, line%d\n", __func__,
+		  (int)cb->nid, __LINE__);
+
+	tbl = snd_hda_jack_tbl_get(codec, cb->nid);
+	if (tbl)
+		tbl->block_report = 1;
+	schedule_delayed_work(&spec->unsol_line_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];
+	hda_nid_t pin0x36 = 0x36;
+
+	snd_hda_jack_detect_enable_callback(codec, pin0x36, hp_callback);
+
+	if (codec->core.subsystem_id == QUIRK_ASL051_SSID) {
+		hda_nid_t lineout_pin = spec->gen.autocfg.line_out_pins[0];
+
+		snd_hda_jack_detect_enable_callback(codec, lineout_pin,
+						    line_callback);
+	} else if (codec->core.subsystem_id == QUIRK_ARH171_SSID
+		   || codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+		hda_nid_t linein_pin = 0x3b;
+
+		snd_hda_jack_detect_enable_callback(codec, linein_pin,
+						    line_callback);
+	}
+}
+
+static void cm9825_init_hook(struct hda_codec *codec)
+{
+	unsigned int val;
+
+	codec_dbg(codec, "init hook\n");
+
+	/* OMTP */
+	val = snd_hda_codec_read(codec, 0x46, 0, 0xfec, 0x0);
+	snd_hda_codec_write(codec, 0x46, 0, 0x7ef, (val >> 24) & 0x7f);
+
+	// link reset
+	if (codec->core.subsystem_id == QUIRK_ASL051_SSID) {
+		snd_hda_codec_write(codec, 0x3a, 0, AC_VERB_SET_CONNECT_SEL,
+				    0x02);
+		snd_hda_codec_write(codec, 0x40, 0, AC_VERB_SET_CONNECT_SEL,
+				    0x40);
+		asl051_retasking_bias1_sw(codec, 0);
+		asl051_retasking_bias2_sw(codec, 0);
+	} else if (codec->core.subsystem_id == QUIRK_ARH171_SSID) {
+		snd_hda_codec_write(codec, 0x3a, 0, AC_VERB_SET_CONNECT_SEL,
+				    0x02);
+		snd_hda_codec_write(codec, 0x40, 0, AC_VERB_SET_CONNECT_SEL,
+				    0x40);
+		snd_hda_sequence_write(codec, cm9825_arh171_tp_verbs);
+		snd_hda_sequence_write(codec, cm9825_arh171_d0_verbs);
+	} else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+		snd_hda_sequence_write(codec, cm9825_gene_twl7_d0_verbs);
+		snd_hda_codec_write(codec, 0x46, 0, CM9825_VERB_SET_P37CAP,
+				    0x20);
+	}
+}
+
+static void cm9825_playback_pcm_hook(struct hda_pcm_stream *hinfo,
+				     struct hda_codec *codec,
+				     struct snd_pcm_substream *substream,
+				     int action)
+{
+	struct cmi_spec *spec = codec->spec;
+	unsigned int val;
+
+	switch (action) {
+	case HDA_GEN_PCM_ACT_PREPARE:
+		spec->playback_started = 1;
+		spec->substream = substream;
+		if (codec->core.subsystem_id == QUIRK_ASL051_SSID) {
+			if (spec->retasking_line == 0)
+				asl051_retasking_lineout(codec, 1);
 
-	snd_hda_jack_detect_enable_callback(codec, hp_pin, hp_callback);
+			if (spec->retasking_hp == 0)
+				asl051_retasking_hp(codec, 1);
+		} else if (codec->core.subsystem_id == QUIRK_ARH171_SSID) {
+			if (!spec->gen.hp_jack_present) {
+				hinfo->nid = (hda_nid_t) 0x31;
+				snd_hda_codec_write(codec, 0x01, 0,
+						    AC_VERB_SET_GPIO_DIRECTION,
+						    0x01);
+				val =
+				    snd_hda_codec_read(codec, 0x43, 0, 0xfa0,
+						       0x0);
+				val = (val >> 24) | 0x54;	// <6,4,2>=1
+				snd_hda_codec_write(codec, 0x43, 0,
+						    CM9825_VERB_SET_DACL, val);
+				snd_hda_sequence_write(spec->codec,
+						       cm9825_arh171_spk_playback_start_verbs);
+			} else {
+				hinfo->nid = (hda_nid_t) 0x30;
+				val =
+				    snd_hda_codec_read(codec, 0x43, 0, 0xfa0,
+						       0x0);
+				val = (val >> 24) | 0xa8;	// <7,5,3>=1
+				snd_hda_codec_write(codec, 0x43, 0,
+						    CM9825_VERB_SET_DACL, val);
+				snd_hda_sequence_write(spec->codec,
+						       cm9825_arh171_hp_playback_start_verbs);
+			}
+		} else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+			snd_hda_sequence_write(spec->codec,
+					       cm9825_gene_twl7_playback_start_verbs);
+		}
+		break;
+	case HDA_GEN_PCM_ACT_CLEANUP:
+		spec->playback_started = 0;
+		if (codec->core.subsystem_id == QUIRK_ARH171_SSID) {
+			if (!spec->gen.hp_jack_present) {
+				hinfo->nid = (hda_nid_t) 0x31;
+				val =
+				    snd_hda_codec_read(codec, 0x43, 0, 0xfa0,
+						       0x0);
+				val = (val >> 24) & 0xab;	// <6,4,2>=0
+				snd_hda_codec_write(codec, 0x43, 0,
+						    CM9825_VERB_SET_DACL, val);
+				snd_hda_sequence_write(spec->codec,
+						       cm9825_arh171_spk_playback_stop_verbs);
+			} else {
+				hinfo->nid = (hda_nid_t) 0x30;
+				val =
+				    snd_hda_codec_read(codec, 0x43, 0, 0xfa0,
+						       0x0);
+				val = (val >> 24) & 0x57;	// <7,5,3>=0
+				snd_hda_codec_write(codec, 0x43, 0,
+						    CM9825_VERB_SET_DACL, val);
+				snd_hda_sequence_write(spec->codec,
+						       cm9825_arh171_hp_playback_stop_verbs);
+			}
+		} else if (codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+			snd_hda_sequence_write(spec->codec,
+					       cm9825_gene_twl7_playback_stop_verbs);
+		}
+		break;
+	default:
+		return;
+	}
+}
+
+static void cm9825_capture_pcm_hook(struct hda_pcm_stream *hinfo,
+				    struct hda_codec *codec,
+				    struct snd_pcm_substream *substream,
+				    int action)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	switch (action) {
+	case HDA_GEN_PCM_ACT_PREPARE:
+		spec->capture_started = 1;
+		if (codec->core.subsystem_id == QUIRK_ASL051_SSID) {
+			if (spec->retasking_line == 1)
+				asl051_retasking_linein(codec, 1);
+
+			if (spec->retasking_hp == 1)
+				asl051_retasking_mic(codec, 1);
+		}
+		if (codec->core.subsystem_id == QUIRK_ARH171_SSID) {
+			if (spec->chip_0x37_present_verbs)
+				snd_hda_sequence_write(spec->codec,
+						       spec->chip_0x37_present_verbs);
+		}
+		break;
+	case HDA_GEN_PCM_ACT_CLEANUP:
+		spec->capture_started = 0;
+		break;
+	default:
+		return;
+	}
 }
 
 static int cm9825_init(struct hda_codec *codec)
@@ -184,17 +995,56 @@ static void cm9825_remove(struct hda_codec *codec)
 	struct cmi_spec *spec = codec->spec;
 
 	cancel_delayed_work_sync(&spec->unsol_hp_work);
+	cancel_delayed_work_sync(&spec->unsol_line_work);
 	snd_hda_gen_remove(codec);
 }
 
+static int cm9825_ncr_resume(struct hda_codec *codec)
+{
+	snd_hda_regmap_sync(codec);
+	hda_call_check_power_status(codec, 0x01);
+
+	return 0;
+}
+
+static int cm9825_ncr_suspend(struct hda_codec *codec)
+{
+	struct cmi_spec *spec = codec->spec;
+
+	snd_hda_sequence_write(codec, spec->chip_d3_verbs);
+
+	return 0;
+}
+
 static int cm9825_suspend(struct hda_codec *codec)
 {
 	struct cmi_spec *spec = codec->spec;
 
+	if (codec->core.subsystem_id == QUIRK_NCR_SSID) {
+		cm9825_ncr_suspend(codec);
+		return 0;
+	}
+
 	cancel_delayed_work_sync(&spec->unsol_hp_work);
 
 	snd_hda_sequence_write(codec, spec->chip_d3_verbs);
 
+	if (codec->core.subsystem_id == QUIRK_ASL051_SSID) {
+		asl051_retasking_bias1_sw(codec, 0);
+		asl051_retasking_bias2_sw(codec, 0);
+
+		cancel_delayed_work_sync(&spec->unsol_line_work);
+
+		//link reset
+		snd_hda_codec_write(codec, 0x3a, 0, AC_VERB_SET_CONNECT_SEL,
+				    0x02);
+		snd_hda_codec_write(codec, 0x40, 0, AC_VERB_SET_CONNECT_SEL,
+				    0x40);
+	} else if (codec->core.subsystem_id == QUIRK_ARH171_SSID
+		   || codec->core.subsystem_id == QUIRK_GENE_TWL7_SSID) {
+		cancel_delayed_work_sync(&spec->unsol_line_work);
+	}
+
 	return 0;
 }
 
@@ -203,8 +1053,14 @@ 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;
+	bool line_jack_plugin = false;
 	int err;
 
+	if (codec->core.subsystem_id == QUIRK_NCR_SSID) {
+		cm9825_ncr_resume(codec);
+		return 0;
+	}
+
 	err =
 	    snd_hda_codec_write(spec->codec, 0x42, 0,
 				AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00);
@@ -213,7 +1069,7 @@ static int cm9825_resume(struct hda_codec *codec)
 
 	msleep(150);		/* for depop noise */
 
-	snd_hda_codec_init(codec);
+	snd_hda_sequence_write(codec, spec->chip_d0_verbs);
 
 	hp_pin = spec->gen.autocfg.hp_pins[0];
 	hp_jack_plugin = snd_hda_jack_detect(spec->codec, hp_pin);
@@ -229,7 +1085,45 @@ static int cm9825_resume(struct hda_codec *codec)
 		if (err)
 			codec_dbg(codec, "codec_write err %d\n", err);
 
-		snd_hda_sequence_write(codec, cm9825_hp_remove_verbs);
+		if (codec->core.subsystem_id != QUIRK_ASL051_SSID)
+			if (spec->chip_0x36_remove_verbs != NULL)
+				snd_hda_sequence_write(codec,
+						       spec->chip_0x36_remove_verbs);
+	}
+
+	if (codec->core.subsystem_id == QUIRK_ASL051_SSID) {
+		if (!spec->retasking_line)
+			asl051_retasking_bias1_sw(codec, 0);
+
+		if (!spec->retasking_hp)
+			asl051_retasking_bias2_sw(codec, 0);
+
+		line_jack_plugin = snd_hda_jack_detect(spec->codec, 0x3b);
+
+		if (!line_jack_plugin) {
+			if (spec->retasking_line == 1)
+				asl051_retasking_linein(spec->codec, 0);
+			else
+				asl051_retasking_lineout(spec->codec, 0);
+
+			if (spec->retasking_hp == 1)
+				asl051_retasking_mic(spec->codec, 0);
+			else
+				asl051_retasking_hp(spec->codec, 0);
+		}
+	}
+
+	if (codec->core.subsystem_id == QUIRK_ARH171_SSID) {
+		line_jack_plugin = snd_hda_jack_detect(spec->codec, 0x3b);
+
+		if (spec->chip_0x3b_present_verbs != NULL) {
+			if (line_jack_plugin)
+				snd_hda_sequence_write(codec,
+						       spec->chip_0x3b_present_verbs);
+			else
+				snd_hda_sequence_write(codec,
+						       spec->chip_0x3b_remove_verbs);
+		}
 	}
 
 	snd_hda_regmap_sync(codec);
@@ -238,11 +1132,232 @@ static int cm9825_resume(struct hda_codec *codec)
 	return 0;
 }
 
+static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
+			     unsigned int ofs)
+{
+	u32 caps = query_amp_caps(codec, nid, dir);
+	/* get num steps */
+	caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT;
+	if (ofs < caps)
+		caps -= ofs;
+	return caps;
+}
+
+static inline int
+update_amp_value(struct hda_codec *codec, hda_nid_t nid,
+		 int ch, int dir, int idx, unsigned int ofs, unsigned int val)
+{
+	unsigned int maxval;
+
+	if (val > 0)
+		val += ofs;
+	/* ofs = 0: raw max value */
+	maxval = get_amp_max_value(codec, nid, dir, 0);
+	if (val > maxval)
+		val = maxval;
+	return snd_hda_codec_amp_update(codec, nid, ch, dir, idx,
+					HDA_AMP_VOLMASK, val);
+}
+
+static int cm9825_ncr_spk_vol_put(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);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	unsigned int ofs = get_amp_offset(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change = 0;
+
+	codec_dbg(codec, "nid 0x%X, chs %d, dir %d, *valp %ld\n",
+		  nid, chs, dir, *valp);
+
+	if (chs & 1) {
+		change = update_amp_value(codec, nid, 0, dir, idx, ofs, *valp);
+		update_amp_value(codec, 0x38, 0, dir, idx, ofs, *valp);
+		valp++;
+	}
+	if (chs & 2) {
+		change |= update_amp_value(codec, nid, 1, dir, idx, ofs, *valp);
+		update_amp_value(codec, 0x38, 1, dir, idx, ofs, *valp);
+	}
+	return change;
+}
+
+static int cm9825_ncr_switch_put(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);
+	int chs = get_amp_channels(kcontrol);
+	int dir = get_amp_direction(kcontrol);
+	int idx = get_amp_index(kcontrol);
+	long *valp = ucontrol->value.integer.value;
+	int change = 0;
+
+	codec_dbg(codec, "nid 0x%X, chs %d, dir %d, *valp %ld\n",
+		  nid, chs, dir, *valp);
+
+	if (chs & 1) {
+		change = snd_hda_codec_amp_update(codec, nid, 0, dir, idx,
+						  HDA_AMP_MUTE,
+						  *valp ? 0 : HDA_AMP_MUTE);
+		snd_hda_codec_amp_update(codec, 0x38, 0, dir, idx,
+					 HDA_AMP_MUTE,
+					 *valp ? 0 : HDA_AMP_MUTE);
+		valp++;
+	}
+	if (chs & 2) {
+		change |= snd_hda_codec_amp_update(codec, nid, 1, dir, idx,
+						   HDA_AMP_MUTE,
+						   *valp ? 0 : HDA_AMP_MUTE);
+		snd_hda_codec_amp_update(codec, 0x38, 1, dir, idx,
+					 HDA_AMP_MUTE,
+					 *valp ? 0 : HDA_AMP_MUTE);
+	}
+	hda_call_check_power_status(codec, nid);
+	return change;
+}
+
+#define CM9825_NCR_CODEC_VOL(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 = cm9825_ncr_spk_vol_put, \
+	  .tlv = { .c = snd_hda_mixer_amp_tlv }, \
+	  .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
+
+#define CM9825_NCR_CODEC_MUTE(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 = snd_hda_mixer_amp_switch_get, \
+	  .put = cm9825_ncr_switch_put, \
+	  .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) }
+
+static const struct snd_kcontrol_new cm9825_ncr_mixer[] = {
+	CM9825_NCR_CODEC_VOL("Master Playback Volume", 0x3c, 3, HDA_OUTPUT),
+	CM9825_NCR_CODEC_MUTE("Master Playback Switch", 0x3c, 3, HDA_OUTPUT),
+	{}
+};
+
+static int asl051_retasking_hp_ctl_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 = 1;
+	return 0;
+}
+
+static int asl051_retasking_hp_ctl_get(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	ucontrol->value.integer.value[0] = spec->retasking_hp;
+
+	return 0;
+}
+
+static int asl051_retasking_hp_ctl_put(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	spec->retasking_hp = ucontrol->value.integer.value[0];
+
+	if (spec->retasking_hp == 1)
+		asl051_retasking_mic(codec, 1);
+	else
+		asl051_retasking_hp(codec, 1);
+
+	snd_hda_gen_update_outputs(spec->codec);
+
+	return 0;
+}
+
+static int asl051_retasking_line_ctl_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 = 1;
+	return 0;
+}
+
+static int asl051_retasking_line_ctl_get(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	ucontrol->value.integer.value[0] = spec->retasking_line;
+
+	return 0;
+}
+
+static int asl051_retasking_line_ctl_put(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_value *ucontrol)
+{
+	struct hda_codec *codec = snd_kcontrol_chip(kcontrol);
+	struct cmi_spec *spec = codec->spec;
+
+	spec->retasking_line = ucontrol->value.integer.value[0];
+
+	if (spec->retasking_line)
+		asl051_retasking_linein(codec, 1);
+	else
+		asl051_retasking_lineout(codec, 1);
+
+	snd_hda_gen_update_outputs(spec->codec);
+
+	return 0;
+}
+
+#define ASL051_RETASKING_HP_CTRL(xname) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	  .name = xname, \
+	  .subdevice = HDA_SUBDEV_NID_FLAG, \
+	  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	  .info = asl051_retasking_hp_ctl_info, \
+	  .get = asl051_retasking_hp_ctl_get, \
+	  .put = asl051_retasking_hp_ctl_put, \
+	  .private_value = AC_JACK_HP_OUT }
+
+#define ASL051_RETASKING_LINE_CTRL(xname) \
+	{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+	  .name = xname, \
+	  .subdevice = HDA_SUBDEV_NID_FLAG, \
+	  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	  .info = asl051_retasking_line_ctl_info, \
+	  .get = asl051_retasking_line_ctl_get, \
+	  .put = asl051_retasking_line_ctl_put, \
+	  .private_value = AC_JACK_LINE_OUT }
+
+static const struct snd_kcontrol_new cm9825_asl051_ctl[] = {
+	ASL051_RETASKING_HP_CTRL("ASL051 HP Retasking"),
+	ASL051_RETASKING_LINE_CTRL("ASL051 LINE Retasking"),
+	{}
+};
+
 static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
 {
 	struct cmi_spec *spec;
 	struct auto_pin_cfg *cfg;
-	int err;
+	int err, i = 0;
 
 	spec = kzalloc(sizeof(*spec), GFP_KERNEL);
 	if (spec == NULL)
@@ -252,15 +1367,179 @@ static int cm9825_probe(struct hda_codec *codec, const struct hda_device_id *id)
 	codec->spec = spec;
 	spec->codec = codec;
 	cfg = &spec->gen.autocfg;
+	spec->gen.init_hook = cm9825_init_hook;
 	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;
+	spec->chip_0x36_present_verbs = cm9825_hp_present_verbs;
+	spec->chip_0x36_remove_verbs = cm9825_hp_remove_verbs;
+
+	codec_info(codec, "subsystem_id: 0x%X\n", codec->core.subsystem_id);
+
+	switch (codec->core.subsystem_id) {
+	case QUIRK_CM_STD:
+		snd_hda_codec_set_name(codec, "CM9825 STD");
+		spec->chip_d0_verbs = cm9825_std_d0_verbs;
+		spec->chip_d3_verbs = cm9825_std_d3_verbs;
+		spec->chip_0x36_present_verbs = cm9825_hp_present_verbs;
+		spec->chip_0x36_remove_verbs = cm9825_hp_remove_verbs;
+		break;
+	case QUIRK_NCR_SSID:
+		snd_hda_codec_set_name(codec, "CM9825 NCR");
+		spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+		spec->chip_d0_verbs = cm9825_ncr_d0_verbs;
+		spec->chip_d3_verbs = cm9825_ncr_d3_verbs;
+		spec->chip_playback_start_verbs =
+		    cm9825_ncr_playback_start_verbs;
+		spec->chip_playback_stop_verbs = cm9825_ncr_playback_stop_verbs;
+
+		for (i = 0; i < ARRAY_SIZE(cm9825_ncr_mixer); i++) {
+			err = snd_hda_add_new_ctls(codec, &cm9825_ncr_mixer[i]);
+			if (err < 0) {
+				codec_info(codec, "add new ctls fail: %d\n",
+					   err);
+				goto error;
+			}
+		}
+		break;
+	case QUIRK_IBP_SSID:
+		snd_hda_codec_set_name(codec, "CM9825 IBP");
+		spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+		spec->chip_d0_verbs = cm9825_ibp_d0_verbs;
+		spec->chip_d3_verbs = cm9825_ibp_d3_verbs;
+		spec->chip_0x36_present_verbs = cm9825_ibp_hp_present_verbs;
+		spec->chip_0x36_remove_verbs = cm9825_ibp_hp_remove_verbs;
+		spec->chip_playback_start_verbs =
+		    cm9825_ibp_playback_start_verbs;
+		spec->chip_playback_stop_verbs = cm9825_ibp_playback_stop_verbs;
+		spec->gen.autocfg.hp_pins[0] =
+		    spec->gen.autocfg.line_out_pins[0];
+		break;
+	case QUIRK_ASL051_SSID:
+		snd_hda_codec_set_name(codec, "CM9825 ASL051");
+		INIT_DELAYED_WORK(&spec->unsol_line_work,
+				  cm9825_unsol_line_delayed);
+		spec->gen.suppress_vmaster = 1;
+		spec->gen.indep_hp = 1;
+		spec->gen.indep_hp_enabled = 1;
+		spec->gen.dyn_adc_switch = 1;
+		spec->gen.detect_lo = 1;
+		spec->gen.detect_hp = 1;
+		spec->gen.automute_lo = 1;
+		spec->gen.automute_speaker = 1;
+		spec->gen.multiout.hp_out_nid[0] = 0x30;
+		spec->gen.alt_dac_nid = 0x30;
+		spec->gen.multiout = asl051_multi_out;
+		spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+		spec->gen.pcm_capture_hook = cm9825_capture_pcm_hook;
+		spec->chip_d0_verbs = cm9825_asl051_d0_verbs;
+		spec->chip_d3_verbs = cm9825_asl051_d3_verbs;
+		spec->chip_lineout_retasking_trig_verbs =
+		    asl051_retasking_lineout_trig_verbs;
+		spec->chip_lineout_retasking_remove_verbs =
+		    asl051_retasking_lineout_remove_verbs;
+		spec->chip_linein_retasking_trig_verbs =
+		    asl051_retasking_linein_trig_verbs;
+		spec->chip_linein_retasking_remove_verbs =
+		    asl051_retasking_linein_remove_verbs;
+		spec->chip_hp_retasking_trig_verbs =
+		    asl051_retasking_hp_trig_verbs;
+		spec->chip_hp_retasking_remove_verbs =
+		    asl051_retasking_hp_remove_verbs;
+		spec->chip_mic_retasking_trig_verbs =
+		    asl051_retasking_mic_trig_verbs;
+		spec->chip_mic_retasking_remove_verbs =
+		    asl051_retasking_mic_remove_verbs;
+
+		for (int i = 0; i < ARRAY_SIZE(cm9825_asl051_ctl); i++) {
+			err =
+			    snd_hda_add_new_ctls(codec, &cm9825_asl051_ctl[i]);
+			if (err < 0) {
+				codec_info(codec, "add new ctls fail: %d\n",
+					   err);
+				goto error;
+			}
+		}
+
+		snd_hda_jack_set_gating_jack(codec, 0x37, 0x36);
+		snd_hda_jack_set_gating_jack(codec, 0x34, 0x3b);
+		break;
+	case QUIRK_ARH171_SSID:
+		snd_hda_codec_set_name(codec, "CM9825 ARH171");
+		INIT_DELAYED_WORK(&spec->unsol_line_work,
+				  cm9825_unsol_line_delayed);
+		spec->gen.autocfg.hp_pins[0] = 0x36;
+		spec->gen.autocfg.hp_outs = 1;
+		spec->gen.automute_speaker = 1;
+		spec->gen.autocfg.num_inputs = 1;
+		cfg->inputs[0].pin = 0x3b;
+		cfg->inputs[0].type = AUTO_PIN_MIC;
+		cfg->inputs[0].is_headphone_mic = 1;
+		hda_nid_t dac_nids[] = { 0x31 };
+
+		spec->gen.multiout.dac_nids = dac_nids;
+		spec->gen.multiout.num_dacs = 1;
+		spec->gen.multiout.hp_nid = 0x30;
+		spec->gen.indep_hp = 1;
+		spec->gen.indep_hp_enabled = 1;
+		spec->gen.out_vol_mask |= (1ULL << 0x3c) | (1ULL << 0x38);
+		spec->gen.num_adc_nids = 1;
+		spec->gen.adc_nids[0] = 0x33;
+		spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+		spec->gen.pcm_capture_hook = cm9825_capture_pcm_hook;
+		spec->chip_d0_verbs = cm9825_arh171_d0_verbs;
+		spec->chip_d3_verbs = cm9825_arh171_d3_verbs;
+		spec->chip_0x36_present_verbs = cm9825_arh171_hp_present_verbs;
+		spec->chip_0x36_remove_verbs = cm9825_arh171_hp_remove_verbs;
+		spec->chip_0x3b_present_verbs =
+		    cm9825_arh171_micin_present_verbs;
+		spec->chip_0x3b_remove_verbs = cm9825_arh171_micin_remove_verbs;
+		spec->chip_d0_verbs = cm9825_arh171_d0_verbs;
+		spec->chip_d3_verbs = cm9825_arh171_d3_verbs;
+
+		for (i = 0; i < ARRAY_SIZE(arh171_mixer); i++) {
+			err = snd_hda_add_new_ctls(codec, &arh171_mixer[i]);
+			if (err < 0) {
+				codec_info(codec, "add new ctls fail: %d\n",
+					   err);
+				goto error;
+			}
+		}
+		break;
+	case QUIRK_GENE_TWL7_SSID:
+		snd_hda_codec_set_name(codec, "CM9825 GENE_TWL7");
+		INIT_DELAYED_WORK(&spec->unsol_line_work,
+				  cm9825_unsol_line_delayed);
+		spec->gen.hp_mic = 0;
+		cfg->line_outs = 1;
+		cfg->line_out_pins[0] = 0x36;
+		cfg->line_out_type = AUTO_PIN_LINE_OUT;
+		cfg->num_inputs = 2;
+		cfg->inputs[0].pin = 0x3b;
+		cfg->inputs[0].type = AUTO_PIN_LINE_IN;
+		cfg->inputs[1].pin = 0x37;
+		cfg->inputs[1].type = AUTO_PIN_MIC;
+		cfg->inputs[1].is_headphone_mic = 1;
+		spec->chip_d0_verbs = cm9825_gene_twl7_d0_verbs;
+		spec->chip_d3_verbs = cm9825_gene_twl7_d3_verbs;
+		spec->gen.pcm_playback_hook = cm9825_playback_pcm_hook;
+		snd_hda_codec_set_pincfg(codec, 0x37, 0x24A70100);
+		break;
+	default:
+		spec->chip_d0_verbs = cm9825_std_d0_verbs;
+		spec->chip_d3_verbs = cm9825_std_d3_verbs;
+		spec->chip_0x36_present_verbs = cm9825_hp_present_verbs;
+		spec->chip_0x36_remove_verbs = cm9825_hp_remove_verbs;
+		break;
+	}
 
 	snd_hda_sequence_write(codec, spec->chip_d0_verbs);
 
-	err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0);
+	err =
+	    snd_hda_parse_pin_defcfg(codec, cfg, NULL,
+				     codec->core.subsystem_id ==
+				     QUIRK_ASL051_SSID ?
+				     HDA_PINCFG_HEADPHONE_MIC : 0);
 	if (err < 0)
 		goto error;
 	err = snd_hda_gen_parse_auto_config(codec, cfg);
@@ -297,8 +1576,9 @@ static const struct hda_codec_ops cm9825_codec_ops = {
  */
 static const struct hda_device_id snd_hda_id_cm9825[] = {
 	HDA_CODEC_ID(0x13f69825, "CM9825"),
-	{} /* terminator */
+	{}			/* terminator */
 };
+
 MODULE_DEVICE_TABLE(hdaudio, snd_hda_id_cm9825);
 
 MODULE_LICENSE("GPL");
-- 
2.34.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ