diff mbox series

[2/2] ASoC: rt712-sdca: add the function for version B

Message ID 20240620103237.2124196-1-shumingf@realtek.com (mailing list archive)
State Accepted
Commit 936abb09c1c7ce2c9c8b7838fc780e98c0140759
Headers show
Series [1/2] ASoC: rt712-sdca: change the definition name of SDCA channel number | expand

Commit Message

Shuming [θŒƒζ›ΈιŠ˜] June 20, 2024, 10:32 a.m. UTC
From: Shuming Fan <shumingf@realtek.com>

The version B will support the multi-lane function and integrate the DMIC function
in one SoundWire interface.
Due to some registers having different default values between version A and B,
this patch also removes the redundant default registers to avoid confusion.

Signed-off-by: Shuming Fan <shumingf@realtek.com>
---
 sound/soc/codecs/rt712-sdca-sdw.c |  24 +-
 sound/soc/codecs/rt712-sdca-sdw.h |  69 +---
 sound/soc/codecs/rt712-sdca.c     | 627 +++++++++++++++++++++++++++---
 sound/soc/codecs/rt712-sdca.h     |  40 ++
 4 files changed, 660 insertions(+), 100 deletions(-)

Comments

Mark Brown June 27, 2024, 11:30 a.m. UTC | #1
On Thu, 20 Jun 2024 18:32:37 +0800, shumingf@realtek.com wrote:
> The version B will support the multi-lane function and integrate the DMIC function
> in one SoundWire interface.
> Due to some registers having different default values between version A and B,
> this patch also removes the redundant default registers to avoid confusion.
> 
> 

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next

Thanks!

[2/2] ASoC: rt712-sdca: add the function for version B
      commit: 936abb09c1c7ce2c9c8b7838fc780e98c0140759

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark
diff mbox series

Patch

diff --git a/sound/soc/codecs/rt712-sdca-sdw.c b/sound/soc/codecs/rt712-sdca-sdw.c
index ecc541c5a583..90d5aaddbd5b 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.c
+++ b/sound/soc/codecs/rt712-sdca-sdw.c
@@ -34,6 +34,10 @@  static bool rt712_sdca_readable_register(struct device *dev, unsigned int reg)
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
 		SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
 	case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2:
 		return true;
 	default:
@@ -56,6 +60,10 @@  static bool rt712_sdca_volatile_register(struct device *dev, unsigned int reg)
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_GE49, RT712_SDCA_CTL_DETECTED_MODE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0) ...
 		SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01, RT712_SDCA_CTL_HIDTX_MESSAGE_LENGTH, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0):
 	case RT712_BUF_ADDR_HID1 ... RT712_BUF_ADDR_HID2:
 		return true;
 	default:
@@ -78,13 +86,21 @@  static bool rt712_sdca_mbq_readable_register(struct device *dev, unsigned int re
 	case 0x5c00000 ... 0x5c0009a:
 	case 0x5d00000 ... 0x5d00009:
 	case 0x5f00000 ... 0x5f00030:
-	case 0x6100000 ... 0x6100068:
+	case 0x6100000 ... 0x61000f1:
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_01):
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_VOLUME, CH_02):
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_01):
 	case SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04):
 		return true;
 	default:
 		return false;
@@ -96,7 +112,9 @@  static bool rt712_sdca_mbq_volatile_register(struct device *dev, unsigned int re
 	switch (reg) {
 	case 0x2000000:
 	case 0x200001a:
+	case 0x2000020:
 	case 0x2000024:
+	case 0x2000030:
 	case 0x2000046:
 	case 0x200008a:
 	case 0x5800000:
@@ -178,13 +196,15 @@  static int rt712_sdca_read_prop(struct sdw_slave *slave)
 	unsigned long addr;
 	struct sdw_dpn_prop *dpn;
 
+	sdw_slave_read_prop(slave);
+
 	prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY;
 	prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY;
 
 	prop->paging_support = true;
 
 	/* first we need to allocate memory for set bits in port lists */
-	prop->source_ports = BIT(4); /* BITMAP: 00010000 */
+	prop->source_ports = BIT(8) | BIT(4); /* BITMAP: 100010000 */
 	prop->sink_ports = BIT(3) | BIT(1); /* BITMAP:  00001010 */
 
 	nval = hweight32(prop->source_ports);
diff --git a/sound/soc/codecs/rt712-sdca-sdw.h b/sound/soc/codecs/rt712-sdca-sdw.h
index f0cb871b9fa2..99fd2d67f04d 100644
--- a/sound/soc/codecs/rt712-sdca-sdw.h
+++ b/sound/soc/codecs/rt712-sdca-sdw.h
@@ -12,49 +12,7 @@ 
 #include <linux/soundwire/sdw_registers.h>
 
 static const struct reg_default rt712_sdca_reg_defaults[] = {
-	{ 0x201a, 0x00 },
-	{ 0x201b, 0x00 },
-	{ 0x201c, 0x00 },
-	{ 0x201d, 0x00 },
-	{ 0x201e, 0x00 },
-	{ 0x201f, 0x00 },
-	{ 0x2029, 0x00 },
-	{ 0x202a, 0x00 },
-	{ 0x202d, 0x00 },
-	{ 0x202e, 0x00 },
-	{ 0x202f, 0x00 },
-	{ 0x2030, 0x00 },
-	{ 0x2031, 0x00 },
-	{ 0x2032, 0x00 },
-	{ 0x2033, 0x00 },
-	{ 0x2034, 0x00 },
-	{ 0x2230, 0x00 },
-	{ 0x2231, 0x2f },
-	{ 0x2232, 0x80 },
-	{ 0x2f01, 0x00 },
-	{ 0x2f02, 0x09 },
-	{ 0x2f03, 0x00 },
-	{ 0x2f04, 0x00 },
-	{ 0x2f05, 0x0b },
-	{ 0x2f06, 0x01 },
-	{ 0x2f08, 0x00 },
-	{ 0x2f09, 0x00 },
-	{ 0x2f0a, 0x01 },
-	{ 0x2f35, 0x01 },
-	{ 0x2f36, 0xcf },
-	{ 0x2f50, 0x0f },
-	{ 0x2f54, 0x01 },
-	{ 0x2f58, 0x07 },
-	{ 0x2f59, 0x09 },
-	{ 0x2f5a, 0x01 },
-	{ 0x2f5b, 0x07 },
-	{ 0x2f5c, 0x05 },
-	{ 0x2f5d, 0x05 },
-	{ 0x3201, 0x01 },
-	{ 0x320c, 0x00 },
-	{ 0x3301, 0x01 },
-	{ 0x3302, 0x00 },
-	{ 0x3303, 0x1f },
+
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS01, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_CS11, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU05, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
@@ -63,17 +21,22 @@  static const struct reg_default rt712_sdca_reg_defaults[] = {
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE40, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PDE12, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_03), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_04), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_PDE23, RT712_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x00 },
 };
 
 static const struct reg_default rt712_sdca_mbq_defaults[] = {
 	{ 0x2000004, 0xaa01 },
 	{ 0x200000e, 0x21e0 },
-	{ 0x2000024, 0x01ba },
 	{ 0x200004a, 0x8830 },
 	{ 0x2000067, 0xf100 },
 	{ 0x5800000, 0x1893 },
@@ -81,12 +44,8 @@  static const struct reg_default rt712_sdca_mbq_defaults[] = {
 	{ 0x5b00005, 0x0000 },
 	{ 0x5b00029, 0x3fff },
 	{ 0x5b0002a, 0xf000 },
-	{ 0x5f00008, 0x7000 },
+	{ 0x6100000, 0x04e4 },
 	{ 0x610000e, 0x0007 },
-	{ 0x6100022, 0x2828 },
-	{ 0x6100023, 0x2929 },
-	{ 0x6100026, 0x2c29 },
-	{ 0x610002c, 0x4150 },
 	{ 0x6100045, 0x0860 },
 	{ 0x6100046, 0x0029 },
 	{ 0x6100053, 0x3fff },
@@ -101,6 +60,14 @@  static const struct reg_default rt712_sdca_mbq_defaults[] = {
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_USER_FU0F, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 },
 	{ SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_PLATFORM_FU44, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_03), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_04), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_03), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_04), 0x0000 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
 };
diff --git a/sound/soc/codecs/rt712-sdca.c b/sound/soc/codecs/rt712-sdca.c
index e69e1a14fb51..e210c574bb74 100644
--- a/sound/soc/codecs/rt712-sdca.c
+++ b/sound/soc/codecs/rt712-sdca.c
@@ -82,7 +82,8 @@  static int rt712_sdca_calibration(struct rt712_sdca_priv *rt712)
 	dev = regmap_get_device(regmap);
 
 	/* Set HP-JD source from JD1 */
-	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
+	if (rt712->version_id == RT712_VA)
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
 
 	/* FSM switch to calibration manual mode */
 	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_FSM_CTL, 0x4100);
@@ -198,11 +199,17 @@  static unsigned int rt712_sdca_button_detect(struct rt712_sdca_priv *rt712)
 
 _end_btn_det_:
 	/* Host is owner, so set back to device */
-	if (owner == 0)
+	if (owner == 0) {
 		/* set owner to device */
-		regmap_write(rt712->regmap,
-			SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
-				RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+		if (rt712->version_id == RT712_VA)
+			regmap_write(rt712->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
+					RT712_SDCA_CTL_HIDTX_SET_OWNER_TO_DEVICE, 0), 0x01);
+		else
+			regmap_write(rt712->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_HID, RT712_SDCA_ENT_HID01,
+					RT712_SDCA_CTL_HIDTX_CURRENT_OWNER, 0), 0x01);
+	}
 
 	return btn_type;
 }
@@ -415,8 +422,9 @@  static void rt712_sdca_jack_init(struct rt712_sdca_priv *rt712)
 
 		switch (rt712->jd_src) {
 		case RT712_JD1:
-			/* Set HP-JD source from JD1 */
-			rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
+			/* Set HP-JD source from JD1, VB uses JD1 in default */
+			if (rt712->version_id == RT712_VA)
+				rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CC_DET1, 0x043a);
 			break;
 		default:
 			dev_warn(rt712->component->dev, "Wrong JD source\n");
@@ -854,7 +862,7 @@  static int rt712_sdca_pde12_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w,
+static int rt712_sdca_pde23_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
 	struct snd_soc_component *component =
@@ -883,9 +891,12 @@  static int rt712_sdca_classd_event(struct snd_soc_dapm_widget *w,
 	return 0;
 }
 
-static const struct snd_kcontrol_new rt712_spk_sto_dac =
-	SOC_DAPM_DOUBLE_R("Switch",
+static const struct snd_kcontrol_new rt712_spk_l_dac =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch",
 		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_01),
+		0, 1, 1);
+static const struct snd_kcontrol_new rt712_spk_r_dac =
+	SOC_DAPM_SINGLE_AUTODISABLE("Switch",
 		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_USER_FU06, RT712_SDCA_CTL_FU_MUTE, CH_02),
 		0, 1, 1);
 
@@ -931,20 +942,26 @@  static const struct snd_soc_dapm_widget rt712_sdca_spk_dapm_widgets[] = {
 	SND_SOC_DAPM_AIF_IN("DP3RX", "DP3 Playback", 0, SND_SOC_NOPM, 0, 0),
 
 	/* Digital Interface */
-	SND_SOC_DAPM_SWITCH("FU06", SND_SOC_NOPM, 0, 0, &rt712_spk_sto_dac),
+	SND_SOC_DAPM_PGA("FU06", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+	SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
+		rt712_sdca_pde23_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 	/* Output */
-	SND_SOC_DAPM_PGA_E("CLASS D", SND_SOC_NOPM, 0, 0, NULL, 0,
-		rt712_sdca_classd_event, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU),
+	SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt712_spk_l_dac),
+	SND_SOC_DAPM_SWITCH("OT23 R", SND_SOC_NOPM, 0, 0, &rt712_spk_r_dac),
 	SND_SOC_DAPM_OUTPUT("SPOL"),
 	SND_SOC_DAPM_OUTPUT("SPOR"),
 };
 
 static const struct snd_soc_dapm_route rt712_sdca_spk_dapm_routes[] = {
-	{ "FU06", "Switch", "DP3RX" },
-	{ "CLASS D", NULL, "FU06" },
-	{ "SPOL", NULL, "CLASS D" },
-	{ "SPOR", NULL, "CLASS D" },
+	{ "FU06", NULL, "DP3RX" },
+	{ "FU06", NULL, "PDE 23" },
+	{ "OT23 L", "Switch", "FU06" },
+	{ "OT23 R", "Switch", "FU06" },
+	{ "SPOL", NULL, "OT23 L" },
+	{ "SPOR", NULL, "OT23 R" },
 };
 
 static int rt712_sdca_parse_dt(struct rt712_sdca_priv *rt712, struct device *dev)
@@ -983,6 +1000,376 @@  static int rt712_sdca_probe(struct snd_soc_component *component)
 	return 0;
 }
 
+static int rt712_sdca_dmic_set_gain_get(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+	unsigned int regvalue, ctl, i;
+	unsigned int adc_vol_flag = 0;
+	const unsigned int interval_offset = 0xc0;
+
+	if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+		adc_vol_flag = 1;
+
+	/* check all channels */
+	for (i = 0; i < p->count; i++) {
+		regmap_read(rt712->mbq_regmap, p->reg_base + i, &regvalue);
+
+		if (!adc_vol_flag) /* boost gain */
+			ctl = regvalue / 0x0a00;
+		else { /* ADC gain */
+			if (adc_vol_flag)
+				ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+			else
+				ctl = p->max - (((0 - regvalue) & 0xffff) / interval_offset);
+		}
+
+		ucontrol->value.integer.value[i] = ctl;
+	}
+
+	return 0;
+}
+
+static int rt712_sdca_dmic_set_gain_put(struct snd_kcontrol *kcontrol,
+		struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	unsigned int gain_val[4];
+	unsigned int i, adc_vol_flag = 0, changed = 0;
+	unsigned int regvalue[4];
+	const unsigned int interval_offset = 0xc0;
+	int err;
+
+	if (strstr(ucontrol->id.name, "FU1E Capture Volume"))
+		adc_vol_flag = 1;
+
+	/* check all channels */
+	for (i = 0; i < p->count; i++) {
+		regmap_read(rt712->mbq_regmap, p->reg_base + i, &regvalue[i]);
+
+		gain_val[i] = ucontrol->value.integer.value[i];
+		if (gain_val[i] > p->max)
+			gain_val[i] = p->max;
+
+		if (!adc_vol_flag) /* boost gain */
+			gain_val[i] = gain_val[i] * 0x0a00;
+		else { /* ADC gain */
+			gain_val[i] = 0x1e00 - ((p->max - gain_val[i]) * interval_offset);
+			gain_val[i] &= 0xffff;
+		}
+
+		if (regvalue[i] != gain_val[i])
+			changed = 1;
+	}
+
+	if (!changed)
+		return 0;
+
+	for (i = 0; i < p->count; i++) {
+		err = regmap_write(rt712->mbq_regmap, p->reg_base + i, gain_val[i]);
+		if (err < 0)
+			dev_err(&rt712->slave->dev, "0x%08x can't be set\n", p->reg_base + i);
+	}
+
+	return changed;
+}
+
+static int rt712_sdca_set_fu1e_capture_ctl(struct rt712_sdca_priv *rt712)
+{
+	int err, i;
+	unsigned int ch_mute;
+
+	for (i = 0; i < ARRAY_SIZE(rt712->fu1e_mixer_mute); i++) {
+		ch_mute = (rt712->fu1e_dapm_mute || rt712->fu1e_mixer_mute[i]) ? 0x01 : 0x00;
+		err = regmap_write(rt712->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E,
+				RT712_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rt712_sdca_dmic_fu1e_capture_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+	unsigned int i;
+
+	for (i = 0; i < p->count; i++)
+		ucontrol->value.integer.value[i] = !rt712->fu1e_mixer_mute[i];
+
+	return 0;
+}
+
+static int rt712_sdca_dmic_fu1e_capture_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+	int err, changed = 0, i;
+
+	for (i = 0; i < p->count; i++) {
+		if (rt712->fu1e_mixer_mute[i] != !ucontrol->value.integer.value[i])
+			changed = 1;
+		rt712->fu1e_mixer_mute[i] = !ucontrol->value.integer.value[i];
+	}
+
+	err = rt712_sdca_set_fu1e_capture_ctl(rt712);
+	if (err < 0)
+		return err;
+
+	return changed;
+}
+
+static int rt712_sdca_fu_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct rt712_dmic_kctrl_priv *p =
+		(struct rt712_dmic_kctrl_priv *)kcontrol->private_value;
+
+	if (p->max == 1)
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+	else
+		uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = p->count;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = p->max;
+	return 0;
+}
+
+#define RT712_SDCA_PR_VALUE(xreg_base, xcount, xmax, xinvert) \
+	((unsigned long)&(struct rt712_dmic_kctrl_priv) \
+		{.reg_base = xreg_base, .count = xcount, .max = xmax, \
+		.invert = xinvert})
+
+#define RT712_SDCA_FU_CTRL(xname, reg_base, xmax, xinvert, xcount) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.info = rt712_sdca_fu_info, \
+	.get = rt712_sdca_dmic_fu1e_capture_get, \
+	.put = rt712_sdca_dmic_fu1e_capture_put, \
+	.private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, xinvert)}
+
+#define RT712_SDCA_EXT_TLV(xname, reg_base, xhandler_get,\
+	 xhandler_put, xcount, xmax, tlv_array) \
+{	.iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname), \
+	.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+		 SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+	.tlv.p = (tlv_array), \
+	.info = rt712_sdca_fu_info, \
+	.get = xhandler_get, .put = xhandler_put, \
+	.private_value = RT712_SDCA_PR_VALUE(reg_base, xcount, xmax, 0) }
+
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
+static const DECLARE_TLV_DB_SCALE(dmic_vol_tlv, 0, 1000, 0);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_snd_controls[] = {
+	RT712_SDCA_FU_CTRL("FU1E Capture Switch",
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_MUTE, CH_01),
+		1, 1, 4),
+	RT712_SDCA_EXT_TLV("FU1E Capture Volume",
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_USER_FU1E, RT712_SDCA_CTL_FU_VOLUME, CH_01),
+		rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 0x3f, in_vol_tlv),
+	RT712_SDCA_EXT_TLV("FU15 Boost Volume",
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PLATFORM_FU15, RT712_SDCA_CTL_FU_CH_GAIN, CH_01),
+		rt712_sdca_dmic_set_gain_get, rt712_sdca_dmic_set_gain_put, 4, 3, dmic_vol_tlv),
+};
+
+static int rt712_sdca_dmic_mux_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_kcontrol_component(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	unsigned int val = 0, mask_sft;
+
+	if (strstr(ucontrol->id.name, "ADC 0A Mux"))
+		mask_sft = 0;
+	else if (strstr(ucontrol->id.name, "ADC 0B Mux"))
+		mask_sft = 4;
+	else
+		return -EINVAL;
+
+	rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL,
+		RT712_HDA_LEGACY_MUX_CTL0, &val);
+
+	ucontrol->value.enumerated.item[0] = (((val >> mask_sft) & 0xf) == 0x4) ? 0 : 1;
+
+	return 0;
+}
+
+static int rt712_sdca_dmic_mux_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_kcontrol_component(kcontrol);
+	struct snd_soc_dapm_context *dapm =
+		snd_soc_dapm_kcontrol_dapm(kcontrol);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+	unsigned int *item = ucontrol->value.enumerated.item;
+	unsigned int val, val2 = 0, change, mask_sft;
+
+	if (item[0] >= e->items)
+		return -EINVAL;
+
+	if (strstr(ucontrol->id.name, "ADC 0A Mux"))
+		mask_sft = 0;
+	else if (strstr(ucontrol->id.name, "ADC 0B Mux"))
+		mask_sft = 4;
+	else
+		return -EINVAL;
+
+	val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+
+	rt712_sdca_index_read(rt712, RT712_VENDOR_HDA_CTL,
+		RT712_HDA_LEGACY_MUX_CTL0, &val2);
+	val2 = ((0xf << mask_sft) & val2) >> mask_sft;
+
+	if (val == 0)
+		val = 0x4;
+	else if (val >= 1)
+		val = 0xe;
+
+	if (val == val2)
+		change = 0;
+	else
+		change = 1;
+
+	if (change)
+		rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL,
+			RT712_HDA_LEGACY_MUX_CTL0, 0xf << mask_sft,
+			val << mask_sft);
+
+	snd_soc_dapm_mux_update_power(dapm, kcontrol, item[0], e, NULL);
+
+	return change;
+}
+
+static const char * const adc_dmic_mux_text[] = {
+	"DMIC1",
+	"DMIC2",
+};
+
+static SOC_ENUM_SINGLE_DECL(
+	rt712_adc0a_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text);
+
+static SOC_ENUM_SINGLE_DECL(
+	rt712_adc0b_enum, SND_SOC_NOPM, 0, adc_dmic_mux_text);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_adc0a_mux =
+	SOC_DAPM_ENUM_EXT("ADC 0A Mux", rt712_adc0a_enum,
+			rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put);
+
+static const struct snd_kcontrol_new rt712_sdca_dmic_adc0b_mux =
+	SOC_DAPM_ENUM_EXT("ADC 0B Mux", rt712_adc0b_enum,
+			rt712_sdca_dmic_mux_get, rt712_sdca_dmic_mux_put);
+
+static int rt712_sdca_dmic_fu1e_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		rt712->fu1e_dapm_mute = false;
+		rt712_sdca_set_fu1e_capture_ctl(rt712);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		rt712->fu1e_dapm_mute = true;
+		rt712_sdca_set_fu1e_capture_ctl(rt712);
+		break;
+	}
+	return 0;
+}
+
+static int rt712_sdca_dmic_pde11_event(struct snd_soc_dapm_widget *w,
+	struct snd_kcontrol *kcontrol, int event)
+{
+	struct snd_soc_component *component =
+		snd_soc_dapm_to_component(w->dapm);
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	unsigned char ps0 = 0x0, ps3 = 0x3;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11,
+				RT712_SDCA_CTL_REQ_POWER_STATE, 0),
+				ps0);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_PDE11,
+				RT712_SDCA_CTL_REQ_POWER_STATE, 0),
+				ps3);
+		break;
+	}
+	return 0;
+}
+
+static const struct snd_soc_dapm_widget rt712_sdca_dmic_dapm_widgets[] = {
+	SND_SOC_DAPM_INPUT("DMIC1"),
+	SND_SOC_DAPM_INPUT("DMIC2"),
+
+	SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+		rt712_sdca_dmic_pde11_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+	SND_SOC_DAPM_ADC_E("FU 1E", NULL, SND_SOC_NOPM, 0, 0,
+		rt712_sdca_dmic_fu1e_event,
+		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_MUX("ADC 0A Mux", SND_SOC_NOPM, 0, 0,
+		&rt712_sdca_dmic_adc0a_mux),
+	SND_SOC_DAPM_MUX("ADC 0B Mux", SND_SOC_NOPM, 0, 0,
+		&rt712_sdca_dmic_adc0b_mux),
+
+	SND_SOC_DAPM_AIF_OUT("DP8TX", "DP8 Capture", 0, SND_SOC_NOPM, 0, 0),
+};
+
+static const struct snd_soc_dapm_route rt712_sdca_dmic_audio_map[] = {
+	{"DP8TX", NULL, "FU 1E"},
+
+	{"FU 1E", NULL, "PDE 11"},
+	{"FU 1E", NULL, "ADC 0A Mux"},
+	{"FU 1E", NULL, "ADC 0B Mux"},
+	{"ADC 0A Mux", "DMIC1", "DMIC1"},
+	{"ADC 0A Mux", "DMIC2", "DMIC2"},
+	{"ADC 0B Mux", "DMIC1", "DMIC1"},
+	{"ADC 0B Mux", "DMIC2", "DMIC2"},
+};
+
+static int rt712_sdca_dmic_probe(struct snd_soc_component *component)
+{
+	struct rt712_sdca_priv *rt712 = snd_soc_component_get_drvdata(component);
+	int ret;
+
+	rt712->dmic_component = component;
+
+	if (!rt712->first_hw_init)
+		return 0;
+
+	ret = pm_runtime_resume(component->dev);
+	if (ret < 0 && ret != -EACCES)
+		return ret;
+
+	return 0;
+}
+
 static const struct snd_soc_component_driver soc_sdca_dev_rt712 = {
 	.probe = rt712_sdca_probe,
 	.controls = rt712_sdca_controls,
@@ -995,6 +1382,20 @@  static const struct snd_soc_component_driver soc_sdca_dev_rt712 = {
 	.endianness = 1,
 };
 
+static const struct snd_soc_component_driver soc_sdca_dev_rt712_dmic = {
+	.probe = rt712_sdca_dmic_probe,
+	.controls = rt712_sdca_dmic_snd_controls,
+	.num_controls = ARRAY_SIZE(rt712_sdca_dmic_snd_controls),
+	.dapm_widgets = rt712_sdca_dmic_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rt712_sdca_dmic_dapm_widgets),
+	.dapm_routes = rt712_sdca_dmic_audio_map,
+	.num_dapm_routes = ARRAY_SIZE(rt712_sdca_dmic_audio_map),
+	.endianness = 1,
+#ifdef CONFIG_DEBUG_FS
+	.debugfs_prefix = "dmic",
+#endif
+};
+
 static int rt712_sdca_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
 				int direction)
 {
@@ -1022,7 +1423,7 @@  static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
 	int retval, port, num_channels;
 	unsigned int sampling_rate;
 
-	dev_dbg(dai->dev, "%s %s", __func__, dai->name);
+	dev_dbg(dai->dev, "%s %s id %d", __func__, dai->name, dai->id);
 	sdw_stream = snd_soc_dai_get_dma_data(dai, substream);
 
 	if (!sdw_stream)
@@ -1031,6 +1432,10 @@  static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
 	if (!rt712->slave)
 		return -EINVAL;
 
+	/* VA doesn't support AIF3 */
+	if (dai->id == RT712_AIF3 && rt712->version_id == RT712_VA)
+		return -EINVAL;
+
 	/* SoundWire specific configuration */
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 		direction = SDW_DATA_DIR_RX;
@@ -1044,6 +1449,8 @@  static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
 		direction = SDW_DATA_DIR_TX;
 		if (dai->id == RT712_AIF1)
 			port = 4;
+		else if (dai->id == RT712_AIF3)
+			port = 8;
 		else
 			return -EINVAL;
 	}
@@ -1105,6 +1512,14 @@  static int rt712_sdca_pcm_hw_params(struct snd_pcm_substream *substream,
 			SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_CS31, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
 			sampling_rate);
 		break;
+	case RT712_AIF3:
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1F, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+			sampling_rate);
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_CS1C, RT712_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+			sampling_rate);
+		break;
 	default:
 		dev_err(component->dev, "%s: Wrong DAI id\n", __func__);
 		return -EINVAL;
@@ -1174,6 +1589,21 @@  static struct snd_soc_dai_driver rt712_sdca_dai[] = {
 	}
 };
 
+static struct snd_soc_dai_driver rt712_sdca_dmic_dai[] = {
+	{
+		.name = "rt712-sdca-aif3",
+		.id = RT712_AIF3,
+		.capture = {
+			.stream_name = "DP8 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = RT712_STEREO_RATES,
+			.formats = RT712_FORMATS,
+		},
+		.ops = &rt712_sdca_ops,
+	}
+};
+
 int rt712_sdca_init(struct device *dev, struct regmap *regmap,
 			struct regmap *mbq_regmap, struct sdw_slave *slave)
 {
@@ -1206,6 +1636,9 @@  int rt712_sdca_init(struct device *dev, struct regmap *regmap,
 	rt712->first_hw_init = false;
 	rt712->fu0f_dapm_mute = true;
 	rt712->fu0f_mixer_l_mute = rt712->fu0f_mixer_r_mute = true;
+	rt712->fu1e_dapm_mute = true;
+	rt712->fu1e_mixer_mute[0] = rt712->fu1e_mixer_mute[1] =
+		rt712->fu1e_mixer_mute[2] = rt712->fu1e_mixer_mute[3] = true;
 
 	/* JD source uses JD1 in default */
 	rt712->jd_src = RT712_JD1;
@@ -1239,35 +1672,11 @@  int rt712_sdca_init(struct device *dev, struct regmap *regmap,
 	return 0;
 }
 
-int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+static void rt712_sdca_va_io_init(struct rt712_sdca_priv *rt712)
 {
-	struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
 	int ret = 0;
-	unsigned int val, hibernation_flag;
-
-	rt712->disable_irq = false;
-
-	if (rt712->hw_init)
-		return 0;
-
-	regcache_cache_only(rt712->regmap, false);
-	regcache_cache_only(rt712->mbq_regmap, false);
-	if (rt712->first_hw_init) {
-		regcache_cache_bypass(rt712->regmap, true);
-		regcache_cache_bypass(rt712->mbq_regmap, true);
-	} else {
-		/*
-		 *  PM runtime status is marked as 'active' only when a Slave reports as Attached
-		 */
-
-		/* update count of parent 'active' children */
-		pm_runtime_set_active(&slave->dev);
-	}
-
-	pm_runtime_get_noresume(&slave->dev);
-
-	rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val);
-	rt712->hw_id = (val & 0xf000) >> 12;
+	unsigned int hibernation_flag;
+	struct device *dev = &rt712->slave->dev;
 
 	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81);
 	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0);
@@ -1307,6 +1716,131 @@  int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
 		regmap_write(rt712->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04);
 	}
+}
+
+static void rt712_sdca_vb_io_init(struct rt712_sdca_priv *rt712)
+{
+	int ret = 0;
+	unsigned int jack_func_status, mic_func_status, amp_func_status;
+	struct device *dev = &rt712->slave->dev;
+
+	regmap_read(rt712->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &jack_func_status);
+	regmap_read(rt712->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &mic_func_status);
+	regmap_read(rt712->regmap,
+		SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0), &amp_func_status);
+	dev_dbg(dev, "%s jack/mic/amp func_status=0x%x, 0x%x, 0x%x\n",
+		__func__, jack_func_status, mic_func_status, amp_func_status);
+
+	/* DMIC */
+	if ((mic_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_IT_FLOAT_CTL, 0x1526);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_DMIC2_FU_CH12_FLOAT_CTL, 0x0304);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL, 0x1f1e);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_ADC0B_FU_CH12_FLOAT_CTL, 0x0304);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_HDA_LEGACY_CONFIG_CTL0, 0x8010);
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT_IT11, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+		rt712_sdca_index_write(rt712, RT712_ULTRA_SOUND_DET, RT712_ULTRA_SOUND_DETECTOR6, 0x3200);
+		regmap_write(rt712->regmap, RT712_RC_CAL, 0x23);
+
+		/* clear flag */
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC_ARRAY, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+				FUNCTION_NEEDS_INITIALIZATION);
+	}
+
+	/* Jack */
+	if ((jack_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+		rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_SEL_VEE2_HP_CTL1, 0x042a);
+		rt712_sdca_index_write(rt712, RT712_CHARGE_PUMP, RT712_HP_DET_CTL3, 0x1fff);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec67);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_ANALOG_BIAS_CTL3, 0xaa81);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_LDO2_3_CTL1, 0xa1e0);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL1, 0x0000);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_IMS_DRE, RT712_HP_DETECT_RLDET_CTL2, 0x0000);
+		regmap_write(rt712->regmap, RT712_RC_CAL, 0x23);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_JD_CTL1, 0x2802);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL6, 0xf215);
+
+		/* calibration */
+		ret = rt712_sdca_calibration(rt712);
+		if (ret < 0)
+			dev_err(dev, "%s, calibration failed!\n", __func__);
+
+		rt712_sdca_index_update_bits(rt712, RT712_VENDOR_HDA_CTL, RT712_MIXER_CTL1, 0x3000, 0x0000);
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT_IT09, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x01);
+		rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_MISC_CTL_FOR_UAJ, 0x0003);
+
+		/* clear flag */
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_JACK_CODEC, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+				FUNCTION_NEEDS_INITIALIZATION);
+	}
+
+	/* SPK */
+	if ((amp_func_status & FUNCTION_NEEDS_INITIALIZATION) || (!rt712->first_hw_init)) {
+		if (rt712->hw_id != RT712_DEV_ID_713) {
+			rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_IO_CTL, 0xec63);
+			rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_CLASSD_AMP_CTL1, 0xfff5);
+			rt712_sdca_index_write(rt712, RT712_VENDOR_HDA_CTL, RT712_EAPD_CTL, 0x0002);
+			regmap_write(rt712->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT_OT23, RT712_SDCA_CTL_VENDOR_DEF, 0), 0x04);
+		}
+		/* clear flag */
+		regmap_write(rt712->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT712_SDCA_ENT0, RT712_SDCA_CTL_FUNC_STATUS, 0),
+				FUNCTION_NEEDS_INITIALIZATION);
+	}
+}
+
+int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
+{
+	struct rt712_sdca_priv *rt712 = dev_get_drvdata(dev);
+	int ret = 0;
+	unsigned int val;
+	struct sdw_slave_prop *prop = &slave->prop;
+
+	rt712->disable_irq = false;
+
+	if (rt712->hw_init)
+		return 0;
+
+	regcache_cache_only(rt712->regmap, false);
+	regcache_cache_only(rt712->mbq_regmap, false);
+	if (rt712->first_hw_init) {
+		regcache_cache_bypass(rt712->regmap, true);
+		regcache_cache_bypass(rt712->mbq_regmap, true);
+	} else {
+		/*
+		 *  PM runtime status is marked as 'active' only when a Slave reports as Attached
+		 */
+
+		/* update count of parent 'active' children */
+		pm_runtime_set_active(&slave->dev);
+	}
+
+	pm_runtime_get_noresume(&slave->dev);
+
+	rt712_sdca_index_read(rt712, RT712_VENDOR_REG, RT712_JD_PRODUCT_NUM, &val);
+	rt712->hw_id = (val & 0xf000) >> 12;
+	rt712->version_id = (val & 0x0f00) >> 8;
+	dev_dbg(&slave->dev, "%s hw_id=0x%x, version_id=0x%x\n", __func__, rt712->hw_id, rt712->version_id);
+
+	if (rt712->version_id == RT712_VA)
+		rt712_sdca_va_io_init(rt712);
+	else {
+		/* multilanes and DMIC are supported by rt712vb */
+		ret =  devm_snd_soc_register_component(dev,
+			&soc_sdca_dev_rt712_dmic, rt712_sdca_dmic_dai, ARRAY_SIZE(rt712_sdca_dmic_dai));
+		if (ret < 0)
+			return ret;
+
+		prop->lane_control_support = true;
+		rt712_sdca_vb_io_init(rt712);
+	}
 
 	/*
 	 * if set_jack callback occurred early than io_init,
@@ -1315,8 +1849,7 @@  int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave)
 	if (rt712->hs_jack)
 		rt712_sdca_jack_init(rt712);
 
-	if (!hibernation_flag)
-		rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001);
+	rt712_sdca_index_write(rt712, RT712_VENDOR_REG, RT712_SW_CONFIG1, 0x0001);
 
 	if (rt712->first_hw_init) {
 		regcache_cache_bypass(rt712->regmap, false);
diff --git a/sound/soc/codecs/rt712-sdca.h b/sound/soc/codecs/rt712-sdca.h
index bf462a837c0d..2169f2f726b9 100644
--- a/sound/soc/codecs/rt712-sdca.h
+++ b/sound/soc/codecs/rt712-sdca.h
@@ -19,6 +19,7 @@  struct  rt712_sdca_priv {
 	struct regmap *regmap;
 	struct regmap *mbq_regmap;
 	struct snd_soc_component *component;
+	struct snd_soc_component *dmic_component;
 	struct sdw_slave *slave;
 	struct sdw_bus_params params;
 	bool hw_init;
@@ -34,9 +35,19 @@  struct  rt712_sdca_priv {
 	unsigned int scp_sdca_stat1;
 	unsigned int scp_sdca_stat2;
 	unsigned int hw_id;
+	unsigned int version_id;
 	bool fu0f_dapm_mute;
 	bool fu0f_mixer_l_mute;
 	bool fu0f_mixer_r_mute;
+	bool fu1e_dapm_mute;
+	bool fu1e_mixer_mute[4];
+};
+
+struct rt712_dmic_kctrl_priv {
+	unsigned int reg_base;
+	unsigned int count;
+	unsigned int max;
+	unsigned int invert;
 };
 
 /* SDCA (Channel) */
@@ -47,6 +58,8 @@  struct  rt712_sdca_priv {
 
 /* NID */
 #define RT712_VENDOR_REG			0x20
+#define RT712_EQ_CTRL				0x53
+#define RT712_CHARGE_PUMP			0x57
 #define RT712_VENDOR_CALI			0x58
 #define RT712_ULTRA_SOUND_DET			0x59
 #define RT712_VENDOR_IMS_DRE			0x5b
@@ -56,9 +69,13 @@  struct  rt712_sdca_priv {
 /* Index (NID:20h) */
 #define RT712_JD_PRODUCT_NUM			0x00
 #define RT712_ANALOG_BIAS_CTL3			0x04
+#define RT712_JD_CTL1				0x09
+#define RT712_IO_CTL				0x0c
 #define RT712_LDO2_3_CTL1			0x0e
 #define RT712_PARA_VERB_CTL			0x1a
 #define RT712_CC_DET1				0x24
+#define RT712_CLASSD_AMP_CTL1			0x37
+#define RT712_CLASSD_AMP_CTL6			0x3c
 #define RT712_COMBO_JACK_AUTO_CTL1		0x45
 #define RT712_COMBO_JACK_AUTO_CTL2		0x46
 #define RT712_COMBO_JACK_AUTO_CTL3		0x47
@@ -67,6 +84,9 @@  struct  rt712_sdca_priv {
 #define RT712_SW_CONFIG1			0x8a
 #define RT712_SW_CONFIG2			0x8b
 
+/* Index (NID:57h) */
+#define RT712_HP_DET_CTL3			0x0c
+
 /* Index (NID:58h) */
 #define RT712_DAC_DC_CALI_CTL1			0x00
 #define RT712_DAC_DC_CALI_CTL2			0x01
@@ -77,6 +97,7 @@  struct  rt712_sdca_priv {
 /* Index (NID:5bh) */
 #define RT712_IMS_DIGITAL_CTL1			0x00
 #define RT712_IMS_DIGITAL_CTL5			0x05
+#define RT712_SEL_VEE2_HP_CTL1			0x23
 #define RT712_HP_DETECT_RLDET_CTL1		0x29
 #define RT712_HP_DETECT_RLDET_CTL2		0x2a
 
@@ -115,6 +136,11 @@  struct  rt712_sdca_priv {
 #define RT712_UMP_HID_CTL6				0x66
 #define RT712_UMP_HID_CTL7				0x67
 #define RT712_UMP_HID_CTL8				0x68
+#define RT712_MISC_CTL_FOR_UAJ				0x72
+#define RT712_ADC0A_CS_ADC0B_FU_FLOAT_CTL		0xa2
+#define RT712_DMIC2_FU_IT_FLOAT_CTL			0xa6
+#define RT712_ADC0B_FU_CH12_FLOAT_CTL			0xb0
+#define RT712_DMIC2_FU_CH12_FLOAT_CTL			0xb1
 
 /* Parameter & Verb control 01 (0x1a)(NID:20h) */
 #define RT712_HIDDEN_REG_SW_RESET (0x1 << 14)
@@ -145,6 +171,7 @@  struct  rt712_sdca_priv {
 #define FUNC_NUM_AMP 0x04
 
 /* RT712 SDCA entity */
+#define RT712_SDCA_ENT0 0x00
 #define RT712_SDCA_ENT_HID01 0x01
 #define RT712_SDCA_ENT_GE49 0x49
 #define RT712_SDCA_ENT_USER_FU05 0x05
@@ -163,6 +190,7 @@  struct  rt712_sdca_priv {
 #define RT712_SDCA_ENT_CS1C 0x1c
 #define RT712_SDCA_ENT_CS31 0x31
 #define RT712_SDCA_ENT_OT23 0x42
+#define RT712_SDCA_ENT_IT11 0x26
 #define RT712_SDCA_ENT_IT26 0x26
 #define RT712_SDCA_ENT_IT09 0x09
 #define RT712_SDCA_ENT_PLATFORM_FU15 0x15
@@ -181,6 +209,12 @@  struct  rt712_sdca_priv {
 #define RT712_SDCA_CTL_REQ_POWER_STATE 0x01
 #define RT712_SDCA_CTL_VENDOR_DEF 0x30
 #define RT712_SDCA_CTL_FU_CH_GAIN 0x0b
+#define RT712_SDCA_CTL_FUNC_STATUS 0x10
+
+/* Function_Status */
+#define FUNCTION_NEEDS_INITIALIZATION		BIT(5)
+#define FUNCTION_HAS_BEEN_RESET			BIT(6)
+#define FUNCTION_BUSY				BIT(7)
 
 /* sample frequency index */
 #define RT712_SDCA_RATE_16000HZ		0x04
@@ -193,6 +227,7 @@  struct  rt712_sdca_priv {
 enum {
 	RT712_AIF1,
 	RT712_AIF2,
+	RT712_AIF3,
 };
 
 enum rt712_sdca_jd_src {
@@ -209,6 +244,11 @@  enum rt712_sdca_hw_id {
 
 #define RT712_PART_ID_713 0x713
 
+enum rt712_sdca_version {
+	RT712_VA,
+	RT712_VB,
+};
+
 int rt712_sdca_io_init(struct device *dev, struct sdw_slave *slave);
 int rt712_sdca_init(struct device *dev, struct regmap *regmap,
 			struct regmap *mbq_regmap, struct sdw_slave *slave);