Prechádzať zdrojové kódy

asoc: qcs405: Add support for META MI2S ports

QCS405 can group data lines of several MI2S interfaces.
This feature is used with new META MI2S ports.

Change-Id: Iffc72a5aae1da8a0620ad988fdc570e5ed493956
Signed-off-by: Ralf Herz <[email protected]>
Ralf Herz 5 rokov pred
rodič
commit
afaec2af14
1 zmenil súbory, kde vykonal 510 pridanie a 1 odobranie
  1. 510 1
      asoc/qcs405.c

+ 510 - 1
asoc/qcs405.c

@@ -105,6 +105,12 @@ enum {
 	MI2S_MAX,
 };
 
+enum {
+	PRIM_META_MI2S = 0,
+	SEC_META_MI2S,
+	META_MI2S_MAX,
+};
+
 enum {
 	PRIM_AUX_PCM = 0,
 	SEC_AUX_PCM,
@@ -157,6 +163,12 @@ static u32 mi2s_ebit_clk[MI2S_MAX] = {
 	Q6AFE_LPASS_CLK_ID_SEN_MI2S_EBIT
 };
 
+struct meta_mi2s_conf {
+	u32 num_member_ports;
+	u32 member_port[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+	bool clk_enable[MAX_NUM_I2S_META_PORT_MEMBER_PORTS];
+};
+
 struct dev_config {
 	u32 sample_rate;
 	u32 bit_format;
@@ -402,6 +414,11 @@ static struct dev_config mi2s_rx_cfg[] = {
 	[SEN_MI2S]  = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
 };
 
+static struct dev_config meta_mi2s_rx_cfg[] = {
+	[PRIM_META_MI2S] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+	[SEC_META_MI2S]  = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
+};
+
 /* Default configuration of SPDIF channels */
 static struct dev_config spdif_rx_cfg[] = {
 	[PRIM_SPDIF_RX] = {SAMPLING_RATE_48KHZ, SNDRV_PCM_FORMAT_S16_LE, 2},
@@ -487,6 +504,14 @@ static const char *const mi2s_ch_text[] = {
 		"Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
 		"Fourteen", "Fifteen", "Sixteen"
 };
+static const char *const meta_mi2s_ch_text[] = {
+		"One", "Two", "Three", "Four", "Five", "Six", "Seven",
+		"Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen",
+		"Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen",
+		"Nineteen", "Twenty", "TwentyOne", "TwentyTwo", "TwentyThree",
+		"TwentyFour", "TwentyFive", "TwentySix", "TwentySeven",
+		"TwentyEight", "TwentyNine", "Thirty", "ThirtyOne", "ThirtyTwo"
+};
 static const char *const qos_text[] = {"Disable", "Enable"};
 
 static const char *const cdc_dma_rx_ch_text[] = {"One", "Two"};
@@ -576,6 +601,12 @@ static SOC_ENUM_SINGLE_EXT_DECL(mi2s_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(mi2s_tx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(aux_pcm_tx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_sample_rate, mi2s_rate_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_chs, meta_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_chs, meta_mi2s_ch_text);
+static SOC_ENUM_SINGLE_EXT_DECL(prim_meta_mi2s_rx_format, bit_format_text);
+static SOC_ENUM_SINGLE_EXT_DECL(sec_meta_mi2s_rx_format, bit_format_text);
 static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_rx_0_chs, cdc_dma_rx_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_rx_1_chs, cdc_dma_rx_ch_text);
 static SOC_ENUM_SINGLE_EXT_DECL(wsa_cdc_dma_tx_0_chs, cdc_dma_tx_ch_text);
@@ -689,6 +720,8 @@ static struct afe_clk_set mi2s_clk[MI2S_MAX] = {
 
 static struct mi2s_conf mi2s_intf_conf[MI2S_MAX];
 
+static struct meta_mi2s_conf meta_mi2s_intf_conf[META_MI2S_MAX];
+
 static int msm_island_vad_get_portid_from_beid(int32_t be_id, int *port_id)
 {
 	*port_id = 0xFFFF;
@@ -3070,6 +3103,143 @@ static int msm_mi2s_tx_format_put(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static int msm_meta_mi2s_get_port_idx(struct snd_kcontrol *kcontrol)
+{
+	int idx = 0;
+
+	if (strnstr(kcontrol->id.name, "PRIM_META_MI2S_RX",
+	    sizeof("PRIM_META_MI2S_RX"))) {
+		idx = PRIM_META_MI2S;
+	} else if (strnstr(kcontrol->id.name, "SEC_META_MI2S_RX",
+		   sizeof("SEC_META_MI2S_RX"))) {
+		idx = SEC_META_MI2S;
+	} else {
+		pr_err("%s: unsupported port: %s",
+			__func__, kcontrol->id.name);
+		idx = -EINVAL;
+	}
+
+	return idx;
+}
+
+static int msm_meta_mi2s_rx_sample_rate_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] =
+		mi2s_get_sample_rate_val(meta_mi2s_rx_cfg[idx].sample_rate);
+
+	pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+		 idx, meta_mi2s_rx_cfg[idx].sample_rate,
+		 ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_meta_mi2s_rx_sample_rate_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	meta_mi2s_rx_cfg[idx].sample_rate =
+		mi2s_get_sample_rate(ucontrol->value.enumerated.item[0]);
+
+	pr_debug("%s: idx[%d]_rx_sample_rate = %d, item = %d\n", __func__,
+		 idx, meta_mi2s_rx_cfg[idx].sample_rate,
+		 ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_meta_mi2s_rx_ch_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] = meta_mi2s_rx_cfg[idx].channels - 1;
+
+	pr_debug("%s: meta_mi2s_[%d]_rx_ch  = %d\n", __func__,
+		 idx, meta_mi2s_rx_cfg[idx].channels);
+
+	return 0;
+}
+
+static int msm_meta_mi2s_rx_ch_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	meta_mi2s_rx_cfg[idx].channels = ucontrol->value.enumerated.item[0] + 1;
+
+	pr_debug("%s: meta_mi2s_[%d]_rx_ch  = %d\n", __func__,
+		 idx, meta_mi2s_rx_cfg[idx].channels);
+
+	return 1;
+}
+
+static int msm_meta_mi2s_rx_format_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	if (idx < 0)
+		return idx;
+
+	ucontrol->value.enumerated.item[0] =
+		mi2s_auxpcm_get_format_value(meta_mi2s_rx_cfg[idx].bit_format);
+
+	pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+		idx, meta_mi2s_rx_cfg[idx].bit_format,
+		ucontrol->value.enumerated.item[0]);
+
+	return 0;
+}
+
+static int msm_meta_mi2s_rx_format_put(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	struct msm_asoc_mach_data *pdata = NULL;
+	struct snd_soc_card *card = NULL;
+	int idx = msm_meta_mi2s_get_port_idx(kcontrol);
+
+	card = kcontrol->private_data;
+	pdata = snd_soc_card_get_drvdata(card);
+
+	if (idx < 0)
+		return idx;
+
+	/* check for PRIM_META_MI2S and CSRAx to allow 24bit BE config only */
+	if ((idx == PRIM_META_MI2S) && pdata->codec_is_csra) {
+		meta_mi2s_rx_cfg[idx].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		pr_debug("%s: Keeping default format idx[%d]_rx_format = %d, item = %d\n",
+			__func__, idx, meta_mi2s_rx_cfg[idx].bit_format,
+			ucontrol->value.enumerated.item[0]);
+	} else {
+		meta_mi2s_rx_cfg[idx].bit_format =
+			mi2s_auxpcm_get_format(
+			ucontrol->value.enumerated.item[0]);
+
+		pr_debug("%s: idx[%d]_rx_format = %d, item = %d\n", __func__,
+			idx, meta_mi2s_rx_cfg[idx].bit_format,
+			ucontrol->value.enumerated.item[0]);
+	}
+
+	return 0;
+}
+
 static int msm_aux_pcm_rx_format_get(struct snd_kcontrol *kcontrol,
 				struct snd_ctl_elem_value *ucontrol)
 {
@@ -3979,6 +4149,26 @@ static const struct snd_kcontrol_new msm_snd_controls[] = {
 			msm_mi2s_rx_format_get, msm_mi2s_rx_format_put),
 	SOC_ENUM_EXT("SEN_MI2S_TX Format", mi2s_tx_format,
 			msm_mi2s_tx_format_get, msm_mi2s_tx_format_put),
+	SOC_ENUM_EXT("PRIM_META_MI2S_RX SampleRate",
+			prim_meta_mi2s_rx_sample_rate,
+			msm_meta_mi2s_rx_sample_rate_get,
+			msm_meta_mi2s_rx_sample_rate_put),
+	SOC_ENUM_EXT("SEC_META_MI2S_RX SampleRate",
+			sec_meta_mi2s_rx_sample_rate,
+			msm_meta_mi2s_rx_sample_rate_get,
+			msm_meta_mi2s_rx_sample_rate_put),
+	SOC_ENUM_EXT("PRIM_META_MI2S_RX Channels", prim_meta_mi2s_rx_chs,
+			msm_meta_mi2s_rx_ch_get,
+			msm_meta_mi2s_rx_ch_put),
+	SOC_ENUM_EXT("SEC_META_MI2S_RX Channels", sec_meta_mi2s_rx_chs,
+			msm_meta_mi2s_rx_ch_get,
+			msm_meta_mi2s_rx_ch_put),
+	SOC_ENUM_EXT("PRIM_META_MI2S_RX Format", mi2s_rx_format,
+			msm_meta_mi2s_rx_format_get,
+			msm_meta_mi2s_rx_format_put),
+	SOC_ENUM_EXT("SEC_META_MI2S_RX Format", mi2s_rx_format,
+			msm_meta_mi2s_rx_format_get,
+			msm_meta_mi2s_rx_format_put),
 	SOC_ENUM_EXT("PRIM_AUX_PCM_RX Format", aux_pcm_rx_format,
 			msm_aux_pcm_rx_format_get, msm_aux_pcm_rx_format_put),
 	SOC_ENUM_EXT("PRIM_AUX_PCM_TX Format", aux_pcm_tx_format,
@@ -4761,6 +4951,25 @@ static int msm_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd,
 		channels->min = channels->max =
 			mi2s_tx_cfg[SEN_MI2S].channels;
 		break;
+
+	case MSM_BACKEND_DAI_PRI_META_MI2S_RX:
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			meta_mi2s_rx_cfg[PRIM_META_MI2S].bit_format);
+		rate->min = rate->max =
+			meta_mi2s_rx_cfg[PRIM_META_MI2S].sample_rate;
+		channels->min = channels->max =
+			meta_mi2s_rx_cfg[PRIM_META_MI2S].channels;
+		break;
+
+	case MSM_BACKEND_DAI_SEC_META_MI2S_RX:
+		param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+			meta_mi2s_rx_cfg[SEC_META_MI2S].bit_format);
+		rate->min = rate->max =
+			meta_mi2s_rx_cfg[SEC_META_MI2S].sample_rate;
+		channels->min = channels->max =
+			meta_mi2s_rx_cfg[SEC_META_MI2S].channels;
+		break;
+
 	case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_0:
 	case MSM_BACKEND_DAI_WSA_CDC_DMA_RX_1:
 		idx = msm_cdc_dma_get_idx_from_beid(dai_link->id);
@@ -5996,6 +6205,172 @@ static void msm_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
 	mutex_unlock(&mi2s_intf_conf[index].lock);
 }
 
+static int msm_meta_mi2s_set_sclk(struct snd_pcm_substream *substream,
+	int member_id, bool enable)
+{
+	int ret = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int be_id = 0;
+	int port_id = 0;
+	int index = cpu_dai->id;
+	u32 bit_per_sample = 0;
+
+	switch (member_id) {
+	case PRIM_MI2S:
+		be_id = MSM_BACKEND_DAI_PRI_MI2S_RX;
+		break;
+	case SEC_MI2S:
+		be_id = MSM_BACKEND_DAI_SECONDARY_MI2S_RX;
+		break;
+	case TERT_MI2S:
+		be_id = MSM_BACKEND_DAI_TERTIARY_MI2S_RX;
+		break;
+	case QUAT_MI2S:
+		be_id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX;
+		break;
+	default:
+		dev_err(rtd->card->dev, "%s: Invalid member_id\n", __func__);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	port_id = msm_get_port_id(be_id);
+	if (port_id < 0) {
+		dev_err(rtd->card->dev, "%s: Invalid port_id\n", __func__);
+		ret = port_id;
+		goto err;
+	}
+
+	if (enable) {
+		bit_per_sample =
+			get_mi2s_bits_per_sample(
+				meta_mi2s_rx_cfg[index].bit_format);
+		mi2s_clk[member_id].clk_freq_in_hz =
+			meta_mi2s_rx_cfg[index].sample_rate * 2 *
+			bit_per_sample;
+
+		dev_dbg(rtd->card->dev, "%s: clock rate %ul\n", __func__,
+			mi2s_clk[member_id].clk_freq_in_hz);
+	}
+
+	mi2s_clk[member_id].enable = enable;
+	ret = afe_set_lpass_clock_v2(port_id, &mi2s_clk[member_id]);
+	if (ret < 0) {
+		dev_err(rtd->card->dev,
+			"%s: afe lpass clock failed for port 0x%x , err:%d\n",
+			__func__, port_id, ret);
+		goto err;
+	}
+
+err:
+	return ret;
+}
+
+static int msm_meta_mi2s_snd_startup(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	int i = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	int index = cpu_dai->id;
+	int member_port = 0;
+	unsigned int fmt = SND_SOC_DAIFMT_CBS_CFS;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+	dev_dbg(rtd->card->dev,
+		"%s: substream = %s  stream = %d, dai name %s, dai ID %d\n",
+		__func__, substream->name, substream->stream,
+		cpu_dai->name, cpu_dai->id);
+
+	if (index < PRIM_META_MI2S || index >= META_MI2S_MAX) {
+		ret = -EINVAL;
+		dev_err(rtd->card->dev,
+			"%s: CPU DAI id (%d) out of range\n",
+			__func__, cpu_dai->id);
+		goto err;
+	}
+
+	for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+		member_port = meta_mi2s_intf_conf[index].member_port[i];
+
+		if (!mi2s_intf_conf[member_port].msm_is_mi2s_master) {
+			mi2s_clk[member_port].clk_id =
+				mi2s_ebit_clk[member_port];
+			fmt = SND_SOC_DAIFMT_CBM_CFM;
+		}
+
+		ret = msm_meta_mi2s_set_sclk(substream, member_port, true);
+		if (ret < 0) {
+			dev_err(rtd->card->dev,
+				"%s: afe lpass clock failed to enable MI2S clock, err:%d\n",
+				__func__, ret);
+			goto clk_off;
+		}
+		meta_mi2s_intf_conf[index].clk_enable[i] = true;
+
+		if (i == 0) {
+			ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+			if (ret < 0) {
+				pr_err("%s: set fmt cpu dai failed for META_MI2S (%d), err:%d\n",
+					__func__, index, ret);
+				goto clk_off;
+			}
+		}
+		if (pdata->mi2s_gpio_p[member_port])
+			msm_cdc_pinctrl_select_active_state(
+					pdata->mi2s_gpio_p[member_port]);
+	}
+	return 0;
+
+clk_off:
+	for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+		member_port = meta_mi2s_intf_conf[index].member_port[i];
+		if (pdata->mi2s_gpio_p[member_port])
+			msm_cdc_pinctrl_select_sleep_state(
+					pdata->mi2s_gpio_p[member_port]);
+
+		if (meta_mi2s_intf_conf[index].clk_enable[i]) {
+			msm_meta_mi2s_set_sclk(substream, member_port, false);
+			meta_mi2s_intf_conf[index].clk_enable[i] = false;
+		}
+	}
+err:
+	return ret;
+}
+
+static void msm_meta_mi2s_snd_shutdown(struct snd_pcm_substream *substream)
+{
+	int ret = 0;
+	int i = 0;
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	int index = rtd->cpu_dai->id;
+	int member_port = 0;
+	struct snd_soc_card *card = rtd->card;
+	struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card);
+
+	pr_debug("%s(): substream = %s  stream = %d\n", __func__,
+		 substream->name, substream->stream);
+	if (index < PRIM_MI2S || index >= MI2S_MAX) {
+		pr_err("%s:invalid MI2S DAI(%d)\n", __func__, index);
+		return;
+	}
+
+	for (i = 0; i < meta_mi2s_intf_conf[index].num_member_ports; i++) {
+		member_port = meta_mi2s_intf_conf[index].member_port[i];
+
+		if (pdata->mi2s_gpio_p[member_port])
+			msm_cdc_pinctrl_select_sleep_state(
+					pdata->mi2s_gpio_p[member_port]);
+
+		ret = msm_meta_mi2s_set_sclk(substream, member_port, false);
+		if (ret < 0)
+			pr_err("%s:clock disable failed for META MI2S (%d); ret=%d\n",
+				__func__, index, ret);
+	}
+}
+
 static int msm_spdif_set_clk(struct snd_pcm_substream *substream, bool enable)
 {
 	int ret = 0;
@@ -6131,6 +6506,11 @@ static struct snd_soc_ops msm_mi2s_be_ops = {
 	.shutdown = msm_mi2s_snd_shutdown,
 };
 
+static struct snd_soc_ops msm_meta_mi2s_be_ops = {
+	.startup = msm_meta_mi2s_snd_startup,
+	.shutdown = msm_meta_mi2s_snd_shutdown,
+};
+
 static struct snd_soc_ops msm_auxpcm_be_ops = {
 	.startup = msm_snd_auxpcm_startup,
 };
@@ -7567,6 +7947,39 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = {
 
 };
 
+static struct snd_soc_dai_link msm_meta_mi2s_be_dai_links[] = {
+	{
+		.name = LPASS_BE_PRI_META_MI2S_RX,
+		.stream_name = "Primary META MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-meta-mi2s.4864",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_PRI_META_MI2S_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_meta_mi2s_be_ops,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+	},
+	{
+		.name = LPASS_BE_SEC_META_MI2S_RX,
+		.stream_name = "Secondary META MI2S Playback",
+		.cpu_dai_name = "msm-dai-q6-meta-mi2s.4866",
+		.platform_name = "msm-pcm-routing",
+		.codec_name = "msm-stub-codec.1",
+		.codec_dai_name = "msm-stub-rx",
+		.no_pcm = 1,
+		.dpcm_playback = 1,
+		.id = MSM_BACKEND_DAI_SEC_META_MI2S_RX,
+		.be_hw_params_fixup = msm_be_hw_params_fixup,
+		.ops = &msm_meta_mi2s_be_ops,
+		.ignore_suspend = 1,
+		.ignore_pmdown_time = 1,
+	},
+};
+
 static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = {
 	/* Primary AUX PCM Backend DAI Links */
 	{
@@ -7885,6 +8298,7 @@ static struct snd_soc_dai_link msm_qcs405_dai_links[
 			 ARRAY_SIZE(msm_tasha_be_dai_links) +
 			 ARRAY_SIZE(msm_wcn_be_dai_links) +
 			 ARRAY_SIZE(msm_mi2s_be_dai_links) +
+			 ARRAY_SIZE(msm_meta_mi2s_be_dai_links) +
 			 ARRAY_SIZE(msm_auxpcm_be_dai_links) +
 			 ARRAY_SIZE(msm_va_cdc_dma_be_dai_links) +
 			 ARRAY_SIZE(msm_wsa_cdc_dma_be_dai_links) +
@@ -8140,7 +8554,7 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
 	uint32_t tasha_codec = 0, auxpcm_audio_intf = 0;
 	uint32_t va_bolero_codec = 0, wsa_bolero_codec = 0, mi2s_audio_intf = 0;
 	uint32_t spdif_audio_intf = 0, wcn_audio_intf = 0;
-	uint32_t afe_loopback_intf = 0;
+	uint32_t afe_loopback_intf = 0, meta_mi2s_intf = 0;
 	const struct of_device_id *match;
 	char __iomem *spdif_cfg, *spdif_pin_ctl;
 	int rc = 0;
@@ -8248,6 +8662,22 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev)
 				ARRAY_SIZE(msm_mi2s_be_dai_links);
 			}
 		}
+
+		rc = of_property_read_u32(dev->of_node, "qcom,meta-mi2s-intf",
+					  &meta_mi2s_intf);
+		if (rc) {
+			dev_dbg(dev, "%s: No DT match META-MI2S interface\n",
+				__func__);
+		} else {
+			if (meta_mi2s_intf) {
+				memcpy(msm_qcs405_dai_links + total_links,
+				msm_meta_mi2s_be_dai_links,
+				sizeof(msm_meta_mi2s_be_dai_links));
+				total_links +=
+				ARRAY_SIZE(msm_meta_mi2s_be_dai_links);
+			}
+		}
+
 		rc = of_property_read_u32(dev->of_node,
 					  "qcom,auxpcm-audio-intf",
 					  &auxpcm_audio_intf);
@@ -8807,6 +9237,81 @@ static void msm_i2s_auxpcm_deinit(void)
 	}
 }
 
+static void msm_meta_mi2s_init(struct platform_device *pdev)
+{
+	int rc = 0;
+	int i = 0;
+	int index = 0;
+	bool parse_of = false;
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+	struct snd_soc_dai_link *dai_link = card->dai_link;
+
+	dev_dbg(&pdev->dev, "%s: read from DT\n", __func__);
+
+	for (index = 0; index < META_MI2S_MAX; index++) {
+		meta_mi2s_intf_conf[index].num_member_ports = 0;
+		meta_mi2s_intf_conf[index].member_port[0] = 0;
+		meta_mi2s_intf_conf[index].member_port[1] = 0;
+		meta_mi2s_intf_conf[index].member_port[2] = 0;
+		meta_mi2s_intf_conf[index].member_port[3] = 0;
+		meta_mi2s_intf_conf[index].clk_enable[0] = false;
+		meta_mi2s_intf_conf[index].clk_enable[1] = false;
+		meta_mi2s_intf_conf[index].clk_enable[2] = false;
+		meta_mi2s_intf_conf[index].clk_enable[3] = false;
+	}
+
+	/* get member port info to set matching clocks for involved ports */
+	for (i = 0; i < card->num_links; i++) {
+		if (dai_link[i].id == MSM_BACKEND_DAI_PRI_META_MI2S_RX) {
+			parse_of = true;
+			index = PRIM_META_MI2S;
+		} else if (dai_link[i].id == MSM_BACKEND_DAI_SEC_META_MI2S_RX) {
+			parse_of = true;
+			index = SEC_META_MI2S;
+		} else {
+			parse_of = false;
+		}
+		if (parse_of && dai_link[i].cpu_of_node) {
+			rc = of_property_read_u32(dai_link[i].cpu_of_node,
+				"qcom,msm-mi2s-num-members",
+				&meta_mi2s_intf_conf[index].num_member_ports);
+			if (rc) {
+				dev_err(&pdev->dev, "%s: invalid num from DT file %s\n",
+					__func__, "qcom,msm-mi2s-num-members");
+			}
+
+			if (meta_mi2s_intf_conf[index].num_member_ports >
+				MAX_NUM_I2S_META_PORT_MEMBER_PORTS) {
+				dev_err(&pdev->dev, "%s: num-members %d too large from DT file\n",
+					__func__,
+					meta_mi2s_intf_conf[index].num_member_ports);
+			}
+
+			if (meta_mi2s_intf_conf[index].num_member_ports > 0) {
+				rc = of_property_read_u32_array(
+					dai_link[i].cpu_of_node,
+					"qcom,msm-mi2s-member-id",
+					meta_mi2s_intf_conf[index].member_port,
+					meta_mi2s_intf_conf[index].num_member_ports);
+				if (rc) {
+					dev_err(&pdev->dev, "%s: member-id from DT file %s\n",
+						__func__,
+						"qcom,msm-mi2s-member-id");
+				}
+			}
+
+			dev_dbg(&pdev->dev, "dev name %s num-members=%d\n",
+				dev_name(&pdev->dev),
+				meta_mi2s_intf_conf[index].num_member_ports);
+			dev_dbg(&pdev->dev, "member array (%d, %d, %d, %d)\n",
+				meta_mi2s_intf_conf[index].member_port[0],
+				meta_mi2s_intf_conf[index].member_port[1],
+				meta_mi2s_intf_conf[index].member_port[2],
+				meta_mi2s_intf_conf[index].member_port[3]);
+		}
+	}
+}
+
 static int msm_scan_i2c_addr(struct platform_device *pdev,
 		uint32_t busnum, uint32_t addr)
 {
@@ -8984,6 +9489,8 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
 	if (val) {
 		pdata->codec_is_csra = true;
 		mi2s_rx_cfg[PRIM_MI2S].bit_format = SNDRV_PCM_FORMAT_S24_LE;
+		meta_mi2s_rx_cfg[PRIM_META_MI2S].bit_format =
+			SNDRV_PCM_FORMAT_S24_LE;
 		ret = msm_init_csra_dev(pdev, card);
 		if (ret)
 			goto err;
@@ -9065,6 +9572,8 @@ static int msm_asoc_machine_probe(struct platform_device *pdev)
 
 	msm_i2s_auxpcm_init(pdev);
 
+	msm_meta_mi2s_init(pdev);
+
 	is_initial_boot = true;
 	return 0;
 err: