diff mbox series

ASoC: rt1320: add mic function

Message ID 20241025081259.1419518-1-shumingf@realtek.com (mailing list archive)
State Accepted
Commit 20079dd9b364483db613186b289fe372bddf41b5
Headers show
Series ASoC: rt1320: add mic function | expand

Commit Message

Shuming [θŒƒζ›ΈιŠ˜] Oct. 25, 2024, 8:12 a.m. UTC
From: Shuming Fan <shumingf@realtek.com>

This patch adds the mic function.

Signed-off-by: Shuming Fan <shumingf@realtek.com>
---
 sound/soc/codecs/rt1320-sdw.c | 323 ++++++++++++++++++++++++++++++++--
 sound/soc/codecs/rt1320-sdw.h |   4 +
 2 files changed, 313 insertions(+), 14 deletions(-)

Comments

Mark Brown Oct. 25, 2024, 3:48 p.m. UTC | #1
On Fri, 25 Oct 2024 16:12:59 +0800, shumingf@realtek.com wrote:
> This patch adds the mic function.
> 
> 

Applied to

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

Thanks!

[1/1] ASoC: rt1320: add mic function
      commit: 20079dd9b364483db613186b289fe372bddf41b5

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/rt1320-sdw.c b/sound/soc/codecs/rt1320-sdw.c
index ebd6f09bd990..3510c3819074 100644
--- a/sound/soc/codecs/rt1320-sdw.c
+++ b/sound/soc/codecs/rt1320-sdw.c
@@ -21,6 +21,7 @@ 
 #include <sound/tlv.h>
 #include <sound/sdw.h>
 #include "rt1320-sdw.h"
+#include "rt-sdw-common.h"
 
 /*
  * The 'blind writes' is an SDCA term to deal with platform-specific initialization.
@@ -106,6 +107,8 @@  static const struct reg_sequence rt1320_blind_write[] = {
 	{ 0x1000db09, 0x00 },
 	{ 0x1000db0a, 0x40 },
 	{ 0x0000d540, 0x01 },
+	{ 0xd172, 0x2a },
+	{ 0xc5d6, 0x01 },
 };
 
 static const struct reg_sequence rt1320_vc_blind_write[] = {
@@ -225,22 +228,41 @@  static const struct reg_sequence rt1320_vc_blind_write[] = {
 	{ 0x0000d540, 0x01 },
 	{ 0x0000c081, 0xfc },
 	{ 0x0000f01e, 0x80 },
+	{ 0xc01b, 0xfc },
+	{ 0xc5d1, 0x89 },
+	{ 0xc5d8, 0x0a },
+	{ 0xc5f7, 0x22 },
+	{ 0xc5f6, 0x22 },
+	{ 0xc065, 0xa5 },
+	{ 0xc06b, 0x0a },
+	{ 0xd172, 0x2a },
+	{ 0xc5d6, 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 };
 
 static const struct reg_default rt1320_reg_defaults[] = {
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02), 0x01 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE27, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0), 0x03 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PPU21, RT1320_SDCA_CTL_POSTURE_NUMBER, 0), 0x00 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
-	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x0b },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0), 0x09 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), 0x03 },
 };
 
 static const struct reg_default rt1320_mbq_defaults[] = {
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
+	{ SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01), 0x0000 },
 	{ SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02), 0x0000 },
 };
@@ -306,6 +328,17 @@  static bool rt1320_readable_register(struct device *dev, unsigned int reg)
 	case 0x1000f021:
 	case 0x3fe2e000 ... 0x3fe2e003:
 	case 0x3fc2ab80 ... 0x3fc2abd4:
+	/* 0x40801508/0x40801809/0x4080180a/0x40801909/0x4080190a */
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_REQ_POWER_STATE, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_MUTE, CH_02):
+	/* 0x40880900/0x40880980 */
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0):
+	/* 0x40881500 */
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
 	/* 0x41000189/0x4100018a */
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_01):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_MUTE, CH_02):
@@ -388,6 +421,7 @@  static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
 	case 0x3fc2bf80 ... 0x3fc2bf83:
 	case 0x3fc2bfc0 ... 0x3fc2bfc7:
 	case 0x3fe2e000 ... 0x3fe2e003:
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT0, RT1320_SDCA_CTL_FUNC_STATUS, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_MODE, 0):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_SAPU, RT1320_SDCA_CTL_SAPU_PROTECTION_STATUS, 0):
@@ -401,6 +435,10 @@  static bool rt1320_volatile_register(struct device *dev, unsigned int reg)
 static bool rt1320_mbq_readable_register(struct device *dev, unsigned int reg)
 {
 	switch (reg) {
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
+	case SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_01):
 	case SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02):
 		return true;
@@ -456,7 +494,7 @@  static int rt1320_read_prop(struct sdw_slave *slave)
 	prop->lane_control_support = true;
 
 	/* first we need to allocate memory for set bits in port lists */
-	prop->source_ports = BIT(4);
+	prop->source_ports = BIT(4) | BIT(8) | BIT(10);
 	prop->sink_ports = BIT(1);
 
 	nval = hweight32(prop->source_ports);
@@ -500,7 +538,8 @@  static int rt1320_read_prop(struct sdw_slave *slave)
 	return 0;
 }
 
-static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char ps)
+static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned char func,
+	unsigned char entity, unsigned char ps)
 {
 	unsigned int delay = 1000, val;
 
@@ -509,8 +548,7 @@  static int rt1320_pde_transition_delay(struct rt1320_sdw_priv *rt1320, unsigned
 	/* waiting for Actual PDE becomes to PS0/PS3 */
 	while (delay) {
 		regmap_read(rt1320->regmap,
-			SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
-			RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val);
+			SDW_SDCA_CTL(func, entity, RT1320_SDCA_CTL_ACTUAL_POWER_STATE, 0), &val);
 		if (val == ps)
 			break;
 
@@ -627,7 +665,7 @@  static void rt1320_vc_preset(struct rt1320_sdw_priv *rt1320)
 			usleep_range(delay, delay + 1000);
 
 		if (reg == SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, RT1320_SDCA_CTL_REQ_POWER_STATE, 0))
-			rt1320_pde_transition_delay(rt1320, val);
+			rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, val);
 	}
 }
 
@@ -733,6 +771,34 @@  static int rt1320_update_status(struct sdw_slave *slave,
 	return rt1320_io_init(&slave->dev, slave);
 }
 
+static int rt1320_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+	unsigned char ps0 = 0x0, ps3 = 0x3;
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		regmap_write(rt1320->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11,
+				RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
+		rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps0);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		regmap_write(rt1320->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11,
+				RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
+		rt1320_pde_transition_delay(rt1320, FUNC_NUM_MIC, RT1320_SDCA_ENT_PDE11, ps3);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
 static int rt1320_pde23_event(struct snd_soc_dapm_widget *w,
 	struct snd_kcontrol *kcontrol, int event)
 {
@@ -746,13 +812,13 @@  static int rt1320_pde23_event(struct snd_soc_dapm_widget *w,
 		regmap_write(rt1320->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
 				RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps0);
-		rt1320_pde_transition_delay(rt1320, ps0);
+		rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps0);
 		break;
 	case SND_SOC_DAPM_PRE_PMD:
 		regmap_write(rt1320->regmap,
 			SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23,
 				RT1320_SDCA_CTL_REQ_POWER_STATE, 0), ps3);
-		rt1320_pde_transition_delay(rt1320, ps3);
+		rt1320_pde_transition_delay(rt1320, FUNC_NUM_AMP, RT1320_SDCA_ENT_PDE23, ps3);
 		break;
 	default:
 		break;
@@ -771,6 +837,13 @@  static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol,
 	unsigned int gain_l_val, gain_r_val;
 	unsigned int lvalue, rvalue;
 	const unsigned int interval_offset = 0xc0;
+	unsigned int changed = 0, reg_base;
+	struct rt_sdca_dmic_kctrl_priv *p;
+	unsigned int regvalue[4], gain_val[4], i;
+	int err;
+
+	if (strstr(ucontrol->id.name, "FU Capture Volume"))
+		goto _dmic_vol_;
 
 	regmap_read(rt1320->mbq_regmap, mc->reg, &lvalue);
 	regmap_read(rt1320->mbq_regmap, mc->rreg, &rvalue);
@@ -796,7 +869,48 @@  static int rt1320_set_gain_put(struct snd_kcontrol *kcontrol,
 	regmap_write(rt1320->mbq_regmap, mc->reg, gain_l_val);
 	/* Rch */
 	regmap_write(rt1320->mbq_regmap, mc->rreg, gain_r_val);
+	goto _done_;
+
+_dmic_vol_:
+	p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+	/* check all channels */
+	for (i = 0; i < p->count; i++) {
+		if (i < 2) {
+			reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+			regmap_read(rt1320->mbq_regmap, reg_base + i, &regvalue[i]);
+		} else {
+			reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+			regmap_read(rt1320->mbq_regmap, reg_base + i - 2, &regvalue[i]);
+		}
+
+		gain_val[i] = ucontrol->value.integer.value[i];
+		if (gain_val[i] > p->max)
+			gain_val[i] = p->max;
+
+		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++) {
+		if (i < 2) {
+			reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+			err = regmap_write(rt1320->mbq_regmap, reg_base + i, gain_val[i]);
+		} else {
+			reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+			err = regmap_write(rt1320->mbq_regmap, reg_base + i - 2, gain_val[i]);
+		}
+
+		if (err < 0)
+			dev_err(&rt1320->sdw_slave->dev, "0x%08x can't be set\n", reg_base + i);
+	}
 
+_done_:
 	return 1;
 }
 
@@ -809,6 +923,11 @@  static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol,
 		(struct soc_mixer_control *)kcontrol->private_value;
 	unsigned int read_l, read_r, ctl_l = 0, ctl_r = 0;
 	const unsigned int interval_offset = 0xc0;
+	unsigned int reg_base, regvalue, ctl, i;
+	struct rt_sdca_dmic_kctrl_priv *p;
+
+	if (strstr(ucontrol->id.name, "FU Capture Volume"))
+		goto _dmic_vol_;
 
 	regmap_read(rt1320->mbq_regmap, mc->reg, &read_l);
 	regmap_read(rt1320->mbq_regmap, mc->rreg, &read_r);
@@ -822,6 +941,121 @@  static int rt1320_set_gain_get(struct snd_kcontrol *kcontrol,
 
 	ucontrol->value.integer.value[0] = ctl_l;
 	ucontrol->value.integer.value[1] = ctl_r;
+	goto _done_;
+
+_dmic_vol_:
+	p = (struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+
+	/* check all channels */
+	for (i = 0; i < p->count; i++) {
+		if (i < 2) {
+			reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+			regmap_read(rt1320->mbq_regmap, reg_base + i, &regvalue);
+		} else {
+			reg_base = SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14, RT1320_SDCA_CTL_FU_VOLUME, CH_01);
+			regmap_read(rt1320->mbq_regmap, reg_base + i - 2, &regvalue);
+		}
+
+		ctl = p->max - (((0x1e00 - regvalue) & 0xffff) / interval_offset);
+		ucontrol->value.integer.value[i] = ctl;
+	}
+_done_:
+	return 0;
+}
+
+static int rt1320_set_fu_capture_ctl(struct rt1320_sdw_priv *rt1320)
+{
+	int err, i;
+	unsigned int ch_mute;
+
+	for (i = 0; i < ARRAY_SIZE(rt1320->fu_mixer_mute); i++) {
+		ch_mute = (rt1320->fu_dapm_mute || rt1320->fu_mixer_mute[i]) ? 0x01 : 0x00;
+
+		if (i < 2)
+			err = regmap_write(rt1320->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113,
+					RT1320_SDCA_CTL_FU_MUTE, CH_01) + i, ch_mute);
+		else
+			err = regmap_write(rt1320->regmap,
+				SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU14,
+					RT1320_SDCA_CTL_FU_MUTE, CH_01) + i - 2, ch_mute);
+		if (err < 0)
+			return err;
+	}
+
+	return 0;
+}
+
+static int rt1320_dmic_fu_capture_get(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+	struct rt_sdca_dmic_kctrl_priv *p =
+		(struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+	unsigned int i;
+
+	for (i = 0; i < p->count; i++)
+		ucontrol->value.integer.value[i] = !rt1320->fu_mixer_mute[i];
+
+	return 0;
+}
+
+static int rt1320_dmic_fu_capture_put(struct snd_kcontrol *kcontrol,
+			struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+	struct rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+	struct rt_sdca_dmic_kctrl_priv *p =
+		(struct rt_sdca_dmic_kctrl_priv *)kcontrol->private_value;
+	int err, changed = 0, i;
+
+	for (i = 0; i < p->count; i++) {
+		if (rt1320->fu_mixer_mute[i] != !ucontrol->value.integer.value[i])
+			changed = 1;
+		rt1320->fu_mixer_mute[i] = !ucontrol->value.integer.value[i];
+	}
+
+	err = rt1320_set_fu_capture_ctl(rt1320);
+	if (err < 0)
+		return err;
+
+	return changed;
+}
+
+static int rt1320_dmic_fu_info(struct snd_kcontrol *kcontrol,
+	struct snd_ctl_elem_info *uinfo)
+{
+	struct rt_sdca_dmic_kctrl_priv *p =
+		(struct rt_sdca_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;
+}
+
+static int rt1320_dmic_fu_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 rt1320_sdw_priv *rt1320 = snd_soc_component_get_drvdata(component);
+
+	switch (event) {
+	case SND_SOC_DAPM_POST_PMU:
+		rt1320->fu_dapm_mute = false;
+		rt1320_set_fu_capture_ctl(rt1320);
+		break;
+	case SND_SOC_DAPM_PRE_PMD:
+		rt1320->fu_dapm_mute = true;
+		rt1320_set_fu_capture_ctl(rt1320);
+		break;
+	}
 	return 0;
 }
 
@@ -842,6 +1076,7 @@  static SOC_ENUM_SINGLE_DECL(rt1320_rx_data_ch_enum,
 	rt1320_rx_data_ch_select);
 
 static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6525, 75, 0);
+static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -1725, 75, 0);
 
 static const struct snd_kcontrol_new rt1320_snd_controls[] = {
 	SOC_DOUBLE_R_EXT_TLV("FU21 Playback Volume",
@@ -849,6 +1084,13 @@  static const struct snd_kcontrol_new rt1320_snd_controls[] = {
 		SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_FU21, RT1320_SDCA_CTL_FU_VOLUME, CH_02),
 		0, 0x57, 0, rt1320_set_gain_get, rt1320_set_gain_put, out_vol_tlv),
 	SOC_ENUM("RX Channel Select", rt1320_rx_data_ch_enum),
+
+	RT_SDCA_FU_CTRL("FU Capture Switch",
+		SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_MUTE, CH_01),
+		1, 1, 4, rt1320_dmic_fu_info, rt1320_dmic_fu_capture_get, rt1320_dmic_fu_capture_put),
+	RT_SDCA_EXT_TLV("FU Capture Volume",
+		SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_FU113, RT1320_SDCA_CTL_FU_VOLUME, CH_01),
+		rt1320_set_gain_get, rt1320_set_gain_put, 4, 0x3f, in_vol_tlv, rt1320_dmic_fu_info),
 };
 
 static const struct snd_kcontrol_new rt1320_spk_l_dac =
@@ -864,12 +1106,19 @@  static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = {
 	/* Audio Interface */
 	SND_SOC_DAPM_AIF_IN("DP1RX", "DP1 Playback", 0, SND_SOC_NOPM, 0, 0),
 	SND_SOC_DAPM_AIF_OUT("DP4TX", "DP4 Capture", 0, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_AIF_OUT("DP8-10TX", "DP8-10 Capture", 0, SND_SOC_NOPM, 0, 0),
 
 	/* Digital Interface */
 	SND_SOC_DAPM_PGA("FU21", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_SUPPLY("PDE 23", SND_SOC_NOPM, 0, 0,
 		rt1320_pde23_event,
 		SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_SUPPLY("PDE 11", SND_SOC_NOPM, 0, 0,
+		rt1320_pde11_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+	SND_SOC_DAPM_ADC("FU 113", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_ADC("FU 14", NULL, SND_SOC_NOPM, 0, 0),
+	SND_SOC_DAPM_PGA_E("FU", SND_SOC_NOPM, 0, 0, NULL, 0,
+		rt1320_dmic_fu_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
 
 	/* Output */
 	SND_SOC_DAPM_SWITCH("OT23 L", SND_SOC_NOPM, 0, 0, &rt1320_spk_l_dac),
@@ -880,6 +1129,8 @@  static const struct snd_soc_dapm_widget rt1320_dapm_widgets[] = {
 	/* Input */
 	SND_SOC_DAPM_PGA("AEC Data", SND_SOC_NOPM, 0, 0, NULL, 0),
 	SND_SOC_DAPM_SIGGEN("AEC Gen"),
+	SND_SOC_DAPM_INPUT("DMIC1"),
+	SND_SOC_DAPM_INPUT("DMIC2"),
 };
 
 static const struct snd_soc_dapm_route rt1320_dapm_routes[] = {
@@ -892,6 +1143,13 @@  static const struct snd_soc_dapm_route rt1320_dapm_routes[] = {
 
 	{ "AEC Data", NULL, "AEC Gen" },
 	{ "DP4TX", NULL, "AEC Data" },
+
+	{"DP8-10TX", NULL, "FU"},
+	{"FU", NULL, "PDE 11"},
+	{"FU", NULL, "FU 113"},
+	{"FU", NULL, "FU 14"},
+	{"FU 113", NULL, "DMIC1"},
+	{"FU 14", NULL, "DMIC2"},
 };
 
 static int rt1320_set_sdw_stream(struct snd_soc_dai *dai, void *sdw_stream,
@@ -915,6 +1173,7 @@  static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
 		snd_soc_component_get_drvdata(component);
 	struct sdw_stream_config stream_config;
 	struct sdw_port_config port_config;
+	struct sdw_port_config dmic_port_config[2];
 	struct sdw_stream_runtime *sdw_stream;
 	int retval;
 	unsigned int sampling_rate;
@@ -939,12 +1198,23 @@  static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
 	} else {
 		if (dai->id == RT1320_AIF1)
 			port_config.num = 4;
-		else
+		else if (dai->id == RT1320_AIF2) {
+			dmic_port_config[0].ch_mask = BIT(0) | BIT(1);
+			dmic_port_config[0].num = 8;
+			dmic_port_config[1].ch_mask = BIT(0) | BIT(1);
+			dmic_port_config[1].num = 10;
+		} else
 			return -EINVAL;
 	}
 
-	retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+	if (dai->id == RT1320_AIF1)
+		retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
 				&port_config, 1, sdw_stream);
+	else if (dai->id == RT1320_AIF2)
+		retval = sdw_stream_add_slave(rt1320->sdw_slave, &stream_config,
+				dmic_port_config, 2, sdw_stream);
+	else
+		return -EINVAL;
 	if (retval) {
 		dev_err(dai->dev, "%s: Unable to configure port\n", __func__);
 		return retval;
@@ -977,9 +1247,18 @@  static int rt1320_sdw_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	/* set sampling frequency */
-	regmap_write(rt1320->regmap,
-		SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
-		sampling_rate);
+	if (dai->id == RT1320_AIF1)
+		regmap_write(rt1320->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_AMP, RT1320_SDCA_ENT_CS21, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+			sampling_rate);
+	else {
+		regmap_write(rt1320->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS113, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+			sampling_rate);
+		regmap_write(rt1320->regmap,
+			SDW_SDCA_CTL(FUNC_NUM_MIC, RT1320_SDCA_ENT_CS14, RT1320_SDCA_CTL_SAMPLE_FREQ_INDEX, 0),
+			sampling_rate);
+	}
 
 	return 0;
 }
@@ -1070,6 +1349,19 @@  static struct snd_soc_dai_driver rt1320_sdw_dai[] = {
 		},
 		.ops = &rt1320_aif_dai_ops,
 	},
+	/* DMIC: DP8 2ch + DP10 2ch */
+	{
+		.name = "rt1320-aif2",
+		.id = RT1320_AIF2,
+		.capture = {
+			.stream_name = "DP8-10 Capture",
+			.channels_min = 1,
+			.channels_max = 4,
+			.rates = RT1320_STEREO_RATES,
+			.formats = RT1320_FORMATS,
+		},
+		.ops = &rt1320_aif_dai_ops,
+	},
 };
 
 static int rt1320_sdw_init(struct device *dev, struct regmap *regmap,
@@ -1097,6 +1389,9 @@  static int rt1320_sdw_init(struct device *dev, struct regmap *regmap,
 	rt1320->hw_init = false;
 	rt1320->first_hw_init = false;
 	rt1320->version_id = -1;
+	rt1320->fu_dapm_mute = true;
+	rt1320->fu_mixer_mute[0] = rt1320->fu_mixer_mute[1] =
+		rt1320->fu_mixer_mute[2] = rt1320->fu_mixer_mute[3] = true;
 
 	ret =  devm_snd_soc_register_component(dev,
 				&soc_component_sdw_rt1320,
diff --git a/sound/soc/codecs/rt1320-sdw.h b/sound/soc/codecs/rt1320-sdw.h
index 95ef9d37c6db..23b321aee6a9 100644
--- a/sound/soc/codecs/rt1320-sdw.h
+++ b/sound/soc/codecs/rt1320-sdw.h
@@ -26,6 +26,7 @@ 
 
 /* RT1320 SDCA Control - function number */
 #define FUNC_NUM_AMP 0x04
+#define FUNC_NUM_MIC 0x02
 
 /* RT1320 SDCA entity */
 #define RT1320_SDCA_ENT0 0x00
@@ -69,6 +70,7 @@ 
 
 enum {
 	RT1320_AIF1,
+	RT1320_AIF2,
 };
 
 /*
@@ -94,6 +96,8 @@  struct rt1320_sdw_priv {
 	bool hw_init;
 	bool first_hw_init;
 	int version_id;
+	bool fu_dapm_mute;
+	bool fu_mixer_mute[4];
 };
 
 #endif /* __RT1320_SDW_H__ */