diff mbox series

[v6,4/5] ASoC: qcom: Add support for lpass hdmi driver

Message ID 1600409084-29093-5-git-send-email-srivasam@codeaurora.org (mailing list archive)
State Superseded
Headers show
Series Qualcomm's lpass-hdmi ASoC driver to support audio over dp port | expand

Commit Message

Srinivasa Rao Mandadapu Sept. 18, 2020, 6:04 a.m. UTC
From: V Sujith Kumar Reddy <vsujithk@codeaurora.org>

Upadate lpass cpu and platform driver to support audio over dp.
Also add lpass-hdmi.c and lpass-hdmi.h.

Signed-off-by: Srinivasa Rao <srivasam@codeaurora.org>
Signed-off-by: V Sujith Kumar Reddy <vsujithk@codeaurora.org>
---
 sound/soc/qcom/Kconfig           |   5 +
 sound/soc/qcom/Makefile          |   2 +
 sound/soc/qcom/lpass-apq8016.c   |   4 +-
 sound/soc/qcom/lpass-cpu.c       |  37 ++-
 sound/soc/qcom/lpass-hdmi.c      | 596 +++++++++++++++++++++++++++++++++++++++
 sound/soc/qcom/lpass-hdmi.h      | 129 +++++++++
 sound/soc/qcom/lpass-ipq806x.c   |   4 +-
 sound/soc/qcom/lpass-lpaif-reg.h |  52 +++-
 sound/soc/qcom/lpass-platform.c  | 466 ++++++++++++++++++++++++------
 sound/soc/qcom/lpass.h           | 119 +++++++-
 10 files changed, 1294 insertions(+), 120 deletions(-)
 create mode 100644 sound/soc/qcom/lpass-hdmi.c
 create mode 100644 sound/soc/qcom/lpass-hdmi.h

Comments

Srinivas Kandagatla Sept. 21, 2020, 9:20 p.m. UTC | #1
On 18/09/2020 07:04, Srinivasa Rao Mandadapu wrote:
> From: V Sujith Kumar Reddy <vsujithk@codeaurora.org>
> 
> Upadate lpass cpu and platform driver to support audio over dp.
> Also add lpass-hdmi.c and lpass-hdmi.h.
> 
> Signed-off-by: Srinivasa Rao <srivasam@codeaurora.org>
> Signed-off-by: V Sujith Kumar Reddy <vsujithk@codeaurora.org>
> ---
>   sound/soc/qcom/Kconfig           |   5 +
>   sound/soc/qcom/Makefile          |   2 +
>   sound/soc/qcom/lpass-apq8016.c   |   4 +-
>   sound/soc/qcom/lpass-cpu.c       |  37 ++-
>   sound/soc/qcom/lpass-hdmi.c      | 596 +++++++++++++++++++++++++++++++++++++++
>   sound/soc/qcom/lpass-hdmi.h      | 129 +++++++++
>   sound/soc/qcom/lpass-ipq806x.c   |   4 +-
>   sound/soc/qcom/lpass-lpaif-reg.h |  52 +++-
>   sound/soc/qcom/lpass-platform.c  | 466 ++++++++++++++++++++++++------
>   sound/soc/qcom/lpass.h           | 119 +++++++-
>   10 files changed, 1294 insertions(+), 120 deletions(-)
>   create mode 100644 sound/soc/qcom/lpass-hdmi.c
>   create mode 100644 sound/soc/qcom/lpass-hdmi.h
> 
> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
> index a607ace..509584c 100644
> --- a/sound/soc/qcom/Kconfig
> +++ b/sound/soc/qcom/Kconfig
> @@ -12,6 +12,10 @@ config SND_SOC_LPASS_CPU
>   	tristate
>   	select REGMAP_MMIO
>   
> +config SND_SOC_LPASS_HDMI
> +	tristate
> +	select REGMAP_MMIO
> +
>   config SND_SOC_LPASS_PLATFORM
>   	tristate
>   	select REGMAP_MMIO
> @@ -30,6 +34,7 @@ config SND_SOC_LPASS_SC7180
>   	tristate
>   	select SND_SOC_LPASS_CPU
>   	select SND_SOC_LPASS_PLATFORM
> +	select SND_SOC_LPASS_HDMI
>   
>   config SND_SOC_STORM
>   	tristate "ASoC I2S support for Storm boards"
> diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
> index 7972c94..0bd90d7 100644
> --- a/sound/soc/qcom/Makefile
> +++ b/sound/soc/qcom/Makefile
> @@ -1,12 +1,14 @@
>   # SPDX-License-Identifier: GPL-2.0
>   # Platform
>   snd-soc-lpass-cpu-objs := lpass-cpu.o
> +snd-soc-lpass-hdmi-objs := lpass-hdmi.o
>   snd-soc-lpass-platform-objs := lpass-platform.o
>   snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
>   snd-soc-lpass-apq8016-objs := lpass-apq8016.o
>   snd-soc-lpass-sc7180-objs := lpass-sc7180.o
>   
>   obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
> +obj-$(CONFIG_SND_SOC_LPASS_HDMI) += snd-soc-lpass-hdmi.o
>   obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
>   obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
>   obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
> diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
> index 5c8ae22..0aedb3a 100644
> --- a/sound/soc/qcom/lpass-apq8016.c
> +++ b/sound/soc/qcom/lpass-apq8016.c
> @@ -125,7 +125,7 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
>   };
>   
>   static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
> -					   int direction)
> +					   int direction, unsigned int dai_id)
>   {
>   	struct lpass_variant *v = drvdata->variant;
>   	int chan = 0;
> @@ -151,7 +151,7 @@ static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
>   	return chan;
>   }
>   
> -static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
> +static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
>   {
>   	clear_bit(chan, &drvdata->dma_ch_bit_map);
>   
> diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
> index 5d84f63..41a2470 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -589,13 +589,33 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   						variant->wrdma_channel_start);
>   
>   	drvdata->lpaif_map = devm_regmap_init_mmio(dev, drvdata->lpaif,
> -			&lpass_cpu_regmap_config);
> +								&lpass_cpu_regmap_config);

change not related to this patch!

Have you run checkpatch on this patch

>   	if (IS_ERR(drvdata->lpaif_map)) {
>   		dev_err(dev, "error initializing regmap: %ld\n",
>   			PTR_ERR(drvdata->lpaif_map));
>   		return PTR_ERR(drvdata->lpaif_map);
>   	}
> +#ifdef CONFIG_SND_SOC_LPASS_SC7180
No, this is not the right way to do it!
We can not have any ifdef with in the code, we should be able to cope up 
with finding if hdmiif resources are available or not!

You should proably look at variant data to see which resources are 
required or not! That should work and also get rid of this #ifdef



> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-hdmiif");
>   
> +	drvdata->hdmiif = devm_ioremap_resource(dev, res);
> +	if (IS_ERR((void const __force *)drvdata->hdmiif)) {
> +		dev_err(dev, "error mapping reg resource: %ld\n",
> +				PTR_ERR((void const __force *)drvdata->hdmiif));
> +		return PTR_ERR((void const __force *)drvdata->hdmiif);
> +	}
> +
> +	lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
> +				variant->hdmi_rdma_channels);
> +	drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
> +				&lpass_hdmi_regmap_config);
> +	if (IS_ERR(drvdata->hdmiif_map)) {
> +		dev_err(dev, "error initializing regmap: %ld\n",
> +		PTR_ERR(drvdata->hdmiif_map));
> +		return PTR_ERR(drvdata->hdmiif_map);
> +	}
> +
> +#endif
>   	if (variant->init) {
>   		ret = variant->init(pdev);
>   		if (ret) {
> @@ -606,6 +626,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   
>   	for (i = 0; i < variant->num_dai; i++) {
>   		dai_id = variant->dai_driver[i].id;
> +		if (dai_id == LPASS_DP_RX)
> +			continue;
> +
>   		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(dev,
>   					     variant->dai_osr_clk_names[i]);
>   		if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
> @@ -625,10 +648,10 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   				"error getting %s: %ld\n",
>   				variant->dai_bit_clk_names[i],
>   				PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
> +

change not related to this patch!

>   			return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
>   		}
>   	}
> -

change not related to this patch!


>   	/* Allocation for i2sctl regmap fields */
>   	drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
>   					GFP_KERNEL);
> @@ -636,10 +659,18 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   	/* Initialize bitfields for dai I2SCTL register */
>   	ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
>   						drvdata->lpaif_map);
> -	if (ret) {
> +	if (ret)
>   		dev_err(dev, "error init i2sctl field: %d\n", ret);
> +
> +#ifdef CONFIG_SND_SOC_LPASS_SC7180
> +	ret = lpass_hdmi_init_bitfields(dev, drvdata->hdmiif_map);
> +	if (ret) {
> +		dev_err(dev, "%s error  hdmi init failed\n", __func__);
>   		return ret;
>   	}
> +#else
> +	return -EINVAL;
> +#endif
>   
>   	ret = devm_snd_soc_register_component(dev,
>   					      &lpass_cpu_comp_driver,
> diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c
> new file mode 100644
> index 0000000..7cb2ba3
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-hdmi.c
> @@ -0,0 +1,596 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (c) 2020 The Linux Foundation. All rights reserved.
> + *
> + * lpass-hdmi.c -- ALSA SoC HDMI-CPU DAI driver for QTi LPASS HDMI
> + */
> +
> +#include <linux/clk.h>
Do you need this header?

> +#include <linux/kernel.h>
> +#include <linux/module.h>
<<<
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
 >>>
Do you need these headers?

> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <linux/regmap.h>
> +#include <sound/soc.h>
> +#include <sound/soc-dai.h>
> +#include <dt-bindings/sound/sc7180-lpass.h>
> +#include "lpass-lpaif-reg.h"
> +#include "lpass.h"
> +#include "lpass-hdmi.h"
> +
> +int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
> +{
> +	struct lpass_data *drvdata = dev_get_drvdata(dev);
> +	struct lpass_variant *v = drvdata->variant;
> +	unsigned int i;
> +	struct lpass_hdmi_tx_ctl *tx_ctl;
> +	struct lpass_hdmitx_legacy *legacy;
> +	struct lpass_vbit_ctrl *vbit_ctl;
> +	struct lpass_hdmi_tx_parity *tx_parity;
> +	struct lpass_dp_metadata_ctl *meta_ctl;
> +	struct lpass_sstream_ctl *sstream_ctl;
> +	struct lpass_hdmi_tx_ch_msb *ch_msb;
> +	struct lpass_hdmi_tx_ch_lsb *ch_lsb;
> +	struct lpass_hdmitx_dmactl *hdmi_tx_dmactl;
> +
> +	drvdata->tx_ctl = devm_kzalloc(dev, sizeof(struct lpass_hdmi_tx_ctl),
> +					GFP_KERNEL);
> +	if (drvdata->tx_ctl == NULL)
> +		return -ENOMEM;
> +
> +	tx_ctl = drvdata->tx_ctl;
> +	tx_ctl->soft_reset = devm_regmap_field_alloc(dev, map,
> +				v->soft_reset);
> +	tx_ctl->force_reset = devm_regmap_field_alloc(dev, map,
> +				v->force_reset);
> +	if (IS_ERR(tx_ctl->soft_reset) || IS_ERR(tx_ctl->force_reset))
> +		return -EINVAL;
> +
> +	drvdata->legacy = devm_kzalloc(dev, sizeof(struct lpass_hdmitx_legacy),

consider doing something like this to save uncessary long lines here! 
which makes code unreadable.


legacy = devm_kzalloc(dev, sizeof(*legacy), GFP_KERNEL);
if (!legacy)
	return -ENOMEM

drvdata->legacy = legacy;


use sizeof(*legacy) and same comment to other parts of the code!


> +					GFP_KERNEL);
> +	if (drvdata->legacy == NULL)
> +		return -ENOMEM;
> +
> +	legacy = drvdata->legacy;
> +	legacy->legacy_en = devm_regmap_field_alloc(dev, map,
> +				v->legacy_en);
> +	if (IS_ERR(legacy->legacy_en))
> +		return -EINVAL;
> +
> +	drvdata->vbit_ctl = devm_kzalloc(dev, sizeof(struct lpass_vbit_ctrl),
> +					GFP_KERNEL);
> +	if (drvdata->vbit_ctl == NULL)
> +		return -ENOMEM;
> +
> +	vbit_ctl = drvdata->vbit_ctl;
> +	vbit_ctl->replace_vbit = devm_regmap_field_alloc(dev, map,
> +					v->replace_vbit);
> +	vbit_ctl->vbit_stream = devm_regmap_field_alloc(dev, map,
> +					v->vbit_stream);
> +	if (IS_ERR(vbit_ctl->replace_vbit) || IS_ERR(vbit_ctl->vbit_stream))
> +		return -EINVAL;
> +
> +	drvdata->tx_parity = devm_kzalloc(dev,
> +		sizeof(struct  lpass_hdmi_tx_parity), GFP_KERNEL);
> +
> +	if (drvdata->tx_parity == NULL)
> +		return -ENOMEM;
> +
> +	tx_parity = drvdata->tx_parity;
> +	tx_parity->calc_en = devm_regmap_field_alloc(dev, map, v->calc_en);
> +
> +	if (IS_ERR(tx_parity->calc_en))
> +		return -EINVAL;
> +
> +	drvdata->meta_ctl = devm_kzalloc(dev,
> +		sizeof(struct lpass_dp_metadata_ctl), GFP_KERNEL);
> +
> +	if (drvdata->meta_ctl == NULL)
> +		return -ENOMEM;
> +
> +	meta_ctl = drvdata->meta_ctl;
> +	meta_ctl->mute = devm_regmap_field_alloc(dev, map, v->mute);
> +	meta_ctl->as_sdp_cc = devm_regmap_field_alloc(dev, map,
> +						v->as_sdp_cc);
> +	meta_ctl->as_sdp_ct = devm_regmap_field_alloc(dev, map,
> +						v->as_sdp_ct);
> +	meta_ctl->aif_db4 = devm_regmap_field_alloc(dev, map,
> +						v->aif_db4);
> +	meta_ctl->frequency = devm_regmap_field_alloc(dev, map,
> +						v->frequency);
> +	meta_ctl->mst_index = devm_regmap_field_alloc(dev, map,
> +						v->mst_index);
<<<<<
> +	meta_ctl->dptx_index = devm_regmap_field_alloc(dev, map,
> +						v->dptx_index);
> +
> +	if (IS_ERR(meta_ctl->mute) || IS_ERR(meta_ctl->as_sdp_cc) ||
> +		IS_ERR(meta_ctl->as_sdp_ct) || IS_ERR(meta_ctl->aif_db4) ||
> +		IS_ERR(meta_ctl->frequency) || IS_ERR(meta_ctl->mst_index) ||
> +		IS_ERR(meta_ctl->dptx_index))
> +		return -EINVAL;
 >>>>>

These type of code is allover the place, why not just add a simple macro 
to do this.

something like

#define QCOM_REGMAP_FILED_ALLOC(d, m, f)	\
	do { \
		f = devm_regmap_field_alloc(d, m, f); 	\
		if (IS_ERR(f))				\
			return -EINVAL; 		\
	} while (0)

and call
	QCOM_REGMAP_FILED_ALLOC(dev, map, meta_ctl->dptx_index);

this will make code much cleaner IMO.

Also we can consider adding some bluk  apis to allocate regmap field
or something 
like!https://git.linaro.org/people/srinivas.kandagatla/linux.git/commit/?h=wip/regmap&id=03551a6e2941d71b99e2e4a5035a9de5f0df6d5d

and call
devm_regmap_field_bulk_alloc(dev, map, &sstream_ctl->sstream_en, 
&v->sstream_en, 9);

this should work as long as order of reg_field and regmap_field are 
maintained, which in this case is true!


> +
> +	drvdata->sstream_ctl = devm_kzalloc(dev,
> +		sizeof(struct lpass_sstream_ctl), GFP_KERNEL);
> +	if (drvdata->sstream_ctl == NULL)
> +		return -ENOMEM;
> +
> +	sstream_ctl = drvdata->sstream_ctl;
> +	sstream_ctl->sstream_en = devm_regmap_field_alloc(dev, map,
> +						v->sstream_en);
> +	sstream_ctl->dma_sel = devm_regmap_field_alloc(dev, map,
> +						v->dma_sel);
> +	sstream_ctl->auto_bbit_en = devm_regmap_field_alloc(dev, map,
> +						v->auto_bbit_en);
> +	sstream_ctl->layout = devm_regmap_field_alloc(dev, map,
> +						v->layout);
> +	sstream_ctl->layout_sp = devm_regmap_field_alloc(dev, map,
> +						v->layout_sp);
> +	sstream_ctl->dp_audio = devm_regmap_field_alloc(dev, map,
> +						v->dp_audio);
> +	sstream_ctl->set_sp_on_en = devm_regmap_field_alloc(dev, map,
> +						v->set_sp_on_en);
> +	sstream_ctl->dp_staffing_en = devm_regmap_field_alloc(dev, map,
> +						v->dp_staffing_en);
> +	sstream_ctl->dp_sp_b_hw_en = devm_regmap_field_alloc(dev, map,
> +						v->dp_sp_b_hw_en);
> +
> +	if (IS_ERR(sstream_ctl->sstream_en) || IS_ERR(sstream_ctl->dma_sel) ||
> +		IS_ERR(sstream_ctl->auto_bbit_en) ||
> +		IS_ERR(sstream_ctl->layout) || IS_ERR(sstream_ctl->layout_sp) ||
> +		IS_ERR(sstream_ctl->dp_audio) ||
> +		IS_ERR(sstream_ctl->set_sp_on_en) ||
> +		IS_ERR(sstream_ctl->dp_staffing_en) ||
> +		IS_ERR(sstream_ctl->dp_sp_b_hw_en))
> +		return -EINVAL;
> +
> +	for (i = 0; i < LPASS_MAX_HDMI_DMA_CHANNELS; i++) {
> +		drvdata->ch_msb[i] = devm_kzalloc(dev,
> +			sizeof(struct lpass_hdmi_tx_ch_msb), GFP_KERNEL);
> +		if (drvdata->ch_msb[i] == NULL)
> +			return -ENOMEM;
> +
> +		ch_msb = drvdata->ch_msb[i];
> +
> +		ch_msb->msb_bits = devm_regmap_field_alloc(dev, map,
> +							v->msb_bits);
> +		if (IS_ERR(ch_msb->msb_bits))
> +			return -EINVAL;
> +
> +		drvdata->ch_lsb[i] = devm_kzalloc(dev,
> +			sizeof(struct lpass_hdmi_tx_ch_lsb), GFP_KERNEL);
> +		if (drvdata->ch_lsb[i] == NULL)
> +			return -ENOMEM;
> +
> +		ch_lsb = drvdata->ch_lsb[i];
> +		ch_lsb->lsb_bits = devm_regmap_field_alloc(dev, map,
> +					v->lsb_bits);
> +		if (IS_ERR(ch_lsb->lsb_bits))
> +			return -EINVAL;
> +
> +
> +		drvdata->hdmi_tx_dmactl[i] = devm_kzalloc(dev,
> +			sizeof(struct lpass_hdmitx_dmactl), GFP_KERNEL);
> +		if (drvdata->hdmi_tx_dmactl[i] == NULL)
> +			return -ENOMEM;
> +
> +		hdmi_tx_dmactl = drvdata->hdmi_tx_dmactl[i];
> +		hdmi_tx_dmactl->use_hw_chs = devm_regmap_field_alloc(dev, map,
> +						v->use_hw_chs);
> +		hdmi_tx_dmactl->use_hw_usr = devm_regmap_field_alloc(dev, map,
> +						v->use_hw_usr);
> +		hdmi_tx_dmactl->hw_chs_sel = devm_regmap_field_alloc(dev, map,
> +						v->hw_chs_sel);
> +		hdmi_tx_dmactl->hw_usr_sel = devm_regmap_field_alloc(dev, map,
> +						v->hw_usr_sel);
> +		if (IS_ERR(hdmi_tx_dmactl->use_hw_chs) ||
> +			IS_ERR(hdmi_tx_dmactl->use_hw_usr) ||
> +			IS_ERR(hdmi_tx_dmactl->hw_chs_sel) ||
> +			IS_ERR(hdmi_tx_dmactl->hw_usr_sel))
> +			return -EINVAL;
> +	}
> +	return 0;
> +
> +}
> +EXPORT_SYMBOL(lpass_hdmi_init_bitfields);
> +
> +static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,
> +		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
> +{
> +	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	snd_pcm_format_t format = params_format(params);
> +	unsigned int rate = params_rate(params);
> +	unsigned int channels = params_channels(params);
> +	unsigned int ret;
> +	unsigned int bitwidth;
> +	unsigned int word_length;
> +	unsigned int ch_sts_buf0;
> +	unsigned int ch_sts_buf1;
> +	unsigned int data_format;
> +	unsigned int sampling_freq;
> +	unsigned int ch = 0;
> +
> +	bitwidth = snd_pcm_format_width(format);
> +	if (bitwidth < 0) {
> +		dev_err(dai->dev, "%s invalid bit width given : %d\n",
> +					__func__, bitwidth);
> +		return bitwidth;
> +	}
> +
> +	switch (bitwidth) {
> +	case 16:
> +		word_length = LPASS_DP_AUDIO_BITWIDTH16;
> +		break;
> +	case 24:
> +		word_length = LPASS_DP_AUDIO_BITWIDTH24;
> +		break;
> +	default:
> +		dev_err(dai->dev, "%s invalid bit width given : %d\n",
> +					__func__, bitwidth);
> +		return -EINVAL;
> +	}
> +
> +	switch (rate) {
> +	case 32000:
> +		sampling_freq = LPASS_SAMPLING_FREQ32;
> +		break;
> +	case 44100:
> +		sampling_freq = LPASS_SAMPLING_FREQ44;
> +		break;
> +	case 48000:
> +		sampling_freq = LPASS_SAMPLING_FREQ48;
> +		break;
> +
> +	default:
> +		dev_err(dai->dev, "%s invalid bit width given : %d\n",
> +					__func__, bitwidth);
> +		return -EINVAL;
> +	}
> +	data_format = LPASS_DATA_FORMAT_LINEAR;
> +	ch_sts_buf0 = (((data_format << LPASS_DATA_FORMAT_SHIFT) & LPASS_DATA_FORMAT_MASK)
> +				| ((sampling_freq << LPASS_FREQ_BIT_SHIFT) & LPASS_FREQ_BIT_MASK));
> +	ch_sts_buf1 = (word_length) & LPASS_WORDLENGTH_MASK;
> +
> +	ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_RESET);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_CLEAR);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->legacy->legacy_en,
> +				LPASS_HDMITX_LEGACY_DISABLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->tx_parity->calc_en,
> +				HDMITX_PARITY_CALC_EN);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->vbit_ctl->replace_vbit,
> +					REPLACE_VBIT);
> +	if (ret)
> +
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->vbit_ctl->vbit_stream,
> +					LINEAR_PCM_DATA);
> +	if (ret)
> +
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->ch_msb[0]->msb_bits, ch_sts_buf1);
> +	if (ret)
> +
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->ch_lsb[0]->lsb_bits, ch_sts_buf0);
> +	if (ret)
> +
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_chs,
> +				HW_MODE);
> +	if (ret)
> +
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_chs_sel,
> +				SW_MODE);
> +	if (ret)
> +
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_usr,
> +				HW_MODE);
> +	if (ret)
> +
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_usr_sel,
> +				SW_MODE);
> +	if (ret)
> +
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->meta_ctl->mute,
> +				LPASS_MUTE_ENABLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->meta_ctl->as_sdp_cc,
> +				channels - 1);
> +	if (ret)
> +		return ret;
> +
> +
> +	ret = regmap_field_write(drvdata->meta_ctl->as_sdp_ct,
> +				LPASS_META_DEFAULT_VAL);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->meta_ctl->aif_db4,
> +				LPASS_META_DEFAULT_VAL);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->meta_ctl->frequency, sampling_freq);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->meta_ctl->mst_index,
> +				LPASS_META_DEFAULT_VAL);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->meta_ctl->dptx_index,
> +				LPASS_META_DEFAULT_VAL);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
> +				LPASS_SSTREAM_DISABLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->dma_sel, ch);
> +	if (ret)
> +		return ret;
> +
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->auto_bbit_en,
> +				LPASS_SSTREAM_DEFAULT_ENABLE);
> +	if (ret)
> +		return ret;
> +
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->layout,
> +				LPASS_SSTREAM_DEFAULT_DISABLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->layout_sp,
> +				LPASS_LAYOUT_SP_DEFAULT);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->dp_audio,
> +				LPASS_SSTREAM_DEFAULT_ENABLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->set_sp_on_en,
> +				LPASS_SSTREAM_DEFAULT_ENABLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->dp_sp_b_hw_en,
> +				LPASS_SSTREAM_DEFAULT_ENABLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->dp_staffing_en,
> +				LPASS_SSTREAM_DEFAULT_ENABLE);
> +	if (ret)
> +
> +		return ret;
> +
> +	return ret;
> +}
> +
> +
> +
too many empty lines !

> +static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream *substream,
> +		struct snd_soc_dai *dai)
> +{
> +	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	int ret;
> +
> +	ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
> +					LPASS_SSTREAM_ENABLE);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_field_write(drvdata->meta_ctl->mute,
> +					LPASS_MUTE_DISABLE);
> +	if (ret)
> +		return ret;
> +
> +	return ret;
> +}
> +
> +static int lpass_hdmi_daiops_trigger(struct snd_pcm_substream *substream,
> +		int cmd, struct snd_soc_dai *dai)
> +{
> +	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	int ret = -EINVAL;
> +
> +	switch (cmd) {
> +	case SNDRV_PCM_TRIGGER_START:
> +	case SNDRV_PCM_TRIGGER_RESUME:
> +	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
> +
unnecessary space!
> +		ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
> +					LPASS_SSTREAM_ENABLE);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_field_write(drvdata->meta_ctl->mute,
> +					LPASS_MUTE_DISABLE);
> +		if (ret)
> +			return ret;
> +
> +		break;
> +	case SNDRV_PCM_TRIGGER_STOP:
> +	case SNDRV_PCM_TRIGGER_SUSPEND:
> +	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
> +
> +		ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
> +					LPASS_SSTREAM_DISABLE);
> +		if (ret)
> +			return ret;
> +
> +
> +		ret = regmap_field_write(drvdata->meta_ctl->mute,
> +					LPASS_MUTE_ENABLE);
> +		if (ret)
> +			return ret;
> +
> +		ret = regmap_field_write(drvdata->sstream_ctl->dp_audio, 0);
> +		if (ret)
> +			return ret;
> +
> +		break;
> +	}
> +	return ret;
> +}
> +
> +const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = {
> +	.hw_params	= lpass_hdmi_daiops_hw_params,
> +	.prepare	= lpass_hdmi_daiops_prepare,
> +	.trigger	= lpass_hdmi_daiops_trigger,
> +};
> +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops);
> +
> +
> +
too many empty lines??


> +static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
> +{
> +	struct lpass_data *drvdata = dev_get_drvdata(dev);
> +	struct lpass_variant *v = drvdata->variant;
> +	int i;
> +
> +	if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
> +		return true;
> +	if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
> +		return true;
> +	if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
> +		return true;
> +
switch case should make this much cleaner.

> +	for (i = 0; i < v->hdmi_rdma_channels; i++) {
> +		if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
> +			return true;
> +		if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
> +			return true;
> +		if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
> +			return true;
> +	}
> +
> +	if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
> +		return true;
> +	if (reg == LPASS_HDMI_TX_DP_ADDR(v))
> +		return true;
> +	if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
> +		return true;
> +
> +	if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
> +		return true;
> +	if (reg == LPASS_HDMITX_APP_IRQCLEAR_REG(v))
> +		return true;
> +
> +	for (i = 0; i < v->rdma_channels; ++i) {
> +		if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
> +			return true;
> +		if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
> +			return true;
> +		if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
> +			return true;
> +		if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
> +			return true;
> +
> +	}
> +	return false;
> +}
> +
> +static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
> +{
> +	struct lpass_data *drvdata = dev_get_drvdata(dev);
> +	struct lpass_variant *v = drvdata->variant;
> +	int i;
> +
> +	if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
> +		return true;
> +	if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
> +		return true;
> +	if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
> +		return true;

Same here, use switch case
> +
> +	for (i = 0; i < v->hdmi_rdma_channels; i++) {
> +		if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
> +			return true;
> +		if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
> +			return true;
> +		if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
> +			return true;
> +	}

> +
> +	if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
> +		return true;
> +	if (reg == LPASS_HDMI_TX_DP_ADDR(v))
> +		return true;
> +	if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
> +		return true;
> +
> +	if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
> +		return true;
> +	if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
> +		return true;
> +
> +	for (i = 0; i < v->rdma_channels; ++i) {
> +		if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
> +			return true;
> +		if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
> +			return true;
> +		if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
> +			return true;
> +		if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
> +			return true;
> +		if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
> +{
> +	return true;

Are all the register range really volatile?

> +
> +}
> +struct regmap_config lpass_hdmi_regmap_config = {
> +	.reg_bits = 32,
> +	.reg_stride = 4,
> +	.val_bits = 32,
> +	.writeable_reg = lpass_hdmi_regmap_writeable,
> +	.readable_reg = lpass_hdmi_regmap_readable,
> +	.volatile_reg = lpass_hdmi_regmap_volatile,
> +	.cache_type = REGCACHE_FLAT,

Any reason for using FLAT cache type ??

> +};
> +EXPORT_SYMBOL(lpass_hdmi_regmap_config);
> +
> +MODULE_DESCRIPTION("QTi LPASS HDMI Driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/sound/soc/qcom/lpass-hdmi.h b/sound/soc/qcom/lpass-hdmi.h
> new file mode 100644
> index 0000000..f91f322
> --- /dev/null
> +++ b/sound/soc/qcom/lpass-hdmi.h
> @@ -0,0 +1,129 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * Copyright (c) 2020 The Linux Foundation. All rights reserved.
> + *
> + * lpass_hdmi.h - Definitions for the QTi LPASS HDMI
> + */
> +
> +#ifndef __LPASS_HDMI_H__
> +#define __LPASS_HDMI_H__
> +
> +#include <linux/clk.h>
> +#include <linux/compiler.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#define LPASS_HDMITX_LEGACY_DISABLE		0x0
> +#define LPASS_HDMITX_LEGACY_ENABLE		0x1
> +#define LPASS_DP_AUDIO_BITWIDTH16		0x0
> +#define LPASS_DP_AUDIO_BITWIDTH24		0xb
> +#define LPASS_DATA_FORMAT_SHIFT			0x1
> +#define LPASS_DATA_FORMAT_MASK			0x2
> +#define LPASS_FREQ_BIT_SHIFT			24
> +#define LPASS_FREQ_BIT_MASK			0xf000000

use GENMASK macro for all such masks.

> +#define LPASS_DATA_FORMAT_LINEAR		0x0
> +#define LPASS_DATA_FORMAT_NON_LINEAR		0x1
> +#define LPASS_SAMPLING_FREQ32			0x3
> +#define LPASS_SAMPLING_FREQ44			0x0
> +#define LPASS_SAMPLING_FREQ48			0x2
> +#define LPASS_TX_CTL_RESET			0x1
> +#define LPASS_TX_CTL_CLEAR			0x0
> +#define LPASS_SSTREAM_ENABLE			1
> +#define LPASS_SSTREAM_DISABLE			0
> +#define LPASS_LAYOUT_SP_DEFAULT			0xf
> +#define LPASS_SSTREAM_DEFAULT_ENABLE		1
> +#define LPASS_SSTREAM_DEFAULT_DISABLE		0
> +#define LPASS_WORDLENGTH_MASK			0xf
> +#define LPASS_MUTE_ENABLE			1
> +#define LPASS_MUTE_DISABLE			0
> +#define LPASS_META_DEFAULT_VAL			0
> +#define HW_MODE					1
> +#define SW_MODE					0
> +#define LEGACY_LPASS_LPAIF			1
> +#define LEGACY_LPASS_HDMI			0
> +#define REPLACE_VBIT				0x1
> +#define LINEAR_PCM_DATA				0x0
> +#define NON_LINEAR_PCM_DATA			0x1
> +#define HDMITX_PARITY_CALC_EN			0x1
> +#define HDMITX_PARITY_CALC_DIS			0x0
> +
> +
> +#define LPASS_HDMI_TX_CTL_ADDR(v) \
> +		(v->hdmi_tx_ctl_addr)
> +
> +#define LPASS_HDMI_TX_LEGACY_ADDR(v) \
> +		(v->hdmi_legacy_addr)
> +#define LPASS_HDMI_TX_VBIT_CTL_ADDR(v) \
> +		(v->hdmi_vbit_addr)
above three macros should be able to go in single lines!! Not sure why 
you are adding an extra break, which makes it very odd for reading.

> +#define LPASS_HDMI_TX_CH_LSB_ADDR(v, port) \
> +		(v->hdmi_ch_lsb_addr + \
> +		v->ch_stride * (port))
> +#define LPASS_HDMI_TX_CH_MSB_ADDR(v, port) \
> +		(v->hdmi_ch_msb_addr + \
> +		v->ch_stride * (port))
> +#define LPASS_HDMI_TX_DMA_ADDR(v, port) \
> +		(v->hdmi_dmactl_addr + \
> +		v->hdmi_dma_stride * (port))
> +#define LPASS_HDMI_TX_PARITY_ADDR(v) \
> +		(v->hdmi_parity_addr)
> +#define LPASS_HDMI_TX_DP_ADDR(v) \
> +		(v->hdmi_DP_addr)
> +#define LPASS_HDMI_TX_SSTREAM_ADDR(v) \
> +		(v->hdmi_sstream_addr)
> +
> +struct lpass_sstream_ctl {
> +	struct regmap_field *sstream_en;
> +	struct regmap_field *dma_sel;
> +	struct regmap_field *auto_bbit_en;
> +	struct regmap_field *layout;
> +	struct regmap_field *layout_sp;
> +	struct regmap_field *set_sp_on_en;
> +	struct regmap_field *dp_audio;
> +	struct regmap_field *dp_staffing_en;
> +	struct regmap_field *dp_sp_b_hw_en;
> +};
> +
> +struct lpass_dp_metadata_ctl {
> +	struct regmap_field *mute;
> +	struct regmap_field *as_sdp_cc;
> +	struct regmap_field *as_sdp_ct;
> +	struct regmap_field *aif_db4;
> +	struct regmap_field *frequency;
> +	struct regmap_field *mst_index;
> +	struct regmap_field *dptx_index;
> +};
> +
> +struct lpass_hdmi_tx_ctl {
> +	struct regmap_field *soft_reset;
> +	struct regmap_field *force_reset;
> +};
> +
> +struct lpass_hdmitx_dmactl {
> +	struct regmap_field *use_hw_chs;
> +	struct regmap_field *use_hw_usr;
> +	struct regmap_field *hw_chs_sel;
> +	struct regmap_field *hw_usr_sel;
> +};
> +
> +struct lpass_vbit_ctrl {
> +		struct regmap_field *replace_vbit;
> +		struct regmap_field *vbit_stream;
> +};
> +
> +struct  lpass_hdmitx_legacy {
> +	struct regmap_field *legacy_en;
> +};
> +
> +struct  lpass_hdmi_tx_parity {
> +	struct regmap_field *calc_en;
> +};
> +
> +struct  lpass_hdmi_tx_ch_lsb {
> +	struct regmap_field *lsb_bits;
> +};
> +
> +struct  lpass_hdmi_tx_ch_msb {
> +	struct regmap_field *msb_bits;
> +};
> +
> +#endif /* __LPASS_HDMI_H__ */
> diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
> index 72f09b3..832a916 100644
> --- a/sound/soc/qcom/lpass-ipq806x.c
> +++ b/sound/soc/qcom/lpass-ipq806x.c
> @@ -96,7 +96,7 @@ static int ipq806x_lpass_exit(struct platform_device *pdev)
>   	return 0;
>   }
>   
> -static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir)
> +static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir, unsigned int dai_id)
>   {
>   	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
>   		return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
> @@ -104,7 +104,7 @@ static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir)
>   		return -EINVAL;
>   }
>   
> -static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
> +static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
>   {
>   	return 0;
>   }
> diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
> index 5258e60..42aebd4 100644
> --- a/sound/soc/qcom/lpass-lpaif-reg.h
> +++ b/sound/soc/qcom/lpass-lpaif-reg.h
> @@ -9,7 +9,8 @@
>   /* LPAIF I2S */
>   
>   #define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
> -	(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
> +	(v->i2sctrl_reg_base + (addr) + \
> +	v->i2sctrl_reg_stride * (port))
>   
>   #define LPAIF_I2SCTL_REG(v, port)	LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port))
>   
> @@ -70,6 +71,14 @@
>   #define LPAIF_IRQSTAT_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x4, (port))
>   #define LPAIF_IRQCLEAR_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0xC, (port))
>   
> +
> +#define LPASS_HDMITX_APP_IRQ_REG_ADDR(v, addr)  \
> +	((v->hdmi_irq_reg_base) + (addr))
> +
> +#define LPASS_HDMITX_APP_IRQEN_REG(v)			LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0x4)
> +#define LPASS_HDMITX_APP_IRQSTAT_REG(v)			LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0x8)
> +#define LPASS_HDMITX_APP_IRQCLEAR_REG(v)		LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0xC)
> +
>   #define LPAIF_IRQ_BITSTRIDE		3
>   
>   #define LPAIF_IRQ_PER(chan)		(1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
> @@ -77,8 +86,22 @@
>   #define LPAIF_IRQ_ERR(chan)		(4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
>   
>   #define LPAIF_IRQ_ALL(chan)		(7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
> +#define LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan)	(1 << (14 + chan))
> +#define LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan)	(1 << (24 + chan))
> +#define LPAIF_IRQ_HDMI_METADONE		BIT(23)
>   
>   /* LPAIF DMA */
> +#define LPAIF_HDMI_RDMA_REG_ADDR(v, addr, chan) \
> +	(v->hdmi_rdma_reg_base + (addr) + v->hdmi_rdma_reg_stride * (chan))
> +
> +#define LPAIF_HDMI_RDMACTL_AUDINTF(id)	(id << LPAIF_RDMACTL_AUDINTF_SHIFT)
> +
> +#define LPAIF_HDMI_RDMACTL_REG(v, chan)		LPAIF_HDMI_RDMA_REG_ADDR(v, 0x00, (chan))
> +#define LPAIF_HDMI_RDMABASE_REG(v, chan)	LPAIF_HDMI_RDMA_REG_ADDR(v, 0x04, (chan))
> +#define	LPAIF_HDMI_RDMABUFF_REG(v, chan)	LPAIF_HDMI_RDMA_REG_ADDR(v, 0x08, (chan))
> +#define LPAIF_HDMI_RDMACURR_REG(v, chan)	LPAIF_HDMI_RDMA_REG_ADDR(v, 0x0C, (chan))
> +#define	LPAIF_HDMI_RDMAPER_REG(v, chan)		LPAIF_HDMI_RDMA_REG_ADDR(v, 0x10, (chan))
> +#define	LPAIF_HDMI_RDMAPERCNT_REG(v, chan)	LPAIF_HDMI_RDMA_REG_ADDR(v, 0x14, (chan))
>   
>   #define LPAIF_RDMA_REG_ADDR(v, addr, chan) \
>   	(v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan))
> @@ -103,17 +126,22 @@
>   #define	LPAIF_WRDMAPER_REG(v, chan)	LPAIF_WRDMA_REG_ADDR(v, 0x10, (chan))
>   #define	LPAIF_WRDMAPERCNT_REG(v, chan)	LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan))
>   
> -#define __LPAIF_DMA_REG(v, chan, dir, reg)  \
> -	(dir ==  SNDRV_PCM_STREAM_PLAYBACK) ? \
> -		LPAIF_RDMA##reg##_REG(v, chan) : \
> -		LPAIF_WRDMA##reg##_REG(v, chan)
> -
> -#define LPAIF_DMACTL_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CTL)
> -#define LPAIF_DMABASE_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BASE)
> -#define	LPAIF_DMABUFF_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BUFF)
> -#define LPAIF_DMACURR_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CURR)
> -#define	LPAIF_DMAPER_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PER)
> -#define	LPAIF_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PERCNT)
> +#define LPAIF_INTFDMA_REG(v, chan, reg, dai_id)  \
> +		((v->dai_driver[dai_id].id ==  LPASS_DP_RX) ? \
> +		LPAIF_HDMI_RDMA##reg##_REG(v, chan) : \
> +		 LPAIF_RDMA##reg##_REG(v, chan))
> +
> +#define __LPAIF_DMA_REG(v, chan, dir, reg, dai_id)  \
> +	((dir ==  SNDRV_PCM_STREAM_PLAYBACK) ? \
> +		(LPAIF_INTFDMA_REG(v, chan, reg, dai_id)) : \
> +		LPAIF_WRDMA##reg##_REG(v, chan))
> +
> +#define LPAIF_DMACTL_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, CTL, dai_id)
> +#define LPAIF_DMABASE_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, BASE, dai_id)
> +#define	LPAIF_DMABUFF_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, BUFF, dai_id)
> +#define LPAIF_DMACURR_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, CURR, dai_id)
> +#define	LPAIF_DMAPER_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, PER, dai_id)
> +#define	LPAIF_DMAPERCNT_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, PERCNT, dai_id)
>   
>   #define LPAIF_DMACTL_BURSTEN_SINGLE	0
>   #define LPAIF_DMACTL_BURSTEN_INCR4	1
> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> index 35aead1..e2d1f25 100644
> --- a/sound/soc/qcom/lpass-platform.c
> +++ b/sound/soc/qcom/lpass-platform.c
> @@ -23,7 +23,7 @@ struct lpass_pcm_data {
>   	int i2s_port;
>   };
>   
> -#define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
> +#define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)
>   #define LPASS_PLATFORM_PERIODS		2
>   
>   static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
> @@ -62,41 +62,79 @@ static int lpass_platform_alloc_dmactl_fields(struct device *dev,
>   	if (drvdata->rd_dmactl == NULL)
>   		return -ENOMEM;
>   
> -	drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
> -					  GFP_KERNEL);
> -	if (drvdata->wr_dmactl == NULL)
> -		return -ENOMEM;
> -
>   	rd_dmactl = drvdata->rd_dmactl;
> -	wr_dmactl = drvdata->wr_dmactl;
>   
>   	rd_dmactl->bursten = devm_regmap_field_alloc(dev, map, v->rdma_bursten);
>   	rd_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, v->rdma_wpscnt);
>   	rd_dmactl->fifowm = devm_regmap_field_alloc(dev, map, v->rdma_fifowm);
> -	rd_dmactl->intf = devm_regmap_field_alloc(dev, map, v->rdma_intf);
>   	rd_dmactl->enable = devm_regmap_field_alloc(dev, map, v->rdma_enable);
>   	rd_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, v->rdma_dyncclk);
> -
> +	rd_dmactl->intf = devm_regmap_field_alloc(dev, map, v->rdma_intf);
>   	if (IS_ERR(rd_dmactl->bursten) || IS_ERR(rd_dmactl->wpscnt) ||
> -	    IS_ERR(rd_dmactl->fifowm) || IS_ERR(rd_dmactl->intf) ||
> -	    IS_ERR(rd_dmactl->enable) || IS_ERR(rd_dmactl->dyncclk))
> +	    IS_ERR(rd_dmactl->fifowm) || IS_ERR(rd_dmactl->dyncclk) ||
> +	    IS_ERR(rd_dmactl->enable) || IS_ERR(rd_dmactl->intf))
>   		return -EINVAL;
> +	drvdata->wr_dmactl = devm_kzalloc(dev,
> +			sizeof(struct lpaif_dmactl), GFP_KERNEL);
> +	if (drvdata->wr_dmactl == NULL)
> +		return -ENOMEM;
>   
> -	wr_dmactl->bursten = devm_regmap_field_alloc(dev, map, v->wrdma_bursten);
> -	wr_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, v->wrdma_wpscnt);
> -	wr_dmactl->fifowm = devm_regmap_field_alloc(dev, map, v->wrdma_fifowm);
> -	wr_dmactl->intf = devm_regmap_field_alloc(dev, map, v->wrdma_intf);
> -	wr_dmactl->enable = devm_regmap_field_alloc(dev, map, v->wrdma_enable);
> -	wr_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, v->wrdma_dyncclk);
> +	wr_dmactl = drvdata->wr_dmactl;
> +
> +	wr_dmactl->bursten = devm_regmap_field_alloc(dev, map,
> +						v->wrdma_bursten);
> +	wr_dmactl->wpscnt = devm_regmap_field_alloc(dev, map,
> +						v->wrdma_wpscnt);
> +	wr_dmactl->fifowm = devm_regmap_field_alloc(dev, map,
> +						v->wrdma_fifowm);
> +	wr_dmactl->intf = devm_regmap_field_alloc(dev, map,
> +						v->wrdma_intf);
> +	wr_dmactl->enable = devm_regmap_field_alloc(dev, map,
> +						v->wrdma_enable);
> +	wr_dmactl->dyncclk = devm_regmap_field_alloc(dev, map,
> +						v->wrdma_dyncclk);

Can you explain what is happening here, these chagnes just look like 
spllitting one line into two!


I should stop reviewing at this point!
As I have seen some general issues with the patch like
- doing un-needed changes!
- removing #ifdef checks.
- try to come up with some api/macro to simplify field allocs as they 
seems to be all over the place!

thanks,
srini
Srinivasa Rao Mandadapu Sept. 23, 2020, 8:41 a.m. UTC | #2
Thanks for review Srinivas!!!

On 9/22/2020 2:50 AM, Srinivas Kandagatla wrote:
>
>
> On 18/09/2020 07:04, Srinivasa Rao Mandadapu wrote:
>> From: V Sujith Kumar Reddy <vsujithk@codeaurora.org>
>>
>> Upadate lpass cpu and platform driver to support audio over dp.
>> Also add lpass-hdmi.c and lpass-hdmi.h.
>>
>> Signed-off-by: Srinivasa Rao <srivasam@codeaurora.org>
>> Signed-off-by: V Sujith Kumar Reddy <vsujithk@codeaurora.org>
>> ---
>>   sound/soc/qcom/Kconfig           |   5 +
>>   sound/soc/qcom/Makefile          |   2 +
>>   sound/soc/qcom/lpass-apq8016.c   |   4 +-
>>   sound/soc/qcom/lpass-cpu.c       |  37 ++-
>>   sound/soc/qcom/lpass-hdmi.c      | 596 
>> +++++++++++++++++++++++++++++++++++++++
>>   sound/soc/qcom/lpass-hdmi.h      | 129 +++++++++
>>   sound/soc/qcom/lpass-ipq806x.c   |   4 +-
>>   sound/soc/qcom/lpass-lpaif-reg.h |  52 +++-
>>   sound/soc/qcom/lpass-platform.c  | 466 ++++++++++++++++++++++++------
>>   sound/soc/qcom/lpass.h           | 119 +++++++-
>>   10 files changed, 1294 insertions(+), 120 deletions(-)
>>   create mode 100644 sound/soc/qcom/lpass-hdmi.c
>>   create mode 100644 sound/soc/qcom/lpass-hdmi.h
>>
>> diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
>> index a607ace..509584c 100644
>> --- a/sound/soc/qcom/Kconfig
>> +++ b/sound/soc/qcom/Kconfig
>> @@ -12,6 +12,10 @@ config SND_SOC_LPASS_CPU
>>       tristate
>>       select REGMAP_MMIO
>>   +config SND_SOC_LPASS_HDMI
>> +    tristate
>> +    select REGMAP_MMIO
>> +
>>   config SND_SOC_LPASS_PLATFORM
>>       tristate
>>       select REGMAP_MMIO
>> @@ -30,6 +34,7 @@ config SND_SOC_LPASS_SC7180
>>       tristate
>>       select SND_SOC_LPASS_CPU
>>       select SND_SOC_LPASS_PLATFORM
>> +    select SND_SOC_LPASS_HDMI
>>     config SND_SOC_STORM
>>       tristate "ASoC I2S support for Storm boards"
>> diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
>> index 7972c94..0bd90d7 100644
>> --- a/sound/soc/qcom/Makefile
>> +++ b/sound/soc/qcom/Makefile
>> @@ -1,12 +1,14 @@
>>   # SPDX-License-Identifier: GPL-2.0
>>   # Platform
>>   snd-soc-lpass-cpu-objs := lpass-cpu.o
>> +snd-soc-lpass-hdmi-objs := lpass-hdmi.o
>>   snd-soc-lpass-platform-objs := lpass-platform.o
>>   snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
>>   snd-soc-lpass-apq8016-objs := lpass-apq8016.o
>>   snd-soc-lpass-sc7180-objs := lpass-sc7180.o
>>     obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
>> +obj-$(CONFIG_SND_SOC_LPASS_HDMI) += snd-soc-lpass-hdmi.o
>>   obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
>>   obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
>>   obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
>> diff --git a/sound/soc/qcom/lpass-apq8016.c 
>> b/sound/soc/qcom/lpass-apq8016.c
>> index 5c8ae22..0aedb3a 100644
>> --- a/sound/soc/qcom/lpass-apq8016.c
>> +++ b/sound/soc/qcom/lpass-apq8016.c
>> @@ -125,7 +125,7 @@ static struct snd_soc_dai_driver 
>> apq8016_lpass_cpu_dai_driver[] = {
>>   };
>>     static int apq8016_lpass_alloc_dma_channel(struct lpass_data 
>> *drvdata,
>> -                       int direction)
>> +                       int direction, unsigned int dai_id)
>>   {
>>       struct lpass_variant *v = drvdata->variant;
>>       int chan = 0;
>> @@ -151,7 +151,7 @@ static int apq8016_lpass_alloc_dma_channel(struct 
>> lpass_data *drvdata,
>>       return chan;
>>   }
>>   -static int apq8016_lpass_free_dma_channel(struct lpass_data 
>> *drvdata, int chan)
>> +static int apq8016_lpass_free_dma_channel(struct lpass_data 
>> *drvdata, int chan, unsigned int dai_id)
>>   {
>>       clear_bit(chan, &drvdata->dma_ch_bit_map);
>>   diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
>> index 5d84f63..41a2470 100644
>> --- a/sound/soc/qcom/lpass-cpu.c
>> +++ b/sound/soc/qcom/lpass-cpu.c
>> @@ -589,13 +589,33 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
>> platform_device *pdev)
>>                           variant->wrdma_channel_start);
>>         drvdata->lpaif_map = devm_regmap_init_mmio(dev, drvdata->lpaif,
>> -            &lpass_cpu_regmap_config);
>> +                                &lpass_cpu_regmap_config);
>
> change not related to this patch!
>
> Have you run checkpatch on this patch
>
>>       if (IS_ERR(drvdata->lpaif_map)) {
>>           dev_err(dev, "error initializing regmap: %ld\n",
>>               PTR_ERR(drvdata->lpaif_map));
>>           return PTR_ERR(drvdata->lpaif_map);
>>       }
>> +#ifdef CONFIG_SND_SOC_LPASS_SC7180
> No, this is not the right way to do it!
> We can not have any ifdef with in the code, we should be able to cope 
> up with finding if hdmiif resources are available or not!
>
> You should proably look at variant data to see which resources are 
> required or not! That should work and also get rid of this #ifdef
Okay. will remove this.
>
>
>
>> +    res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 
>> "lpass-hdmiif");
>>   +    drvdata->hdmiif = devm_ioremap_resource(dev, res);
>> +    if (IS_ERR((void const __force *)drvdata->hdmiif)) {
>> +        dev_err(dev, "error mapping reg resource: %ld\n",
>> +                PTR_ERR((void const __force *)drvdata->hdmiif));
>> +        return PTR_ERR((void const __force *)drvdata->hdmiif);
>> +    }
>> +
>> +    lpass_hdmi_regmap_config.max_register = 
>> LPAIF_HDMI_RDMAPER_REG(variant,
>> +                variant->hdmi_rdma_channels);
>> +    drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
>> +                &lpass_hdmi_regmap_config);
>> +    if (IS_ERR(drvdata->hdmiif_map)) {
>> +        dev_err(dev, "error initializing regmap: %ld\n",
>> +        PTR_ERR(drvdata->hdmiif_map));
>> +        return PTR_ERR(drvdata->hdmiif_map);
>> +    }
>> +
>> +#endif
>>       if (variant->init) {
>>           ret = variant->init(pdev);
>>           if (ret) {
>> @@ -606,6 +626,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
>> platform_device *pdev)
>>         for (i = 0; i < variant->num_dai; i++) {
>>           dai_id = variant->dai_driver[i].id;
>> +        if (dai_id == LPASS_DP_RX)
>> +            continue;
>> +
>>           drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(dev,
>>                            variant->dai_osr_clk_names[i]);
>>           if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
>> @@ -625,10 +648,10 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
>> platform_device *pdev)
>>                   "error getting %s: %ld\n",
>>                   variant->dai_bit_clk_names[i],
>>                   PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
>> +
>
> change not related to this patch!
Okay.
>
>>               return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
>>           }
>>       }
>> -
>
> change not related to this patch!
Okay.
>
>
>>       /* Allocation for i2sctl regmap fields */
>>       drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct 
>> lpaif_i2sctl),
>>                       GFP_KERNEL);
>> @@ -636,10 +659,18 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
>> platform_device *pdev)
>>       /* Initialize bitfields for dai I2SCTL register */
>>       ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
>>                           drvdata->lpaif_map);
>> -    if (ret) {
>> +    if (ret)
>>           dev_err(dev, "error init i2sctl field: %d\n", ret);
>> +
>> +#ifdef CONFIG_SND_SOC_LPASS_SC7180
>> +    ret = lpass_hdmi_init_bitfields(dev, drvdata->hdmiif_map);
>> +    if (ret) {
>> +        dev_err(dev, "%s error  hdmi init failed\n", __func__);
>>           return ret;
>>       }
>> +#else
>> +    return -EINVAL;
>> +#endif
>>         ret = devm_snd_soc_register_component(dev,
>>                             &lpass_cpu_comp_driver,
>> diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c
>> new file mode 100644
>> index 0000000..7cb2ba3
>> --- /dev/null
>> +++ b/sound/soc/qcom/lpass-hdmi.c
>> @@ -0,0 +1,596 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + * Copyright (c) 2020 The Linux Foundation. All rights reserved.
>> + *
>> + * lpass-hdmi.c -- ALSA SoC HDMI-CPU DAI driver for QTi LPASS HDMI
>> + */
>> +
>> +#include <linux/clk.h>
> Do you need this header?
>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
> <<<
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
> >>>
> Do you need these headers?
Will remove redundant headers.
>
>> +#include <sound/pcm.h>
>> +#include <sound/pcm_params.h>
>> +#include <linux/regmap.h>
>> +#include <sound/soc.h>
>> +#include <sound/soc-dai.h>
>> +#include <dt-bindings/sound/sc7180-lpass.h>
>> +#include "lpass-lpaif-reg.h"
>> +#include "lpass.h"
>> +#include "lpass-hdmi.h"
>> +
>> +int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
>> +{
>> +    struct lpass_data *drvdata = dev_get_drvdata(dev);
>> +    struct lpass_variant *v = drvdata->variant;
>> +    unsigned int i;
>> +    struct lpass_hdmi_tx_ctl *tx_ctl;
>> +    struct lpass_hdmitx_legacy *legacy;
>> +    struct lpass_vbit_ctrl *vbit_ctl;
>> +    struct lpass_hdmi_tx_parity *tx_parity;
>> +    struct lpass_dp_metadata_ctl *meta_ctl;
>> +    struct lpass_sstream_ctl *sstream_ctl;
>> +    struct lpass_hdmi_tx_ch_msb *ch_msb;
>> +    struct lpass_hdmi_tx_ch_lsb *ch_lsb;
>> +    struct lpass_hdmitx_dmactl *hdmi_tx_dmactl;
>> +
>> +    drvdata->tx_ctl = devm_kzalloc(dev, sizeof(struct 
>> lpass_hdmi_tx_ctl),
>> +                    GFP_KERNEL);
>> +    if (drvdata->tx_ctl == NULL)
>> +        return -ENOMEM;
>> +
>> +    tx_ctl = drvdata->tx_ctl;
>> +    tx_ctl->soft_reset = devm_regmap_field_alloc(dev, map,
>> +                v->soft_reset);
>> +    tx_ctl->force_reset = devm_regmap_field_alloc(dev, map,
>> +                v->force_reset);
>> +    if (IS_ERR(tx_ctl->soft_reset) || IS_ERR(tx_ctl->force_reset))
>> +        return -EINVAL;
>> +
>> +    drvdata->legacy = devm_kzalloc(dev, sizeof(struct 
>> lpass_hdmitx_legacy),
>
> consider doing something like this to save uncessary long lines here! 
> which makes code unreadable.
okay.
>
>
> legacy = devm_kzalloc(dev, sizeof(*legacy), GFP_KERNEL);
> if (!legacy)
>     return -ENOMEM
>
> drvdata->legacy = legacy;
>
>
> use sizeof(*legacy) and same comment to other parts of the code!
>
>
>> +                    GFP_KERNEL);
>> +    if (drvdata->legacy == NULL)
>> +        return -ENOMEM;
>> +
>> +    legacy = drvdata->legacy;
>> +    legacy->legacy_en = devm_regmap_field_alloc(dev, map,
>> +                v->legacy_en);
>> +    if (IS_ERR(legacy->legacy_en))
>> +        return -EINVAL;
>> +
>> +    drvdata->vbit_ctl = devm_kzalloc(dev, sizeof(struct 
>> lpass_vbit_ctrl),
>> +                    GFP_KERNEL);
>> +    if (drvdata->vbit_ctl == NULL)
>> +        return -ENOMEM;
>> +
>> +    vbit_ctl = drvdata->vbit_ctl;
>> +    vbit_ctl->replace_vbit = devm_regmap_field_alloc(dev, map,
>> +                    v->replace_vbit);
>> +    vbit_ctl->vbit_stream = devm_regmap_field_alloc(dev, map,
>> +                    v->vbit_stream);
>> +    if (IS_ERR(vbit_ctl->replace_vbit) || 
>> IS_ERR(vbit_ctl->vbit_stream))
>> +        return -EINVAL;
>> +
>> +    drvdata->tx_parity = devm_kzalloc(dev,
>> +        sizeof(struct  lpass_hdmi_tx_parity), GFP_KERNEL);
>> +
>> +    if (drvdata->tx_parity == NULL)
>> +        return -ENOMEM;
>> +
>> +    tx_parity = drvdata->tx_parity;
>> +    tx_parity->calc_en = devm_regmap_field_alloc(dev, map, v->calc_en);
>> +
>> +    if (IS_ERR(tx_parity->calc_en))
>> +        return -EINVAL;
>> +
>> +    drvdata->meta_ctl = devm_kzalloc(dev,
>> +        sizeof(struct lpass_dp_metadata_ctl), GFP_KERNEL);
>> +
>> +    if (drvdata->meta_ctl == NULL)
>> +        return -ENOMEM;
>> +
>> +    meta_ctl = drvdata->meta_ctl;
>> +    meta_ctl->mute = devm_regmap_field_alloc(dev, map, v->mute);
>> +    meta_ctl->as_sdp_cc = devm_regmap_field_alloc(dev, map,
>> +                        v->as_sdp_cc);
>> +    meta_ctl->as_sdp_ct = devm_regmap_field_alloc(dev, map,
>> +                        v->as_sdp_ct);
>> +    meta_ctl->aif_db4 = devm_regmap_field_alloc(dev, map,
>> +                        v->aif_db4);
>> +    meta_ctl->frequency = devm_regmap_field_alloc(dev, map,
>> +                        v->frequency);
>> +    meta_ctl->mst_index = devm_regmap_field_alloc(dev, map,
>> +                        v->mst_index);
> <<<<<
>> +    meta_ctl->dptx_index = devm_regmap_field_alloc(dev, map,
>> +                        v->dptx_index);
>> +
>> +    if (IS_ERR(meta_ctl->mute) || IS_ERR(meta_ctl->as_sdp_cc) ||
>> +        IS_ERR(meta_ctl->as_sdp_ct) || IS_ERR(meta_ctl->aif_db4) ||
>> +        IS_ERR(meta_ctl->frequency) || IS_ERR(meta_ctl->mst_index) ||
>> +        IS_ERR(meta_ctl->dptx_index))
>> +        return -EINVAL;
> >>>>>
>
> These type of code is allover the place, why not just add a simple 
> macro to do this.
>
> something like
>
> #define QCOM_REGMAP_FILED_ALLOC(d, m, f)    \
>     do { \
>         f = devm_regmap_field_alloc(d, m, f);     \
>         if (IS_ERR(f))                \
>             return -EINVAL;         \
>     } while (0)
>
> and call
>     QCOM_REGMAP_FILED_ALLOC(dev, map, meta_ctl->dptx_index);
>
> this will make code much cleaner IMO.
Okay.
>
> Also we can consider adding some bluk  apis to allocate regmap field
> or something 
> like!https://git.linaro.org/people/srinivas.kandagatla/linux.git/commit/?h=wip/regmap&id=03551a6e2941d71b99e2e4a5035a9de5f0df6d5d
>
> and call
> devm_regmap_field_bulk_alloc(dev, map, &sstream_ctl->sstream_en, 
> &v->sstream_en, 9);
>
> this should work as long as order of reg_field and regmap_field are 
> maintained, which in this case is true!
>
Okay.
>
>> +
>> +    drvdata->sstream_ctl = devm_kzalloc(dev,
>> +        sizeof(struct lpass_sstream_ctl), GFP_KERNEL);
>> +    if (drvdata->sstream_ctl == NULL)
>> +        return -ENOMEM;
>> +
>> +    sstream_ctl = drvdata->sstream_ctl;
>> +    sstream_ctl->sstream_en = devm_regmap_field_alloc(dev, map,
>> +                        v->sstream_en);
>> +    sstream_ctl->dma_sel = devm_regmap_field_alloc(dev, map,
>> +                        v->dma_sel);
>> +    sstream_ctl->auto_bbit_en = devm_regmap_field_alloc(dev, map,
>> +                        v->auto_bbit_en);
>> +    sstream_ctl->layout = devm_regmap_field_alloc(dev, map,
>> +                        v->layout);
>> +    sstream_ctl->layout_sp = devm_regmap_field_alloc(dev, map,
>> +                        v->layout_sp);
>> +    sstream_ctl->dp_audio = devm_regmap_field_alloc(dev, map,
>> +                        v->dp_audio);
>> +    sstream_ctl->set_sp_on_en = devm_regmap_field_alloc(dev, map,
>> +                        v->set_sp_on_en);
>> +    sstream_ctl->dp_staffing_en = devm_regmap_field_alloc(dev, map,
>> +                        v->dp_staffing_en);
>> +    sstream_ctl->dp_sp_b_hw_en = devm_regmap_field_alloc(dev, map,
>> +                        v->dp_sp_b_hw_en);
>> +
>> +    if (IS_ERR(sstream_ctl->sstream_en) || 
>> IS_ERR(sstream_ctl->dma_sel) ||
>> +        IS_ERR(sstream_ctl->auto_bbit_en) ||
>> +        IS_ERR(sstream_ctl->layout) || 
>> IS_ERR(sstream_ctl->layout_sp) ||
>> +        IS_ERR(sstream_ctl->dp_audio) ||
>> +        IS_ERR(sstream_ctl->set_sp_on_en) ||
>> +        IS_ERR(sstream_ctl->dp_staffing_en) ||
>> +        IS_ERR(sstream_ctl->dp_sp_b_hw_en))
>> +        return -EINVAL;
>> +
>> +    for (i = 0; i < LPASS_MAX_HDMI_DMA_CHANNELS; i++) {
>> +        drvdata->ch_msb[i] = devm_kzalloc(dev,
>> +            sizeof(struct lpass_hdmi_tx_ch_msb), GFP_KERNEL);
>> +        if (drvdata->ch_msb[i] == NULL)
>> +            return -ENOMEM;
>> +
>> +        ch_msb = drvdata->ch_msb[i];
>> +
>> +        ch_msb->msb_bits = devm_regmap_field_alloc(dev, map,
>> +                            v->msb_bits);
>> +        if (IS_ERR(ch_msb->msb_bits))
>> +            return -EINVAL;
>> +
>> +        drvdata->ch_lsb[i] = devm_kzalloc(dev,
>> +            sizeof(struct lpass_hdmi_tx_ch_lsb), GFP_KERNEL);
>> +        if (drvdata->ch_lsb[i] == NULL)
>> +            return -ENOMEM;
>> +
>> +        ch_lsb = drvdata->ch_lsb[i];
>> +        ch_lsb->lsb_bits = devm_regmap_field_alloc(dev, map,
>> +                    v->lsb_bits);
>> +        if (IS_ERR(ch_lsb->lsb_bits))
>> +            return -EINVAL;
>> +
>> +
>> +        drvdata->hdmi_tx_dmactl[i] = devm_kzalloc(dev,
>> +            sizeof(struct lpass_hdmitx_dmactl), GFP_KERNEL);
>> +        if (drvdata->hdmi_tx_dmactl[i] == NULL)
>> +            return -ENOMEM;
>> +
>> +        hdmi_tx_dmactl = drvdata->hdmi_tx_dmactl[i];
>> +        hdmi_tx_dmactl->use_hw_chs = devm_regmap_field_alloc(dev, map,
>> +                        v->use_hw_chs);
>> +        hdmi_tx_dmactl->use_hw_usr = devm_regmap_field_alloc(dev, map,
>> +                        v->use_hw_usr);
>> +        hdmi_tx_dmactl->hw_chs_sel = devm_regmap_field_alloc(dev, map,
>> +                        v->hw_chs_sel);
>> +        hdmi_tx_dmactl->hw_usr_sel = devm_regmap_field_alloc(dev, map,
>> +                        v->hw_usr_sel);
>> +        if (IS_ERR(hdmi_tx_dmactl->use_hw_chs) ||
>> +            IS_ERR(hdmi_tx_dmactl->use_hw_usr) ||
>> +            IS_ERR(hdmi_tx_dmactl->hw_chs_sel) ||
>> +            IS_ERR(hdmi_tx_dmactl->hw_usr_sel))
>> +            return -EINVAL;
>> +    }
>> +    return 0;
>> +
>> +}
>> +EXPORT_SYMBOL(lpass_hdmi_init_bitfields);
>> +
>> +static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream 
>> *substream,
>> +        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
>> +{
>> +    struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>> +    snd_pcm_format_t format = params_format(params);
>> +    unsigned int rate = params_rate(params);
>> +    unsigned int channels = params_channels(params);
>> +    unsigned int ret;
>> +    unsigned int bitwidth;
>> +    unsigned int word_length;
>> +    unsigned int ch_sts_buf0;
>> +    unsigned int ch_sts_buf1;
>> +    unsigned int data_format;
>> +    unsigned int sampling_freq;
>> +    unsigned int ch = 0;
>> +
>> +    bitwidth = snd_pcm_format_width(format);
>> +    if (bitwidth < 0) {
>> +        dev_err(dai->dev, "%s invalid bit width given : %d\n",
>> +                    __func__, bitwidth);
>> +        return bitwidth;
>> +    }
>> +
>> +    switch (bitwidth) {
>> +    case 16:
>> +        word_length = LPASS_DP_AUDIO_BITWIDTH16;
>> +        break;
>> +    case 24:
>> +        word_length = LPASS_DP_AUDIO_BITWIDTH24;
>> +        break;
>> +    default:
>> +        dev_err(dai->dev, "%s invalid bit width given : %d\n",
>> +                    __func__, bitwidth);
>> +        return -EINVAL;
>> +    }
>> +
>> +    switch (rate) {
>> +    case 32000:
>> +        sampling_freq = LPASS_SAMPLING_FREQ32;
>> +        break;
>> +    case 44100:
>> +        sampling_freq = LPASS_SAMPLING_FREQ44;
>> +        break;
>> +    case 48000:
>> +        sampling_freq = LPASS_SAMPLING_FREQ48;
>> +        break;
>> +
>> +    default:
>> +        dev_err(dai->dev, "%s invalid bit width given : %d\n",
>> +                    __func__, bitwidth);
>> +        return -EINVAL;
>> +    }
>> +    data_format = LPASS_DATA_FORMAT_LINEAR;
>> +    ch_sts_buf0 = (((data_format << LPASS_DATA_FORMAT_SHIFT) & 
>> LPASS_DATA_FORMAT_MASK)
>> +                | ((sampling_freq << LPASS_FREQ_BIT_SHIFT) & 
>> LPASS_FREQ_BIT_MASK));
>> +    ch_sts_buf1 = (word_length) & LPASS_WORDLENGTH_MASK;
>> +
>> +    ret = regmap_field_write(drvdata->tx_ctl->soft_reset, 
>> LPASS_TX_CTL_RESET);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->tx_ctl->soft_reset, 
>> LPASS_TX_CTL_CLEAR);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->legacy->legacy_en,
>> +                LPASS_HDMITX_LEGACY_DISABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->tx_parity->calc_en,
>> +                HDMITX_PARITY_CALC_EN);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->vbit_ctl->replace_vbit,
>> +                    REPLACE_VBIT);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->vbit_ctl->vbit_stream,
>> +                    LINEAR_PCM_DATA);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->ch_msb[0]->msb_bits, 
>> ch_sts_buf1);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->ch_lsb[0]->lsb_bits, 
>> ch_sts_buf0);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_chs,
>> +                HW_MODE);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_chs_sel,
>> +                SW_MODE);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_usr,
>> +                HW_MODE);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_usr_sel,
>> +                SW_MODE);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->meta_ctl->mute,
>> +                LPASS_MUTE_ENABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->meta_ctl->as_sdp_cc,
>> +                channels - 1);
>> +    if (ret)
>> +        return ret;
>> +
>> +
>> +    ret = regmap_field_write(drvdata->meta_ctl->as_sdp_ct,
>> +                LPASS_META_DEFAULT_VAL);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->meta_ctl->aif_db4,
>> +                LPASS_META_DEFAULT_VAL);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->meta_ctl->frequency, 
>> sampling_freq);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->meta_ctl->mst_index,
>> +                LPASS_META_DEFAULT_VAL);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->meta_ctl->dptx_index,
>> +                LPASS_META_DEFAULT_VAL);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
>> +                LPASS_SSTREAM_DISABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->dma_sel, ch);
>> +    if (ret)
>> +        return ret;
>> +
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->auto_bbit_en,
>> +                LPASS_SSTREAM_DEFAULT_ENABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->layout,
>> +                LPASS_SSTREAM_DEFAULT_DISABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->layout_sp,
>> +                LPASS_LAYOUT_SP_DEFAULT);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->dp_audio,
>> +                LPASS_SSTREAM_DEFAULT_ENABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->set_sp_on_en,
>> +                LPASS_SSTREAM_DEFAULT_ENABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->dp_sp_b_hw_en,
>> +                LPASS_SSTREAM_DEFAULT_ENABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->dp_staffing_en,
>> +                LPASS_SSTREAM_DEFAULT_ENABLE);
>> +    if (ret)
>> +
>> +        return ret;
>> +
>> +    return ret;
>> +}
>> +
>> +
>> +
> too many empty lines !
Okay. Will remove empty lines!
>
>> +static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream 
>> *substream,
>> +        struct snd_soc_dai *dai)
>> +{
>> +    struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>> +    int ret;
>> +
>> +    ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
>> +                    LPASS_SSTREAM_ENABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    ret = regmap_field_write(drvdata->meta_ctl->mute,
>> +                    LPASS_MUTE_DISABLE);
>> +    if (ret)
>> +        return ret;
>> +
>> +    return ret;
>> +}
>> +
>> +static int lpass_hdmi_daiops_trigger(struct snd_pcm_substream 
>> *substream,
>> +        int cmd, struct snd_soc_dai *dai)
>> +{
>> +    struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>> +    int ret = -EINVAL;
>> +
>> +    switch (cmd) {
>> +    case SNDRV_PCM_TRIGGER_START:
>> +    case SNDRV_PCM_TRIGGER_RESUME:
>> +    case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
>> +
> unnecessary space!
Okay.
>> +        ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
>> +                    LPASS_SSTREAM_ENABLE);
>> +        if (ret)
>> +            return ret;
>> +
>> +        ret = regmap_field_write(drvdata->meta_ctl->mute,
>> +                    LPASS_MUTE_DISABLE);
>> +        if (ret)
>> +            return ret;
>> +
>> +        break;
>> +    case SNDRV_PCM_TRIGGER_STOP:
>> +    case SNDRV_PCM_TRIGGER_SUSPEND:
>> +    case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
>> +
>> +        ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
>> +                    LPASS_SSTREAM_DISABLE);
>> +        if (ret)
>> +            return ret;
>> +
>> +
>> +        ret = regmap_field_write(drvdata->meta_ctl->mute,
>> +                    LPASS_MUTE_ENABLE);
>> +        if (ret)
>> +            return ret;
>> +
>> +        ret = regmap_field_write(drvdata->sstream_ctl->dp_audio, 0);
>> +        if (ret)
>> +            return ret;
>> +
>> +        break;
>> +    }
>> +    return ret;
>> +}
>> +
>> +const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = {
>> +    .hw_params    = lpass_hdmi_daiops_hw_params,
>> +    .prepare    = lpass_hdmi_daiops_prepare,
>> +    .trigger    = lpass_hdmi_daiops_trigger,
>> +};
>> +EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops);
>> +
>> +
>> +
> too many empty lines??
Okay.
>
>
>> +static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned 
>> int reg)
>> +{
>> +    struct lpass_data *drvdata = dev_get_drvdata(dev);
>> +    struct lpass_variant *v = drvdata->variant;
>> +    int i;
>> +
>> +    if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
>> +        return true;
>> +    if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
>> +        return true;
>> +    if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
>> +        return true;
>> +
> switch case should make this much cleaner.
Okay.
>
>> +    for (i = 0; i < v->hdmi_rdma_channels; i++) {
>> +        if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
>> +            return true;
>> +        if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
>> +            return true;
>> +        if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
>> +            return true;
>> +    }
>> +
>> +    if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
>> +        return true;
>> +    if (reg == LPASS_HDMI_TX_DP_ADDR(v))
>> +        return true;
>> +    if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
>> +        return true;
>> +
>> +    if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
>> +        return true;
>> +    if (reg == LPASS_HDMITX_APP_IRQCLEAR_REG(v))
>> +        return true;
>> +
>> +    for (i = 0; i < v->rdma_channels; ++i) {
>> +        if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
>> +            return true;
>> +        if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
>> +            return true;
>> +        if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
>> +            return true;
>> +        if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
>> +            return true;
>> +
>> +    }
>> +    return false;
>> +}
>> +
>> +static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned 
>> int reg)
>> +{
>> +    struct lpass_data *drvdata = dev_get_drvdata(dev);
>> +    struct lpass_variant *v = drvdata->variant;
>> +    int i;
>> +
>> +    if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
>> +        return true;
>> +    if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
>> +        return true;
>> +    if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
>> +        return true;
>
> Same here, use switch case
Okay.
>> +
>> +    for (i = 0; i < v->hdmi_rdma_channels; i++) {
>> +        if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
>> +            return true;
>> +        if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
>> +            return true;
>> +        if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
>> +            return true;
>> +    }
>
>> +
>> +    if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
>> +        return true;
>> +    if (reg == LPASS_HDMI_TX_DP_ADDR(v))
>> +        return true;
>> +    if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
>> +        return true;
>> +
>> +    if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
>> +        return true;
>> +    if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
>> +        return true;
>> +
>> +    for (i = 0; i < v->rdma_channels; ++i) {
>> +        if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
>> +            return true;
>> +        if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
>> +            return true;
>> +        if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
>> +            return true;
>> +        if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
>> +            return true;
>> +        if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
>> +            return true;
>> +    }
>> +
>> +    return false;
>> +}
>> +
>> +static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned 
>> int reg)
>> +{
>> +    return true;
>
> Are all the register range really volatile?
will check this.
>
>> +
>> +}
>> +struct regmap_config lpass_hdmi_regmap_config = {
>> +    .reg_bits = 32,
>> +    .reg_stride = 4,
>> +    .val_bits = 32,
>> +    .writeable_reg = lpass_hdmi_regmap_writeable,
>> +    .readable_reg = lpass_hdmi_regmap_readable,
>> +    .volatile_reg = lpass_hdmi_regmap_volatile,
>> +    .cache_type = REGCACHE_FLAT,
>
> Any reason for using FLAT cache type ??
Will check this.
>
>> +};
>> +EXPORT_SYMBOL(lpass_hdmi_regmap_config);
>> +
>> +MODULE_DESCRIPTION("QTi LPASS HDMI Driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/sound/soc/qcom/lpass-hdmi.h b/sound/soc/qcom/lpass-hdmi.h
>> new file mode 100644
>> index 0000000..f91f322
>> --- /dev/null
>> +++ b/sound/soc/qcom/lpass-hdmi.h
>> @@ -0,0 +1,129 @@
>> +/* SPDX-License-Identifier: GPL-2.0-only */
>> +/*
>> + * Copyright (c) 2020 The Linux Foundation. All rights reserved.
>> + *
>> + * lpass_hdmi.h - Definitions for the QTi LPASS HDMI
>> + */
>> +
>> +#ifndef __LPASS_HDMI_H__
>> +#define __LPASS_HDMI_H__
>> +
>> +#include <linux/clk.h>
>> +#include <linux/compiler.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/regmap.h>
>> +
>> +#define LPASS_HDMITX_LEGACY_DISABLE        0x0
>> +#define LPASS_HDMITX_LEGACY_ENABLE        0x1
>> +#define LPASS_DP_AUDIO_BITWIDTH16        0x0
>> +#define LPASS_DP_AUDIO_BITWIDTH24        0xb
>> +#define LPASS_DATA_FORMAT_SHIFT            0x1
>> +#define LPASS_DATA_FORMAT_MASK            0x2
>> +#define LPASS_FREQ_BIT_SHIFT            24
>> +#define LPASS_FREQ_BIT_MASK            0xf000000
>
> use GENMASK macro for all such masks.
Okay.
>
>> +#define LPASS_DATA_FORMAT_LINEAR 0x0
>> +#define LPASS_DATA_FORMAT_NON_LINEAR        0x1
>> +#define LPASS_SAMPLING_FREQ32            0x3
>> +#define LPASS_SAMPLING_FREQ44            0x0
>> +#define LPASS_SAMPLING_FREQ48            0x2
>> +#define LPASS_TX_CTL_RESET            0x1
>> +#define LPASS_TX_CTL_CLEAR            0x0
>> +#define LPASS_SSTREAM_ENABLE            1
>> +#define LPASS_SSTREAM_DISABLE            0
>> +#define LPASS_LAYOUT_SP_DEFAULT            0xf
>> +#define LPASS_SSTREAM_DEFAULT_ENABLE        1
>> +#define LPASS_SSTREAM_DEFAULT_DISABLE        0
>> +#define LPASS_WORDLENGTH_MASK            0xf
>> +#define LPASS_MUTE_ENABLE            1
>> +#define LPASS_MUTE_DISABLE            0
>> +#define LPASS_META_DEFAULT_VAL            0
>> +#define HW_MODE                    1
>> +#define SW_MODE                    0
>> +#define LEGACY_LPASS_LPAIF            1
>> +#define LEGACY_LPASS_HDMI            0
>> +#define REPLACE_VBIT                0x1
>> +#define LINEAR_PCM_DATA                0x0
>> +#define NON_LINEAR_PCM_DATA            0x1
>> +#define HDMITX_PARITY_CALC_EN            0x1
>> +#define HDMITX_PARITY_CALC_DIS            0x0
>> +
>> +
>> +#define LPASS_HDMI_TX_CTL_ADDR(v) \
>> +        (v->hdmi_tx_ctl_addr)
>> +
>> +#define LPASS_HDMI_TX_LEGACY_ADDR(v) \
>> +        (v->hdmi_legacy_addr)
>> +#define LPASS_HDMI_TX_VBIT_CTL_ADDR(v) \
>> +        (v->hdmi_vbit_addr)
> above three macros should be able to go in single lines!! Not sure why 
> you are adding an extra break, which makes it very odd for reading.
Okay.
>
>> +#define LPASS_HDMI_TX_CH_LSB_ADDR(v, port) \
>> +        (v->hdmi_ch_lsb_addr + \
>> +        v->ch_stride * (port))
>> +#define LPASS_HDMI_TX_CH_MSB_ADDR(v, port) \
>> +        (v->hdmi_ch_msb_addr + \
>> +        v->ch_stride * (port))
>> +#define LPASS_HDMI_TX_DMA_ADDR(v, port) \
>> +        (v->hdmi_dmactl_addr + \
>> +        v->hdmi_dma_stride * (port))
>> +#define LPASS_HDMI_TX_PARITY_ADDR(v) \
>> +        (v->hdmi_parity_addr)
>> +#define LPASS_HDMI_TX_DP_ADDR(v) \
>> +        (v->hdmi_DP_addr)
>> +#define LPASS_HDMI_TX_SSTREAM_ADDR(v) \
>> +        (v->hdmi_sstream_addr)
>> +
>> +struct lpass_sstream_ctl {
>> +    struct regmap_field *sstream_en;
>> +    struct regmap_field *dma_sel;
>> +    struct regmap_field *auto_bbit_en;
>> +    struct regmap_field *layout;
>> +    struct regmap_field *layout_sp;
>> +    struct regmap_field *set_sp_on_en;
>> +    struct regmap_field *dp_audio;
>> +    struct regmap_field *dp_staffing_en;
>> +    struct regmap_field *dp_sp_b_hw_en;
>> +};
>> +
>> +struct lpass_dp_metadata_ctl {
>> +    struct regmap_field *mute;
>> +    struct regmap_field *as_sdp_cc;
>> +    struct regmap_field *as_sdp_ct;
>> +    struct regmap_field *aif_db4;
>> +    struct regmap_field *frequency;
>> +    struct regmap_field *mst_index;
>> +    struct regmap_field *dptx_index;
>> +};
>> +
>> +struct lpass_hdmi_tx_ctl {
>> +    struct regmap_field *soft_reset;
>> +    struct regmap_field *force_reset;
>> +};
>> +
>> +struct lpass_hdmitx_dmactl {
>> +    struct regmap_field *use_hw_chs;
>> +    struct regmap_field *use_hw_usr;
>> +    struct regmap_field *hw_chs_sel;
>> +    struct regmap_field *hw_usr_sel;
>> +};
>> +
>> +struct lpass_vbit_ctrl {
>> +        struct regmap_field *replace_vbit;
>> +        struct regmap_field *vbit_stream;
>> +};
>> +
>> +struct  lpass_hdmitx_legacy {
>> +    struct regmap_field *legacy_en;
>> +};
>> +
>> +struct  lpass_hdmi_tx_parity {
>> +    struct regmap_field *calc_en;
>> +};
>> +
>> +struct  lpass_hdmi_tx_ch_lsb {
>> +    struct regmap_field *lsb_bits;
>> +};
>> +
>> +struct  lpass_hdmi_tx_ch_msb {
>> +    struct regmap_field *msb_bits;
>> +};
>> +
>> +#endif /* __LPASS_HDMI_H__ */
>> diff --git a/sound/soc/qcom/lpass-ipq806x.c 
>> b/sound/soc/qcom/lpass-ipq806x.c
>> index 72f09b3..832a916 100644
>> --- a/sound/soc/qcom/lpass-ipq806x.c
>> +++ b/sound/soc/qcom/lpass-ipq806x.c
>> @@ -96,7 +96,7 @@ static int ipq806x_lpass_exit(struct 
>> platform_device *pdev)
>>       return 0;
>>   }
>>   -static int ipq806x_lpass_alloc_dma_channel(struct lpass_data 
>> *drvdata, int dir)
>> +static int ipq806x_lpass_alloc_dma_channel(struct lpass_data 
>> *drvdata, int dir, unsigned int dai_id)
>>   {
>>       if (dir == SNDRV_PCM_STREAM_PLAYBACK)
>>           return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
>> @@ -104,7 +104,7 @@ static int ipq806x_lpass_alloc_dma_channel(struct 
>> lpass_data *drvdata, int dir)
>>           return -EINVAL;
>>   }
>>   -static int ipq806x_lpass_free_dma_channel(struct lpass_data 
>> *drvdata, int chan)
>> +static int ipq806x_lpass_free_dma_channel(struct lpass_data 
>> *drvdata, int chan, unsigned int dai_id)
>>   {
>>       return 0;
>>   }
>> diff --git a/sound/soc/qcom/lpass-lpaif-reg.h 
>> b/sound/soc/qcom/lpass-lpaif-reg.h
>> index 5258e60..42aebd4 100644
>> --- a/sound/soc/qcom/lpass-lpaif-reg.h
>> +++ b/sound/soc/qcom/lpass-lpaif-reg.h
>> @@ -9,7 +9,8 @@
>>   /* LPAIF I2S */
>>     #define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
>> -    (v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
>> +    (v->i2sctrl_reg_base + (addr) + \
>> +    v->i2sctrl_reg_stride * (port))
>>     #define LPAIF_I2SCTL_REG(v, port) LPAIF_I2SCTL_REG_ADDR(v, 0x0, 
>> (port))
>>   @@ -70,6 +71,14 @@
>>   #define LPAIF_IRQSTAT_REG(v, port)    LPAIF_IRQ_REG_ADDR(v, 0x4, 
>> (port))
>>   #define LPAIF_IRQCLEAR_REG(v, port)    LPAIF_IRQ_REG_ADDR(v, 0xC, 
>> (port))
>>   +
>> +#define LPASS_HDMITX_APP_IRQ_REG_ADDR(v, addr)  \
>> +    ((v->hdmi_irq_reg_base) + (addr))
>> +
>> +#define LPASS_HDMITX_APP_IRQEN_REG(v) 
>> LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0x4)
>> +#define LPASS_HDMITX_APP_IRQSTAT_REG(v) 
>> LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0x8)
>> +#define LPASS_HDMITX_APP_IRQCLEAR_REG(v) 
>> LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0xC)
>> +
>>   #define LPAIF_IRQ_BITSTRIDE        3
>>     #define LPAIF_IRQ_PER(chan)        (1 << (LPAIF_IRQ_BITSTRIDE * 
>> (chan)))
>> @@ -77,8 +86,22 @@
>>   #define LPAIF_IRQ_ERR(chan)        (4 << (LPAIF_IRQ_BITSTRIDE * 
>> (chan)))
>>     #define LPAIF_IRQ_ALL(chan)        (7 << (LPAIF_IRQ_BITSTRIDE * 
>> (chan)))
>> +#define LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan)    (1 << (14 + chan))
>> +#define LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan)    (1 << (24 + chan))
>> +#define LPAIF_IRQ_HDMI_METADONE        BIT(23)
>>     /* LPAIF DMA */
>> +#define LPAIF_HDMI_RDMA_REG_ADDR(v, addr, chan) \
>> +    (v->hdmi_rdma_reg_base + (addr) + v->hdmi_rdma_reg_stride * (chan))
>> +
>> +#define LPAIF_HDMI_RDMACTL_AUDINTF(id)    (id << 
>> LPAIF_RDMACTL_AUDINTF_SHIFT)
>> +
>> +#define LPAIF_HDMI_RDMACTL_REG(v, chan) LPAIF_HDMI_RDMA_REG_ADDR(v, 
>> 0x00, (chan))
>> +#define LPAIF_HDMI_RDMABASE_REG(v, chan) LPAIF_HDMI_RDMA_REG_ADDR(v, 
>> 0x04, (chan))
>> +#define    LPAIF_HDMI_RDMABUFF_REG(v, chan) 
>> LPAIF_HDMI_RDMA_REG_ADDR(v, 0x08, (chan))
>> +#define LPAIF_HDMI_RDMACURR_REG(v, chan) LPAIF_HDMI_RDMA_REG_ADDR(v, 
>> 0x0C, (chan))
>> +#define    LPAIF_HDMI_RDMAPER_REG(v, chan) 
>> LPAIF_HDMI_RDMA_REG_ADDR(v, 0x10, (chan))
>> +#define    LPAIF_HDMI_RDMAPERCNT_REG(v, chan) 
>> LPAIF_HDMI_RDMA_REG_ADDR(v, 0x14, (chan))
>>     #define LPAIF_RDMA_REG_ADDR(v, addr, chan) \
>>       (v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan))
>> @@ -103,17 +126,22 @@
>>   #define    LPAIF_WRDMAPER_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 
>> 0x10, (chan))
>>   #define    LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 
>> 0x14, (chan))
>>   -#define __LPAIF_DMA_REG(v, chan, dir, reg)  \
>> -    (dir ==  SNDRV_PCM_STREAM_PLAYBACK) ? \
>> -        LPAIF_RDMA##reg##_REG(v, chan) : \
>> -        LPAIF_WRDMA##reg##_REG(v, chan)
>> -
>> -#define LPAIF_DMACTL_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, 
>> CTL)
>> -#define LPAIF_DMABASE_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, 
>> dir, BASE)
>> -#define    LPAIF_DMABUFF_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, 
>> dir, BUFF)
>> -#define LPAIF_DMACURR_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, 
>> dir, CURR)
>> -#define    LPAIF_DMAPER_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, 
>> dir, PER)
>> -#define    LPAIF_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, 
>> chan, dir, PERCNT)
>> +#define LPAIF_INTFDMA_REG(v, chan, reg, dai_id)  \
>> +        ((v->dai_driver[dai_id].id ==  LPASS_DP_RX) ? \
>> +        LPAIF_HDMI_RDMA##reg##_REG(v, chan) : \
>> +         LPAIF_RDMA##reg##_REG(v, chan))
>> +
>> +#define __LPAIF_DMA_REG(v, chan, dir, reg, dai_id)  \
>> +    ((dir ==  SNDRV_PCM_STREAM_PLAYBACK) ? \
>> +        (LPAIF_INTFDMA_REG(v, chan, reg, dai_id)) : \
>> +        LPAIF_WRDMA##reg##_REG(v, chan))
>> +
>> +#define LPAIF_DMACTL_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, 
>> chan, dir, CTL, dai_id)
>> +#define LPAIF_DMABASE_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, 
>> chan, dir, BASE, dai_id)
>> +#define    LPAIF_DMABUFF_REG(v, chan, dir, dai_id) 
>> __LPAIF_DMA_REG(v, chan, dir, BUFF, dai_id)
>> +#define LPAIF_DMACURR_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, 
>> chan, dir, CURR, dai_id)
>> +#define    LPAIF_DMAPER_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, 
>> chan, dir, PER, dai_id)
>> +#define    LPAIF_DMAPERCNT_REG(v, chan, dir, dai_id) 
>> __LPAIF_DMA_REG(v, chan, dir, PERCNT, dai_id)
>>     #define LPAIF_DMACTL_BURSTEN_SINGLE    0
>>   #define LPAIF_DMACTL_BURSTEN_INCR4    1
>> diff --git a/sound/soc/qcom/lpass-platform.c 
>> b/sound/soc/qcom/lpass-platform.c
>> index 35aead1..e2d1f25 100644
>> --- a/sound/soc/qcom/lpass-platform.c
>> +++ b/sound/soc/qcom/lpass-platform.c
>> @@ -23,7 +23,7 @@ struct lpass_pcm_data {
>>       int i2s_port;
>>   };
>>   -#define LPASS_PLATFORM_BUFFER_SIZE    (16 * 1024)
>> +#define LPASS_PLATFORM_BUFFER_SIZE    (24 *  2 * 1024)
>>   #define LPASS_PLATFORM_PERIODS        2
>>     static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>> @@ -62,41 +62,79 @@ static int 
>> lpass_platform_alloc_dmactl_fields(struct device *dev,
>>       if (drvdata->rd_dmactl == NULL)
>>           return -ENOMEM;
>>   -    drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct 
>> lpaif_dmactl),
>> -                      GFP_KERNEL);
>> -    if (drvdata->wr_dmactl == NULL)
>> -        return -ENOMEM;
>> -
>>       rd_dmactl = drvdata->rd_dmactl;
>> -    wr_dmactl = drvdata->wr_dmactl;
>>         rd_dmactl->bursten = devm_regmap_field_alloc(dev, map, 
>> v->rdma_bursten);
>>       rd_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, 
>> v->rdma_wpscnt);
>>       rd_dmactl->fifowm = devm_regmap_field_alloc(dev, map, 
>> v->rdma_fifowm);
>> -    rd_dmactl->intf = devm_regmap_field_alloc(dev, map, v->rdma_intf);
>>       rd_dmactl->enable = devm_regmap_field_alloc(dev, map, 
>> v->rdma_enable);
>>       rd_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, 
>> v->rdma_dyncclk);
>> -
>> +    rd_dmactl->intf = devm_regmap_field_alloc(dev, map, v->rdma_intf);
>>       if (IS_ERR(rd_dmactl->bursten) || IS_ERR(rd_dmactl->wpscnt) ||
>> -        IS_ERR(rd_dmactl->fifowm) || IS_ERR(rd_dmactl->intf) ||
>> -        IS_ERR(rd_dmactl->enable) || IS_ERR(rd_dmactl->dyncclk))
>> +        IS_ERR(rd_dmactl->fifowm) || IS_ERR(rd_dmactl->dyncclk) ||
>> +        IS_ERR(rd_dmactl->enable) || IS_ERR(rd_dmactl->intf))
>>           return -EINVAL;
>> +    drvdata->wr_dmactl = devm_kzalloc(dev,
>> +            sizeof(struct lpaif_dmactl), GFP_KERNEL);
>> +    if (drvdata->wr_dmactl == NULL)
>> +        return -ENOMEM;
>>   -    wr_dmactl->bursten = devm_regmap_field_alloc(dev, map, 
>> v->wrdma_bursten);
>> -    wr_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, 
>> v->wrdma_wpscnt);
>> -    wr_dmactl->fifowm = devm_regmap_field_alloc(dev, map, 
>> v->wrdma_fifowm);
>> -    wr_dmactl->intf = devm_regmap_field_alloc(dev, map, v->wrdma_intf);
>> -    wr_dmactl->enable = devm_regmap_field_alloc(dev, map, 
>> v->wrdma_enable);
>> -    wr_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, 
>> v->wrdma_dyncclk);
>> +    wr_dmactl = drvdata->wr_dmactl;
>> +
>> +    wr_dmactl->bursten = devm_regmap_field_alloc(dev, map,
>> +                        v->wrdma_bursten);
>> +    wr_dmactl->wpscnt = devm_regmap_field_alloc(dev, map,
>> +                        v->wrdma_wpscnt);
>> +    wr_dmactl->fifowm = devm_regmap_field_alloc(dev, map,
>> +                        v->wrdma_fifowm);
>> +    wr_dmactl->intf = devm_regmap_field_alloc(dev, map,
>> +                        v->wrdma_intf);
>> +    wr_dmactl->enable = devm_regmap_field_alloc(dev, map,
>> +                        v->wrdma_enable);
>> +    wr_dmactl->dyncclk = devm_regmap_field_alloc(dev, map,
>> +                        v->wrdma_dyncclk);
>
> Can you explain what is happening here, these chagnes just look like 
> spllitting one line into two!
Will bring them in same line. As previous code has long lines and not 
taken care after modification.
>
>
> I should stop reviewing at this point!
> As I have seen some general issues with the patch like
> - doing un-needed changes!
> - removing #ifdef checks.
> - try to come up with some api/macro to simplify field allocs as they 
> seems to be all over the place!
>
> thanks,
> srini
diff mbox series

Patch

diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig
index a607ace..509584c 100644
--- a/sound/soc/qcom/Kconfig
+++ b/sound/soc/qcom/Kconfig
@@ -12,6 +12,10 @@  config SND_SOC_LPASS_CPU
 	tristate
 	select REGMAP_MMIO
 
+config SND_SOC_LPASS_HDMI
+	tristate
+	select REGMAP_MMIO
+
 config SND_SOC_LPASS_PLATFORM
 	tristate
 	select REGMAP_MMIO
@@ -30,6 +34,7 @@  config SND_SOC_LPASS_SC7180
 	tristate
 	select SND_SOC_LPASS_CPU
 	select SND_SOC_LPASS_PLATFORM
+	select SND_SOC_LPASS_HDMI
 
 config SND_SOC_STORM
 	tristate "ASoC I2S support for Storm boards"
diff --git a/sound/soc/qcom/Makefile b/sound/soc/qcom/Makefile
index 7972c94..0bd90d7 100644
--- a/sound/soc/qcom/Makefile
+++ b/sound/soc/qcom/Makefile
@@ -1,12 +1,14 @@ 
 # SPDX-License-Identifier: GPL-2.0
 # Platform
 snd-soc-lpass-cpu-objs := lpass-cpu.o
+snd-soc-lpass-hdmi-objs := lpass-hdmi.o
 snd-soc-lpass-platform-objs := lpass-platform.o
 snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
 snd-soc-lpass-apq8016-objs := lpass-apq8016.o
 snd-soc-lpass-sc7180-objs := lpass-sc7180.o
 
 obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
+obj-$(CONFIG_SND_SOC_LPASS_HDMI) += snd-soc-lpass-hdmi.o
 obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
 obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
 obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
index 5c8ae22..0aedb3a 100644
--- a/sound/soc/qcom/lpass-apq8016.c
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -125,7 +125,7 @@  static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
 };
 
 static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
-					   int direction)
+					   int direction, unsigned int dai_id)
 {
 	struct lpass_variant *v = drvdata->variant;
 	int chan = 0;
@@ -151,7 +151,7 @@  static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
 	return chan;
 }
 
-static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
 {
 	clear_bit(chan, &drvdata->dma_ch_bit_map);
 
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index 5d84f63..41a2470 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -589,13 +589,33 @@  int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 						variant->wrdma_channel_start);
 
 	drvdata->lpaif_map = devm_regmap_init_mmio(dev, drvdata->lpaif,
-			&lpass_cpu_regmap_config);
+								&lpass_cpu_regmap_config);
 	if (IS_ERR(drvdata->lpaif_map)) {
 		dev_err(dev, "error initializing regmap: %ld\n",
 			PTR_ERR(drvdata->lpaif_map));
 		return PTR_ERR(drvdata->lpaif_map);
 	}
+#ifdef CONFIG_SND_SOC_LPASS_SC7180
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-hdmiif");
 
+	drvdata->hdmiif = devm_ioremap_resource(dev, res);
+	if (IS_ERR((void const __force *)drvdata->hdmiif)) {
+		dev_err(dev, "error mapping reg resource: %ld\n",
+				PTR_ERR((void const __force *)drvdata->hdmiif));
+		return PTR_ERR((void const __force *)drvdata->hdmiif);
+	}
+
+	lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
+				variant->hdmi_rdma_channels);
+	drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
+				&lpass_hdmi_regmap_config);
+	if (IS_ERR(drvdata->hdmiif_map)) {
+		dev_err(dev, "error initializing regmap: %ld\n",
+		PTR_ERR(drvdata->hdmiif_map));
+		return PTR_ERR(drvdata->hdmiif_map);
+	}
+
+#endif
 	if (variant->init) {
 		ret = variant->init(pdev);
 		if (ret) {
@@ -606,6 +626,9 @@  int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 
 	for (i = 0; i < variant->num_dai; i++) {
 		dai_id = variant->dai_driver[i].id;
+		if (dai_id == LPASS_DP_RX)
+			continue;
+
 		drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(dev,
 					     variant->dai_osr_clk_names[i]);
 		if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
@@ -625,10 +648,10 @@  int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 				"error getting %s: %ld\n",
 				variant->dai_bit_clk_names[i],
 				PTR_ERR(drvdata->mi2s_bit_clk[dai_id]));
+
 			return PTR_ERR(drvdata->mi2s_bit_clk[dai_id]);
 		}
 	}
-
 	/* Allocation for i2sctl regmap fields */
 	drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
 					GFP_KERNEL);
@@ -636,10 +659,18 @@  int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 	/* Initialize bitfields for dai I2SCTL register */
 	ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
 						drvdata->lpaif_map);
-	if (ret) {
+	if (ret)
 		dev_err(dev, "error init i2sctl field: %d\n", ret);
+
+#ifdef CONFIG_SND_SOC_LPASS_SC7180
+	ret = lpass_hdmi_init_bitfields(dev, drvdata->hdmiif_map);
+	if (ret) {
+		dev_err(dev, "%s error  hdmi init failed\n", __func__);
 		return ret;
 	}
+#else
+	return -EINVAL;
+#endif
 
 	ret = devm_snd_soc_register_component(dev,
 					      &lpass_cpu_comp_driver,
diff --git a/sound/soc/qcom/lpass-hdmi.c b/sound/soc/qcom/lpass-hdmi.c
new file mode 100644
index 0000000..7cb2ba3
--- /dev/null
+++ b/sound/soc/qcom/lpass-hdmi.c
@@ -0,0 +1,596 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ *
+ * lpass-hdmi.c -- ALSA SoC HDMI-CPU DAI driver for QTi LPASS HDMI
+ */
+
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/soc-dai.h>
+#include <dt-bindings/sound/sc7180-lpass.h>
+#include "lpass-lpaif-reg.h"
+#include "lpass.h"
+#include "lpass-hdmi.h"
+
+int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int i;
+	struct lpass_hdmi_tx_ctl *tx_ctl;
+	struct lpass_hdmitx_legacy *legacy;
+	struct lpass_vbit_ctrl *vbit_ctl;
+	struct lpass_hdmi_tx_parity *tx_parity;
+	struct lpass_dp_metadata_ctl *meta_ctl;
+	struct lpass_sstream_ctl *sstream_ctl;
+	struct lpass_hdmi_tx_ch_msb *ch_msb;
+	struct lpass_hdmi_tx_ch_lsb *ch_lsb;
+	struct lpass_hdmitx_dmactl *hdmi_tx_dmactl;
+
+	drvdata->tx_ctl = devm_kzalloc(dev, sizeof(struct lpass_hdmi_tx_ctl),
+					GFP_KERNEL);
+	if (drvdata->tx_ctl == NULL)
+		return -ENOMEM;
+
+	tx_ctl = drvdata->tx_ctl;
+	tx_ctl->soft_reset = devm_regmap_field_alloc(dev, map,
+				v->soft_reset);
+	tx_ctl->force_reset = devm_regmap_field_alloc(dev, map,
+				v->force_reset);
+	if (IS_ERR(tx_ctl->soft_reset) || IS_ERR(tx_ctl->force_reset))
+		return -EINVAL;
+
+	drvdata->legacy = devm_kzalloc(dev, sizeof(struct lpass_hdmitx_legacy),
+					GFP_KERNEL);
+	if (drvdata->legacy == NULL)
+		return -ENOMEM;
+
+	legacy = drvdata->legacy;
+	legacy->legacy_en = devm_regmap_field_alloc(dev, map,
+				v->legacy_en);
+	if (IS_ERR(legacy->legacy_en))
+		return -EINVAL;
+
+	drvdata->vbit_ctl = devm_kzalloc(dev, sizeof(struct lpass_vbit_ctrl),
+					GFP_KERNEL);
+	if (drvdata->vbit_ctl == NULL)
+		return -ENOMEM;
+
+	vbit_ctl = drvdata->vbit_ctl;
+	vbit_ctl->replace_vbit = devm_regmap_field_alloc(dev, map,
+					v->replace_vbit);
+	vbit_ctl->vbit_stream = devm_regmap_field_alloc(dev, map,
+					v->vbit_stream);
+	if (IS_ERR(vbit_ctl->replace_vbit) || IS_ERR(vbit_ctl->vbit_stream))
+		return -EINVAL;
+
+	drvdata->tx_parity = devm_kzalloc(dev,
+		sizeof(struct  lpass_hdmi_tx_parity), GFP_KERNEL);
+
+	if (drvdata->tx_parity == NULL)
+		return -ENOMEM;
+
+	tx_parity = drvdata->tx_parity;
+	tx_parity->calc_en = devm_regmap_field_alloc(dev, map, v->calc_en);
+
+	if (IS_ERR(tx_parity->calc_en))
+		return -EINVAL;
+
+	drvdata->meta_ctl = devm_kzalloc(dev,
+		sizeof(struct lpass_dp_metadata_ctl), GFP_KERNEL);
+
+	if (drvdata->meta_ctl == NULL)
+		return -ENOMEM;
+
+	meta_ctl = drvdata->meta_ctl;
+	meta_ctl->mute = devm_regmap_field_alloc(dev, map, v->mute);
+	meta_ctl->as_sdp_cc = devm_regmap_field_alloc(dev, map,
+						v->as_sdp_cc);
+	meta_ctl->as_sdp_ct = devm_regmap_field_alloc(dev, map,
+						v->as_sdp_ct);
+	meta_ctl->aif_db4 = devm_regmap_field_alloc(dev, map,
+						v->aif_db4);
+	meta_ctl->frequency = devm_regmap_field_alloc(dev, map,
+						v->frequency);
+	meta_ctl->mst_index = devm_regmap_field_alloc(dev, map,
+						v->mst_index);
+	meta_ctl->dptx_index = devm_regmap_field_alloc(dev, map,
+						v->dptx_index);
+
+	if (IS_ERR(meta_ctl->mute) || IS_ERR(meta_ctl->as_sdp_cc) ||
+		IS_ERR(meta_ctl->as_sdp_ct) || IS_ERR(meta_ctl->aif_db4) ||
+		IS_ERR(meta_ctl->frequency) || IS_ERR(meta_ctl->mst_index) ||
+		IS_ERR(meta_ctl->dptx_index))
+		return -EINVAL;
+
+	drvdata->sstream_ctl = devm_kzalloc(dev,
+		sizeof(struct lpass_sstream_ctl), GFP_KERNEL);
+	if (drvdata->sstream_ctl == NULL)
+		return -ENOMEM;
+
+	sstream_ctl = drvdata->sstream_ctl;
+	sstream_ctl->sstream_en = devm_regmap_field_alloc(dev, map,
+						v->sstream_en);
+	sstream_ctl->dma_sel = devm_regmap_field_alloc(dev, map,
+						v->dma_sel);
+	sstream_ctl->auto_bbit_en = devm_regmap_field_alloc(dev, map,
+						v->auto_bbit_en);
+	sstream_ctl->layout = devm_regmap_field_alloc(dev, map,
+						v->layout);
+	sstream_ctl->layout_sp = devm_regmap_field_alloc(dev, map,
+						v->layout_sp);
+	sstream_ctl->dp_audio = devm_regmap_field_alloc(dev, map,
+						v->dp_audio);
+	sstream_ctl->set_sp_on_en = devm_regmap_field_alloc(dev, map,
+						v->set_sp_on_en);
+	sstream_ctl->dp_staffing_en = devm_regmap_field_alloc(dev, map,
+						v->dp_staffing_en);
+	sstream_ctl->dp_sp_b_hw_en = devm_regmap_field_alloc(dev, map,
+						v->dp_sp_b_hw_en);
+
+	if (IS_ERR(sstream_ctl->sstream_en) || IS_ERR(sstream_ctl->dma_sel) ||
+		IS_ERR(sstream_ctl->auto_bbit_en) ||
+		IS_ERR(sstream_ctl->layout) || IS_ERR(sstream_ctl->layout_sp) ||
+		IS_ERR(sstream_ctl->dp_audio) ||
+		IS_ERR(sstream_ctl->set_sp_on_en) ||
+		IS_ERR(sstream_ctl->dp_staffing_en) ||
+		IS_ERR(sstream_ctl->dp_sp_b_hw_en))
+		return -EINVAL;
+
+	for (i = 0; i < LPASS_MAX_HDMI_DMA_CHANNELS; i++) {
+		drvdata->ch_msb[i] = devm_kzalloc(dev,
+			sizeof(struct lpass_hdmi_tx_ch_msb), GFP_KERNEL);
+		if (drvdata->ch_msb[i] == NULL)
+			return -ENOMEM;
+
+		ch_msb = drvdata->ch_msb[i];
+
+		ch_msb->msb_bits = devm_regmap_field_alloc(dev, map,
+							v->msb_bits);
+		if (IS_ERR(ch_msb->msb_bits))
+			return -EINVAL;
+
+		drvdata->ch_lsb[i] = devm_kzalloc(dev,
+			sizeof(struct lpass_hdmi_tx_ch_lsb), GFP_KERNEL);
+		if (drvdata->ch_lsb[i] == NULL)
+			return -ENOMEM;
+
+		ch_lsb = drvdata->ch_lsb[i];
+		ch_lsb->lsb_bits = devm_regmap_field_alloc(dev, map,
+					v->lsb_bits);
+		if (IS_ERR(ch_lsb->lsb_bits))
+			return -EINVAL;
+
+
+		drvdata->hdmi_tx_dmactl[i] = devm_kzalloc(dev,
+			sizeof(struct lpass_hdmitx_dmactl), GFP_KERNEL);
+		if (drvdata->hdmi_tx_dmactl[i] == NULL)
+			return -ENOMEM;
+
+		hdmi_tx_dmactl = drvdata->hdmi_tx_dmactl[i];
+		hdmi_tx_dmactl->use_hw_chs = devm_regmap_field_alloc(dev, map,
+						v->use_hw_chs);
+		hdmi_tx_dmactl->use_hw_usr = devm_regmap_field_alloc(dev, map,
+						v->use_hw_usr);
+		hdmi_tx_dmactl->hw_chs_sel = devm_regmap_field_alloc(dev, map,
+						v->hw_chs_sel);
+		hdmi_tx_dmactl->hw_usr_sel = devm_regmap_field_alloc(dev, map,
+						v->hw_usr_sel);
+		if (IS_ERR(hdmi_tx_dmactl->use_hw_chs) ||
+			IS_ERR(hdmi_tx_dmactl->use_hw_usr) ||
+			IS_ERR(hdmi_tx_dmactl->hw_chs_sel) ||
+			IS_ERR(hdmi_tx_dmactl->hw_usr_sel))
+			return -EINVAL;
+	}
+	return 0;
+
+}
+EXPORT_SYMBOL(lpass_hdmi_init_bitfields);
+
+static int lpass_hdmi_daiops_hw_params(struct snd_pcm_substream *substream,
+		struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
+	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+	snd_pcm_format_t format = params_format(params);
+	unsigned int rate = params_rate(params);
+	unsigned int channels = params_channels(params);
+	unsigned int ret;
+	unsigned int bitwidth;
+	unsigned int word_length;
+	unsigned int ch_sts_buf0;
+	unsigned int ch_sts_buf1;
+	unsigned int data_format;
+	unsigned int sampling_freq;
+	unsigned int ch = 0;
+
+	bitwidth = snd_pcm_format_width(format);
+	if (bitwidth < 0) {
+		dev_err(dai->dev, "%s invalid bit width given : %d\n",
+					__func__, bitwidth);
+		return bitwidth;
+	}
+
+	switch (bitwidth) {
+	case 16:
+		word_length = LPASS_DP_AUDIO_BITWIDTH16;
+		break;
+	case 24:
+		word_length = LPASS_DP_AUDIO_BITWIDTH24;
+		break;
+	default:
+		dev_err(dai->dev, "%s invalid bit width given : %d\n",
+					__func__, bitwidth);
+		return -EINVAL;
+	}
+
+	switch (rate) {
+	case 32000:
+		sampling_freq = LPASS_SAMPLING_FREQ32;
+		break;
+	case 44100:
+		sampling_freq = LPASS_SAMPLING_FREQ44;
+		break;
+	case 48000:
+		sampling_freq = LPASS_SAMPLING_FREQ48;
+		break;
+
+	default:
+		dev_err(dai->dev, "%s invalid bit width given : %d\n",
+					__func__, bitwidth);
+		return -EINVAL;
+	}
+	data_format = LPASS_DATA_FORMAT_LINEAR;
+	ch_sts_buf0 = (((data_format << LPASS_DATA_FORMAT_SHIFT) & LPASS_DATA_FORMAT_MASK)
+				| ((sampling_freq << LPASS_FREQ_BIT_SHIFT) & LPASS_FREQ_BIT_MASK));
+	ch_sts_buf1 = (word_length) & LPASS_WORDLENGTH_MASK;
+
+	ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_RESET);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->tx_ctl->soft_reset, LPASS_TX_CTL_CLEAR);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->legacy->legacy_en,
+				LPASS_HDMITX_LEGACY_DISABLE);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->tx_parity->calc_en,
+				HDMITX_PARITY_CALC_EN);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->vbit_ctl->replace_vbit,
+					REPLACE_VBIT);
+	if (ret)
+
+		return ret;
+
+	ret = regmap_field_write(drvdata->vbit_ctl->vbit_stream,
+					LINEAR_PCM_DATA);
+	if (ret)
+
+		return ret;
+
+	ret = regmap_field_write(drvdata->ch_msb[0]->msb_bits, ch_sts_buf1);
+	if (ret)
+
+		return ret;
+
+	ret = regmap_field_write(drvdata->ch_lsb[0]->lsb_bits, ch_sts_buf0);
+	if (ret)
+
+		return ret;
+
+	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_chs,
+				HW_MODE);
+	if (ret)
+
+		return ret;
+
+	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_chs_sel,
+				SW_MODE);
+	if (ret)
+
+		return ret;
+
+	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->use_hw_usr,
+				HW_MODE);
+	if (ret)
+
+		return ret;
+
+	ret = regmap_field_write(drvdata->hdmi_tx_dmactl[0]->hw_usr_sel,
+				SW_MODE);
+	if (ret)
+
+		return ret;
+
+	ret = regmap_field_write(drvdata->meta_ctl->mute,
+				LPASS_MUTE_ENABLE);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->meta_ctl->as_sdp_cc,
+				channels - 1);
+	if (ret)
+		return ret;
+
+
+	ret = regmap_field_write(drvdata->meta_ctl->as_sdp_ct,
+				LPASS_META_DEFAULT_VAL);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->meta_ctl->aif_db4,
+				LPASS_META_DEFAULT_VAL);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->meta_ctl->frequency, sampling_freq);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->meta_ctl->mst_index,
+				LPASS_META_DEFAULT_VAL);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->meta_ctl->dptx_index,
+				LPASS_META_DEFAULT_VAL);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
+				LPASS_SSTREAM_DISABLE);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->sstream_ctl->dma_sel, ch);
+	if (ret)
+		return ret;
+
+
+	ret = regmap_field_write(drvdata->sstream_ctl->auto_bbit_en,
+				LPASS_SSTREAM_DEFAULT_ENABLE);
+	if (ret)
+		return ret;
+
+
+	ret = regmap_field_write(drvdata->sstream_ctl->layout,
+				LPASS_SSTREAM_DEFAULT_DISABLE);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->sstream_ctl->layout_sp,
+				LPASS_LAYOUT_SP_DEFAULT);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->sstream_ctl->dp_audio,
+				LPASS_SSTREAM_DEFAULT_ENABLE);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->sstream_ctl->set_sp_on_en,
+				LPASS_SSTREAM_DEFAULT_ENABLE);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->sstream_ctl->dp_sp_b_hw_en,
+				LPASS_SSTREAM_DEFAULT_ENABLE);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->sstream_ctl->dp_staffing_en,
+				LPASS_SSTREAM_DEFAULT_ENABLE);
+	if (ret)
+
+		return ret;
+
+	return ret;
+}
+
+
+
+static int lpass_hdmi_daiops_prepare(struct snd_pcm_substream *substream,
+		struct snd_soc_dai *dai)
+{
+	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+	int ret;
+
+	ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
+					LPASS_SSTREAM_ENABLE);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(drvdata->meta_ctl->mute,
+					LPASS_MUTE_DISABLE);
+	if (ret)
+		return ret;
+
+	return ret;
+}
+
+static int lpass_hdmi_daiops_trigger(struct snd_pcm_substream *substream,
+		int cmd, struct snd_soc_dai *dai)
+{
+	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+	int ret = -EINVAL;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+
+		ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
+					LPASS_SSTREAM_ENABLE);
+		if (ret)
+			return ret;
+
+		ret = regmap_field_write(drvdata->meta_ctl->mute,
+					LPASS_MUTE_DISABLE);
+		if (ret)
+			return ret;
+
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+
+		ret = regmap_field_write(drvdata->sstream_ctl->sstream_en,
+					LPASS_SSTREAM_DISABLE);
+		if (ret)
+			return ret;
+
+
+		ret = regmap_field_write(drvdata->meta_ctl->mute,
+					LPASS_MUTE_ENABLE);
+		if (ret)
+			return ret;
+
+		ret = regmap_field_write(drvdata->sstream_ctl->dp_audio, 0);
+		if (ret)
+			return ret;
+
+		break;
+	}
+	return ret;
+}
+
+const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops = {
+	.hw_params	= lpass_hdmi_daiops_hw_params,
+	.prepare	= lpass_hdmi_daiops_prepare,
+	.trigger	= lpass_hdmi_daiops_trigger,
+};
+EXPORT_SYMBOL_GPL(asoc_qcom_lpass_hdmi_dai_ops);
+
+
+
+static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
+		return true;
+	if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
+		return true;
+	if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
+		return true;
+
+	for (i = 0; i < v->hdmi_rdma_channels; i++) {
+		if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
+			return true;
+		if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
+			return true;
+		if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
+			return true;
+	}
+
+	if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
+		return true;
+	if (reg == LPASS_HDMI_TX_DP_ADDR(v))
+		return true;
+	if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
+		return true;
+
+	if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
+		return true;
+	if (reg == LPASS_HDMITX_APP_IRQCLEAR_REG(v))
+		return true;
+
+	for (i = 0; i < v->rdma_channels; ++i) {
+		if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
+			return true;
+		if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
+			return true;
+		if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
+			return true;
+		if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
+			return true;
+
+	}
+	return false;
+}
+
+static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	int i;
+
+	if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
+		return true;
+	if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
+		return true;
+	if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
+		return true;
+
+	for (i = 0; i < v->hdmi_rdma_channels; i++) {
+		if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
+			return true;
+		if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
+			return true;
+		if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
+			return true;
+	}
+
+	if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
+		return true;
+	if (reg == LPASS_HDMI_TX_DP_ADDR(v))
+		return true;
+	if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
+		return true;
+
+	if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
+		return true;
+	if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
+		return true;
+
+	for (i = 0; i < v->rdma_channels; ++i) {
+		if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
+			return true;
+		if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
+			return true;
+		if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
+			return true;
+		if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
+			return true;
+		if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
+			return true;
+	}
+
+	return false;
+}
+
+static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
+{
+	return true;
+
+}
+struct regmap_config lpass_hdmi_regmap_config = {
+	.reg_bits = 32,
+	.reg_stride = 4,
+	.val_bits = 32,
+	.writeable_reg = lpass_hdmi_regmap_writeable,
+	.readable_reg = lpass_hdmi_regmap_readable,
+	.volatile_reg = lpass_hdmi_regmap_volatile,
+	.cache_type = REGCACHE_FLAT,
+};
+EXPORT_SYMBOL(lpass_hdmi_regmap_config);
+
+MODULE_DESCRIPTION("QTi LPASS HDMI Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/qcom/lpass-hdmi.h b/sound/soc/qcom/lpass-hdmi.h
new file mode 100644
index 0000000..f91f322
--- /dev/null
+++ b/sound/soc/qcom/lpass-hdmi.h
@@ -0,0 +1,129 @@ 
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2020 The Linux Foundation. All rights reserved.
+ *
+ * lpass_hdmi.h - Definitions for the QTi LPASS HDMI
+ */
+
+#ifndef __LPASS_HDMI_H__
+#define __LPASS_HDMI_H__
+
+#include <linux/clk.h>
+#include <linux/compiler.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define LPASS_HDMITX_LEGACY_DISABLE		0x0
+#define LPASS_HDMITX_LEGACY_ENABLE		0x1
+#define LPASS_DP_AUDIO_BITWIDTH16		0x0
+#define LPASS_DP_AUDIO_BITWIDTH24		0xb
+#define LPASS_DATA_FORMAT_SHIFT			0x1
+#define LPASS_DATA_FORMAT_MASK			0x2
+#define LPASS_FREQ_BIT_SHIFT			24
+#define LPASS_FREQ_BIT_MASK			0xf000000
+#define LPASS_DATA_FORMAT_LINEAR		0x0
+#define LPASS_DATA_FORMAT_NON_LINEAR		0x1
+#define LPASS_SAMPLING_FREQ32			0x3
+#define LPASS_SAMPLING_FREQ44			0x0
+#define LPASS_SAMPLING_FREQ48			0x2
+#define LPASS_TX_CTL_RESET			0x1
+#define LPASS_TX_CTL_CLEAR			0x0
+#define LPASS_SSTREAM_ENABLE			1
+#define LPASS_SSTREAM_DISABLE			0
+#define LPASS_LAYOUT_SP_DEFAULT			0xf
+#define LPASS_SSTREAM_DEFAULT_ENABLE		1
+#define LPASS_SSTREAM_DEFAULT_DISABLE		0
+#define LPASS_WORDLENGTH_MASK			0xf
+#define LPASS_MUTE_ENABLE			1
+#define LPASS_MUTE_DISABLE			0
+#define LPASS_META_DEFAULT_VAL			0
+#define HW_MODE					1
+#define SW_MODE					0
+#define LEGACY_LPASS_LPAIF			1
+#define LEGACY_LPASS_HDMI			0
+#define REPLACE_VBIT				0x1
+#define LINEAR_PCM_DATA				0x0
+#define NON_LINEAR_PCM_DATA			0x1
+#define HDMITX_PARITY_CALC_EN			0x1
+#define HDMITX_PARITY_CALC_DIS			0x0
+
+
+#define LPASS_HDMI_TX_CTL_ADDR(v) \
+		(v->hdmi_tx_ctl_addr)
+
+#define LPASS_HDMI_TX_LEGACY_ADDR(v) \
+		(v->hdmi_legacy_addr)
+#define LPASS_HDMI_TX_VBIT_CTL_ADDR(v) \
+		(v->hdmi_vbit_addr)
+#define LPASS_HDMI_TX_CH_LSB_ADDR(v, port) \
+		(v->hdmi_ch_lsb_addr + \
+		v->ch_stride * (port))
+#define LPASS_HDMI_TX_CH_MSB_ADDR(v, port) \
+		(v->hdmi_ch_msb_addr + \
+		v->ch_stride * (port))
+#define LPASS_HDMI_TX_DMA_ADDR(v, port) \
+		(v->hdmi_dmactl_addr + \
+		v->hdmi_dma_stride * (port))
+#define LPASS_HDMI_TX_PARITY_ADDR(v) \
+		(v->hdmi_parity_addr)
+#define LPASS_HDMI_TX_DP_ADDR(v) \
+		(v->hdmi_DP_addr)
+#define LPASS_HDMI_TX_SSTREAM_ADDR(v) \
+		(v->hdmi_sstream_addr)
+
+struct lpass_sstream_ctl {
+	struct regmap_field *sstream_en;
+	struct regmap_field *dma_sel;
+	struct regmap_field *auto_bbit_en;
+	struct regmap_field *layout;
+	struct regmap_field *layout_sp;
+	struct regmap_field *set_sp_on_en;
+	struct regmap_field *dp_audio;
+	struct regmap_field *dp_staffing_en;
+	struct regmap_field *dp_sp_b_hw_en;
+};
+
+struct lpass_dp_metadata_ctl {
+	struct regmap_field *mute;
+	struct regmap_field *as_sdp_cc;
+	struct regmap_field *as_sdp_ct;
+	struct regmap_field *aif_db4;
+	struct regmap_field *frequency;
+	struct regmap_field *mst_index;
+	struct regmap_field *dptx_index;
+};
+
+struct lpass_hdmi_tx_ctl {
+	struct regmap_field *soft_reset;
+	struct regmap_field *force_reset;
+};
+
+struct lpass_hdmitx_dmactl {
+	struct regmap_field *use_hw_chs;
+	struct regmap_field *use_hw_usr;
+	struct regmap_field *hw_chs_sel;
+	struct regmap_field *hw_usr_sel;
+};
+
+struct lpass_vbit_ctrl {
+		struct regmap_field *replace_vbit;
+		struct regmap_field *vbit_stream;
+};
+
+struct  lpass_hdmitx_legacy {
+	struct regmap_field *legacy_en;
+};
+
+struct  lpass_hdmi_tx_parity {
+	struct regmap_field *calc_en;
+};
+
+struct  lpass_hdmi_tx_ch_lsb {
+	struct regmap_field *lsb_bits;
+};
+
+struct  lpass_hdmi_tx_ch_msb {
+	struct regmap_field *msb_bits;
+};
+
+#endif /* __LPASS_HDMI_H__ */
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index 72f09b3..832a916 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -96,7 +96,7 @@  static int ipq806x_lpass_exit(struct platform_device *pdev)
 	return 0;
 }
 
-static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir)
+static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir, unsigned int dai_id)
 {
 	if (dir == SNDRV_PCM_STREAM_PLAYBACK)
 		return IPQ806X_LPAIF_RDMA_CHAN_MI2S;
@@ -104,7 +104,7 @@  static int ipq806x_lpass_alloc_dma_channel(struct lpass_data *drvdata, int dir)
 		return -EINVAL;
 }
 
-static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
+static int ipq806x_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
 {
 	return 0;
 }
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
index 5258e60..42aebd4 100644
--- a/sound/soc/qcom/lpass-lpaif-reg.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -9,7 +9,8 @@ 
 /* LPAIF I2S */
 
 #define LPAIF_I2SCTL_REG_ADDR(v, addr, port) \
-	(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
+	(v->i2sctrl_reg_base + (addr) + \
+	v->i2sctrl_reg_stride * (port))
 
 #define LPAIF_I2SCTL_REG(v, port)	LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port))
 
@@ -70,6 +71,14 @@ 
 #define LPAIF_IRQSTAT_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0x4, (port))
 #define LPAIF_IRQCLEAR_REG(v, port)	LPAIF_IRQ_REG_ADDR(v, 0xC, (port))
 
+
+#define LPASS_HDMITX_APP_IRQ_REG_ADDR(v, addr)  \
+	((v->hdmi_irq_reg_base) + (addr))
+
+#define LPASS_HDMITX_APP_IRQEN_REG(v)			LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0x4)
+#define LPASS_HDMITX_APP_IRQSTAT_REG(v)			LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0x8)
+#define LPASS_HDMITX_APP_IRQCLEAR_REG(v)		LPASS_HDMITX_APP_IRQ_REG_ADDR(v, 0xC)
+
 #define LPAIF_IRQ_BITSTRIDE		3
 
 #define LPAIF_IRQ_PER(chan)		(1 << (LPAIF_IRQ_BITSTRIDE * (chan)))
@@ -77,8 +86,22 @@ 
 #define LPAIF_IRQ_ERR(chan)		(4 << (LPAIF_IRQ_BITSTRIDE * (chan)))
 
 #define LPAIF_IRQ_ALL(chan)		(7 << (LPAIF_IRQ_BITSTRIDE * (chan)))
+#define LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan)	(1 << (14 + chan))
+#define LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan)	(1 << (24 + chan))
+#define LPAIF_IRQ_HDMI_METADONE		BIT(23)
 
 /* LPAIF DMA */
+#define LPAIF_HDMI_RDMA_REG_ADDR(v, addr, chan) \
+	(v->hdmi_rdma_reg_base + (addr) + v->hdmi_rdma_reg_stride * (chan))
+
+#define LPAIF_HDMI_RDMACTL_AUDINTF(id)	(id << LPAIF_RDMACTL_AUDINTF_SHIFT)
+
+#define LPAIF_HDMI_RDMACTL_REG(v, chan)		LPAIF_HDMI_RDMA_REG_ADDR(v, 0x00, (chan))
+#define LPAIF_HDMI_RDMABASE_REG(v, chan)	LPAIF_HDMI_RDMA_REG_ADDR(v, 0x04, (chan))
+#define	LPAIF_HDMI_RDMABUFF_REG(v, chan)	LPAIF_HDMI_RDMA_REG_ADDR(v, 0x08, (chan))
+#define LPAIF_HDMI_RDMACURR_REG(v, chan)	LPAIF_HDMI_RDMA_REG_ADDR(v, 0x0C, (chan))
+#define	LPAIF_HDMI_RDMAPER_REG(v, chan)		LPAIF_HDMI_RDMA_REG_ADDR(v, 0x10, (chan))
+#define	LPAIF_HDMI_RDMAPERCNT_REG(v, chan)	LPAIF_HDMI_RDMA_REG_ADDR(v, 0x14, (chan))
 
 #define LPAIF_RDMA_REG_ADDR(v, addr, chan) \
 	(v->rdma_reg_base + (addr) + v->rdma_reg_stride * (chan))
@@ -103,17 +126,22 @@ 
 #define	LPAIF_WRDMAPER_REG(v, chan)	LPAIF_WRDMA_REG_ADDR(v, 0x10, (chan))
 #define	LPAIF_WRDMAPERCNT_REG(v, chan)	LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan))
 
-#define __LPAIF_DMA_REG(v, chan, dir, reg)  \
-	(dir ==  SNDRV_PCM_STREAM_PLAYBACK) ? \
-		LPAIF_RDMA##reg##_REG(v, chan) : \
-		LPAIF_WRDMA##reg##_REG(v, chan)
-
-#define LPAIF_DMACTL_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CTL)
-#define LPAIF_DMABASE_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BASE)
-#define	LPAIF_DMABUFF_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, BUFF)
-#define LPAIF_DMACURR_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, CURR)
-#define	LPAIF_DMAPER_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PER)
-#define	LPAIF_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PERCNT)
+#define LPAIF_INTFDMA_REG(v, chan, reg, dai_id)  \
+		((v->dai_driver[dai_id].id ==  LPASS_DP_RX) ? \
+		LPAIF_HDMI_RDMA##reg##_REG(v, chan) : \
+		 LPAIF_RDMA##reg##_REG(v, chan))
+
+#define __LPAIF_DMA_REG(v, chan, dir, reg, dai_id)  \
+	((dir ==  SNDRV_PCM_STREAM_PLAYBACK) ? \
+		(LPAIF_INTFDMA_REG(v, chan, reg, dai_id)) : \
+		LPAIF_WRDMA##reg##_REG(v, chan))
+
+#define LPAIF_DMACTL_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, CTL, dai_id)
+#define LPAIF_DMABASE_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, BASE, dai_id)
+#define	LPAIF_DMABUFF_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, BUFF, dai_id)
+#define LPAIF_DMACURR_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, CURR, dai_id)
+#define	LPAIF_DMAPER_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, PER, dai_id)
+#define	LPAIF_DMAPERCNT_REG(v, chan, dir, dai_id) __LPAIF_DMA_REG(v, chan, dir, PERCNT, dai_id)
 
 #define LPAIF_DMACTL_BURSTEN_SINGLE	0
 #define LPAIF_DMACTL_BURSTEN_INCR4	1
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 35aead1..e2d1f25 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -23,7 +23,7 @@  struct lpass_pcm_data {
 	int i2s_port;
 };
 
-#define LPASS_PLATFORM_BUFFER_SIZE	(16 * 1024)
+#define LPASS_PLATFORM_BUFFER_SIZE	(24 *  2 * 1024)
 #define LPASS_PLATFORM_PERIODS		2
 
 static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
@@ -62,41 +62,79 @@  static int lpass_platform_alloc_dmactl_fields(struct device *dev,
 	if (drvdata->rd_dmactl == NULL)
 		return -ENOMEM;
 
-	drvdata->wr_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
-					  GFP_KERNEL);
-	if (drvdata->wr_dmactl == NULL)
-		return -ENOMEM;
-
 	rd_dmactl = drvdata->rd_dmactl;
-	wr_dmactl = drvdata->wr_dmactl;
 
 	rd_dmactl->bursten = devm_regmap_field_alloc(dev, map, v->rdma_bursten);
 	rd_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, v->rdma_wpscnt);
 	rd_dmactl->fifowm = devm_regmap_field_alloc(dev, map, v->rdma_fifowm);
-	rd_dmactl->intf = devm_regmap_field_alloc(dev, map, v->rdma_intf);
 	rd_dmactl->enable = devm_regmap_field_alloc(dev, map, v->rdma_enable);
 	rd_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, v->rdma_dyncclk);
-
+	rd_dmactl->intf = devm_regmap_field_alloc(dev, map, v->rdma_intf);
 	if (IS_ERR(rd_dmactl->bursten) || IS_ERR(rd_dmactl->wpscnt) ||
-	    IS_ERR(rd_dmactl->fifowm) || IS_ERR(rd_dmactl->intf) ||
-	    IS_ERR(rd_dmactl->enable) || IS_ERR(rd_dmactl->dyncclk))
+	    IS_ERR(rd_dmactl->fifowm) || IS_ERR(rd_dmactl->dyncclk) ||
+	    IS_ERR(rd_dmactl->enable) || IS_ERR(rd_dmactl->intf))
 		return -EINVAL;
+	drvdata->wr_dmactl = devm_kzalloc(dev,
+			sizeof(struct lpaif_dmactl), GFP_KERNEL);
+	if (drvdata->wr_dmactl == NULL)
+		return -ENOMEM;
 
-	wr_dmactl->bursten = devm_regmap_field_alloc(dev, map, v->wrdma_bursten);
-	wr_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, v->wrdma_wpscnt);
-	wr_dmactl->fifowm = devm_regmap_field_alloc(dev, map, v->wrdma_fifowm);
-	wr_dmactl->intf = devm_regmap_field_alloc(dev, map, v->wrdma_intf);
-	wr_dmactl->enable = devm_regmap_field_alloc(dev, map, v->wrdma_enable);
-	wr_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, v->wrdma_dyncclk);
+	wr_dmactl = drvdata->wr_dmactl;
+
+	wr_dmactl->bursten = devm_regmap_field_alloc(dev, map,
+						v->wrdma_bursten);
+	wr_dmactl->wpscnt = devm_regmap_field_alloc(dev, map,
+						v->wrdma_wpscnt);
+	wr_dmactl->fifowm = devm_regmap_field_alloc(dev, map,
+						v->wrdma_fifowm);
+	wr_dmactl->intf = devm_regmap_field_alloc(dev, map,
+						v->wrdma_intf);
+	wr_dmactl->enable = devm_regmap_field_alloc(dev, map,
+						v->wrdma_enable);
+	wr_dmactl->dyncclk = devm_regmap_field_alloc(dev, map,
+						v->wrdma_dyncclk);
 
 	if (IS_ERR(wr_dmactl->bursten) || IS_ERR(wr_dmactl->wpscnt) ||
-	    IS_ERR(wr_dmactl->fifowm) || IS_ERR(wr_dmactl->intf) ||
-	    IS_ERR(wr_dmactl->enable) || IS_ERR(wr_dmactl->dyncclk))
+		IS_ERR(wr_dmactl->fifowm) || IS_ERR(wr_dmactl->intf) ||
+		IS_ERR(wr_dmactl->enable) || IS_ERR(wr_dmactl->dyncclk))
 		return -EINVAL;
 
 	return 0;
 }
 
+#ifdef CONFIG_SND_SOC_LPASS_SC7180
+static int lpass_platform_alloc_hdmidmactl_fields(struct device *dev,
+					 struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+	struct lpaif_dmactl *rd_dmactl;
+
+	drvdata->hdmi_rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+					  GFP_KERNEL);
+	if (drvdata->hdmi_rd_dmactl == NULL)
+		return -ENOMEM;
+
+	rd_dmactl = drvdata->hdmi_rd_dmactl;
+
+	rd_dmactl->bursten = devm_regmap_field_alloc(dev, map, v->hdmi_rdma_bursten);
+	rd_dmactl->wpscnt = devm_regmap_field_alloc(dev, map, v->hdmi_rdma_wpscnt);
+	rd_dmactl->fifowm = devm_regmap_field_alloc(dev, map, v->hdmi_rdma_fifowm);
+	rd_dmactl->enable = devm_regmap_field_alloc(dev, map, v->hdmi_rdma_enable);
+	rd_dmactl->dyncclk = devm_regmap_field_alloc(dev, map, v->hdmi_rdma_dyncclk);
+	rd_dmactl->burst8 = devm_regmap_field_alloc(dev, map, v->hdmi_rdma_burst8);
+	rd_dmactl->burst16 = devm_regmap_field_alloc(dev, map, v->hdmi_rdma_burst16);
+	rd_dmactl->dynburst = devm_regmap_field_alloc(dev, map, v->hdmi_rdma_dynburst);
+
+	if (IS_ERR(rd_dmactl->bursten) || IS_ERR(rd_dmactl->wpscnt) ||
+	    IS_ERR(rd_dmactl->fifowm) || IS_ERR(rd_dmactl->dyncclk) ||
+	    IS_ERR(rd_dmactl->enable) || IS_ERR(rd_dmactl->dynburst) ||
+	    IS_ERR(rd_dmactl->burst8) || IS_ERR(rd_dmactl->burst16))
+		return -EINVAL;
+	return 0;
+}
+#endif
+
 static int lpass_platform_pcmops_open(struct snd_soc_component *component,
 				      struct snd_pcm_substream *substream)
 {
@@ -106,7 +144,9 @@  static int lpass_platform_pcmops_open(struct snd_soc_component *component,
 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct lpass_variant *v = drvdata->variant;
 	int ret, dma_ch, dir = substream->stream;
-	struct lpass_pcm_data *data;
+	struct lpass_pcm_data *data = NULL;
+	struct regmap *map;
+	unsigned int dai_id = cpu_dai->driver->id;
 
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
@@ -116,24 +156,30 @@  static int lpass_platform_pcmops_open(struct snd_soc_component *component,
 	runtime->private_data = data;
 
 	if (v->alloc_dma_channel)
-		dma_ch = v->alloc_dma_channel(drvdata, dir);
+		dma_ch = v->alloc_dma_channel(drvdata, dir, dai_id);
 	else
 		dma_ch = 0;
 
 	if (dma_ch < 0)
 		return dma_ch;
 
-	drvdata->substream[dma_ch] = substream;
-
-	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_DMACTL_REG(v, dma_ch, dir), 0);
+	if (cpu_dai->driver->id == LPASS_DP_RX) {
+		map = drvdata->hdmiif_map;
+		drvdata->hdmi_substream[dma_ch] = substream;
+	} else {
+		map = drvdata->lpaif_map;
+		drvdata->substream[dma_ch] = substream;
+	}
+	data->dma_ch = dma_ch;
+	ret = regmap_write(map,
+			LPAIF_DMACTL_REG(v, dma_ch, dir, data->i2s_port), 0);
 	if (ret) {
 		dev_err(soc_runtime->dev,
 			"error writing to rdmactl reg: %d\n", ret);
 		return ret;
 	}
 
-	data->dma_ch = dma_ch;
+
 
 	snd_soc_set_runtime_hwparams(substream, &lpass_platform_pcm_hardware);
 
@@ -156,14 +202,20 @@  static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 				       struct snd_pcm_substream *substream)
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
+	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct lpass_variant *v = drvdata->variant;
 	struct lpass_pcm_data *data;
+	unsigned int dai_id = cpu_dai->driver->id;
 
 	data = runtime->private_data;
-	drvdata->substream[data->dma_ch] = NULL;
+	if (dai_id == LPASS_DP_RX)
+		drvdata->hdmi_substream[data->dma_ch] = NULL;
+	else
+		drvdata->substream[data->dma_ch] = NULL;
 	if (v->free_dma_channel)
-		v->free_dma_channel(drvdata, data->dma_ch);
+		v->free_dma_channel(drvdata, data->dma_ch, dai_id);
 
 	kfree(data);
 	return 0;
@@ -174,6 +226,7 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 					   struct snd_pcm_hw_params *params)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
@@ -185,10 +238,15 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 	int id, dir = substream->stream;
 	int bitwidth;
 	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
+	unsigned int dai_id = cpu_dai->driver->id;
 
 	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		dmactl = drvdata->rd_dmactl;
 		id = pcm_data->dma_ch;
+		if (dai_id == LPASS_DP_RX)
+			dmactl = drvdata->hdmi_rd_dmactl;
+		else
+			dmactl = drvdata->rd_dmactl;
+
 	} else {
 		dmactl = drvdata->wr_dmactl;
 		id = pcm_data->dma_ch - v->wrdma_channel_start;
@@ -207,18 +265,48 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 		return ret;
 	}
 
-	regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
+	ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
 	if (ret) {
 		dev_err(soc_runtime->dev, "error updating fifowm field: %d\n", ret);
 		return ret;
 	}
 
-	regmap_fields_write(dmactl->intf, id, LPAIF_DMACTL_AUDINTF(dma_port));
-	if (ret) {
-		dev_err(soc_runtime->dev, "error updating audintf field: %d\n", ret);
-		return ret;
-	}
+	switch (dai_id) {
+	case LPASS_DP_RX:
+		ret = regmap_fields_write(dmactl->burst8, id,
+							LPAIF_DMACTL_BURSTEN_INCR4);
+		if (ret) {
+			dev_err(soc_runtime->dev, "error updating burst8en field: %d\n", ret);
+			return ret;
+		}
+		ret = regmap_fields_write(dmactl->burst16, id,
+							LPAIF_DMACTL_BURSTEN_INCR4);
+		if (ret) {
+			dev_err(soc_runtime->dev, "error updating burst16en field: %d\n", ret);
+			return ret;
+		}
+		ret = regmap_fields_write(dmactl->dynburst, id,
+							LPAIF_DMACTL_BURSTEN_INCR4);
+		if (ret) {
+			dev_err(soc_runtime->dev, "error updating dynbursten field: %d\n", ret);
+			return ret;
+		}
+		break;
+	case MI2S_PRIMARY:
+	case MI2S_SECONDARY:
+		ret = regmap_fields_write(dmactl->intf, id,
+						LPAIF_DMACTL_AUDINTF(dma_port));
+		if (ret) {
+			dev_err(soc_runtime->dev, "error updating audio interface field: %d\n",
+					ret);
+			return ret;
+		}
 
+		break;
+	default:
+		dev_err(soc_runtime->dev, "%s: invalid  interface: %d\n", __func__, dai_id);
+		break;
+	}
 	switch (bitwidth) {
 	case 16:
 		switch (channels) {
@@ -249,16 +337,24 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 			regval = LPAIF_DMACTL_WPSCNT_ONE;
 			break;
 		case 2:
-			regval = LPAIF_DMACTL_WPSCNT_TWO;
+			regval = (dai_id == LPASS_DP_RX ?
+			LPAIF_DMACTL_WPSCNT_ONE :
+			LPAIF_DMACTL_WPSCNT_TWO);
 			break;
 		case 4:
-			regval = LPAIF_DMACTL_WPSCNT_FOUR;
+			regval = (dai_id == LPASS_DP_RX ?
+			LPAIF_DMACTL_WPSCNT_TWO :
+			LPAIF_DMACTL_WPSCNT_FOUR);
 			break;
 		case 6:
-			regval = LPAIF_DMACTL_WPSCNT_SIX;
+			regval = (dai_id == LPASS_DP_RX ?
+			LPAIF_DMACTL_WPSCNT_THREE :
+			LPAIF_DMACTL_WPSCNT_SIX);
 			break;
 		case 8:
-			regval = LPAIF_DMACTL_WPSCNT_EIGHT;
+			regval = (dai_id == LPASS_DP_RX ?
+			LPAIF_DMACTL_WPSCNT_FOUR :
+			LPAIF_DMACTL_WPSCNT_EIGHT);
 			break;
 		default:
 			dev_err(soc_runtime->dev,
@@ -268,7 +364,8 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 		}
 		break;
 	default:
-		dev_err(soc_runtime->dev, "invalid PCM config given: bw=%d, ch=%u\n",
+		dev_err(soc_runtime->dev,
+			"invalid PCM config given: bw=%d,ch=%u\n",
 			bitwidth, channels);
 		return -EINVAL;
 	}
@@ -287,15 +384,23 @@  static int lpass_platform_pcmops_hw_free(struct snd_soc_component *component,
 					 struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	unsigned int reg;
 	int ret;
+	struct regmap *map;
+	unsigned int dai_id = cpu_dai->driver->id;
 
-	reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream);
-	ret = regmap_write(drvdata->lpaif_map, reg, 0);
+	if (dai_id == LPASS_DP_RX)
+		map = drvdata->hdmiif_map;
+	else
+		map = drvdata->lpaif_map;
+
+	reg = LPAIF_DMACTL_REG(v, pcm_data->dma_ch, substream->stream, dai_id);
+	ret = regmap_write(map, reg, 0);
 	if (ret)
 		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
 			ret);
@@ -308,33 +413,44 @@  static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	struct lpaif_dmactl *dmactl;
+	struct regmap *map;
 	int ret, id, ch, dir = substream->stream;
+	unsigned int dai_id = cpu_dai->driver->id;
+
 
 	ch = pcm_data->dma_ch;
 	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		dmactl = drvdata->rd_dmactl;
+		if (dai_id == LPASS_DP_RX) {
+			dmactl = drvdata->hdmi_rd_dmactl;
+			map = drvdata->hdmiif_map;
+		} else {
+			dmactl = drvdata->rd_dmactl;
+			map = drvdata->lpaif_map;
+		}
+
 		id = pcm_data->dma_ch;
 	} else {
 		dmactl = drvdata->wr_dmactl;
 		id = pcm_data->dma_ch - v->wrdma_channel_start;
+		map = drvdata->lpaif_map;
 	}
 
-	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_DMABASE_REG(v, ch, dir),
-			runtime->dma_addr);
+	ret = regmap_write(map, LPAIF_DMABASE_REG(v, ch, dir, dai_id),
+				runtime->dma_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev, "error writing to rdmabase reg: %d\n",
 			ret);
 		return ret;
 	}
 
-	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_DMABUFF_REG(v, ch, dir),
+	ret = regmap_write(map,
+			LPAIF_DMABUFF_REG(v, ch, dir, dai_id),
 			(snd_pcm_lib_buffer_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "error writing to rdmabuff reg: %d\n",
@@ -342,8 +458,8 @@  static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 		return ret;
 	}
 
-	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_DMAPER_REG(v, ch, dir),
+	ret = regmap_write(map,
+			LPAIF_DMAPER_REG(v, ch, dir, dai_id),
 			(snd_pcm_lib_period_bytes(substream) >> 2) - 1);
 	if (ret) {
 		dev_err(soc_runtime->dev, "error writing to rdmaper reg: %d\n",
@@ -366,18 +482,26 @@  static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 					 int cmd)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	struct lpaif_dmactl *dmactl;
+	struct regmap *map;
 	int ret, ch, id;
 	int dir = substream->stream;
+	unsigned int reg_irqclr = 0, val_irqclr = 0;
+	unsigned int  reg_irqen = 0, val_irqen = 0, val_mask = 0;
+	unsigned int dai_id = cpu_dai->driver->id;
 
 	ch = pcm_data->dma_ch;
 	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
-		dmactl = drvdata->rd_dmactl;
 		id = pcm_data->dma_ch;
+		if (dai_id == LPASS_DP_RX)
+			dmactl = drvdata->hdmi_rd_dmactl;
+		else
+			dmactl = drvdata->rd_dmactl;
 	} else {
 		dmactl = drvdata->wr_dmactl;
 		id = pcm_data->dma_ch - v->wrdma_channel_start;
@@ -387,31 +511,63 @@  static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		/* clear status before enabling interrupts */
-		ret = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(ch));
+		ret = regmap_fields_write(dmactl->enable, id,
+						 LPAIF_DMACTL_ENABLE_ON);
 		if (ret) {
 			dev_err(soc_runtime->dev,
-				"error writing to irqclear reg: %d\n", ret);
+				"error writing to rdmactl reg: %d\n", ret);
 			return ret;
 		}
+		switch (dai_id) {
+		case LPASS_DP_RX:
+			ret = regmap_fields_write(dmactl->dyncclk, id,
+					 LPAIF_DMACTL_DYNCLK_ON);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg: %d\n", ret);
+				return ret;
+			}
+			map = drvdata->hdmiif_map;
+			reg_irqclr = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
+			val_irqclr = (LPAIF_IRQ_ALL(ch) |
+					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
+					LPAIF_IRQ_HDMI_METADONE |
+					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
+
+			reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
+			val_mask = (LPAIF_IRQ_ALL(ch) |
+					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
+					LPAIF_IRQ_HDMI_METADONE |
+					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
+			val_irqen = (LPAIF_IRQ_ALL(ch) |
+					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
+					LPAIF_IRQ_HDMI_METADONE |
+					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
+			break;
+		case MI2S_PRIMARY:
+		case MI2S_SECONDARY:
+			map = drvdata->lpaif_map;
+			reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_irqclr = LPAIF_IRQ_ALL(ch);
+
+
+			reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = LPAIF_IRQ_ALL(ch);
+			break;
+		default:
+			dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
+			return -EINVAL;
+		}
 
-		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(ch),
-				LPAIF_IRQ_ALL(ch));
+		ret = regmap_write(map, reg_irqclr, val_irqclr);
 		if (ret) {
-			dev_err(soc_runtime->dev,
-				"error writing to irqen reg: %d\n", ret);
+			dev_err(soc_runtime->dev, "error writing to irqclear reg: %d\n", ret);
 			return ret;
 		}
-
-		ret = regmap_fields_write(dmactl->enable, id,
-					 LPAIF_DMACTL_ENABLE_ON);
+		ret = regmap_update_bits(map, reg_irqen, val_mask, val_irqen);
 		if (ret) {
-			dev_err(soc_runtime->dev,
-				"error writing to rdmactl reg: %d\n", ret);
+			dev_err(soc_runtime->dev, "error writing to irqen reg: %d\n", ret);
 			return ret;
 		}
 		break;
@@ -425,10 +581,38 @@  static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 				"error writing to rdmactl reg: %d\n", ret);
 			return ret;
 		}
+		switch (dai_id) {
+		case LPASS_DP_RX:
+			ret = regmap_fields_write(dmactl->dyncclk, id,
+					 LPAIF_DMACTL_DYNCLK_OFF);
+			if (ret) {
+				dev_err(soc_runtime->dev,
+					"error writing to rdmactl reg: %d\n", ret);
+				return ret;
+			}
+			map = drvdata->hdmiif_map;
+			reg_irqen = LPASS_HDMITX_APP_IRQEN_REG(v);
+			val_mask = (LPAIF_IRQ_ALL(ch) |
+					LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(ch) |
+					LPAIF_IRQ_HDMI_METADONE |
+					LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(ch));
+			val_irqen = 0;
+			break;
+		case MI2S_PRIMARY:
+		case MI2S_SECONDARY:
+			map = drvdata->lpaif_map;
+			reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST);
+			val_mask = LPAIF_IRQ_ALL(ch);
+			val_irqen = 0;
+			break;
+		default:
+			dev_err(soc_runtime->dev, "%s: invalid %d interface\n", __func__, dai_id);
+			return -EINVAL;
+		}
 
-		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ALL(ch), 0);
+		ret = regmap_update_bits(map,
+				reg_irqen,
+				val_mask, val_irqen);
 		if (ret) {
 			dev_err(soc_runtime->dev,
 				"error writing to irqen reg: %d\n", ret);
@@ -445,25 +629,33 @@  static snd_pcm_uframes_t lpass_platform_pcmops_pointer(
 		struct snd_pcm_substream *substream)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
 	unsigned int base_addr, curr_addr;
 	int ret, ch, dir = substream->stream;
+	struct regmap *map;
+	unsigned int dai_id = cpu_dai->driver->id;
+
+	if (dai_id == LPASS_DP_RX)
+		map = drvdata->hdmiif_map;
+	else
+		map = drvdata->lpaif_map;
 
 	ch = pcm_data->dma_ch;
 
-	ret = regmap_read(drvdata->lpaif_map,
-			LPAIF_DMABASE_REG(v, ch, dir), &base_addr);
+	ret = regmap_read(map,
+			LPAIF_DMABASE_REG(v, ch, dir, dai_id), &base_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev,
 			"error reading from rdmabase reg: %d\n", ret);
 		return ret;
 	}
 
-	ret = regmap_read(drvdata->lpaif_map,
-			LPAIF_DMACURR_REG(v, ch, dir), &curr_addr);
+	ret = regmap_read(map,
+			LPAIF_DMACURR_REG(v, ch, dir, dai_id), &curr_addr);
 	if (ret) {
 		dev_err(soc_runtime->dev,
 			"error reading from rdmacurr reg: %d\n", ret);
@@ -489,14 +681,36 @@  static irqreturn_t lpass_dma_interrupt_handler(
 			int chan, u32 interrupts)
 {
 	struct snd_soc_pcm_runtime *soc_runtime = asoc_substream_to_rtd(substream);
+	struct snd_soc_dai *cpu_dai = asoc_rtd_to_cpu(soc_runtime, 0);
 	struct lpass_variant *v = drvdata->variant;
 	irqreturn_t ret = IRQ_NONE;
 	int rv;
-
+	unsigned int reg = 0, val = 0;
+	struct regmap *map;
+	unsigned int dai_id = cpu_dai->driver->id;
+
+	switch (dai_id) {
+	case LPASS_DP_RX:
+		map = drvdata->hdmiif_map;
+		reg = LPASS_HDMITX_APP_IRQCLEAR_REG(v);
+		val = (LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
+		LPAIF_IRQ_HDMI_METADONE |
+		LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan));
+	break;
+	case MI2S_PRIMARY:
+	case MI2S_SECONDARY:
+		map = drvdata->lpaif_map;
+		reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST);
+		val = 0;
+	break;
+	default:
+	dev_err(soc_runtime->dev, "%s: invalid  %d interface\n", __func__, dai_id);
+	return -EINVAL;
+	}
 	if (interrupts & LPAIF_IRQ_PER(chan)) {
-		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_PER(chan));
+
+		rv = regmap_write(map, reg,
+				LPAIF_IRQ_PER(chan) | val);
 		if (rv) {
 			dev_err(soc_runtime->dev,
 				"error writing to irqclear reg: %d\n", rv);
@@ -507,9 +721,8 @@  static irqreturn_t lpass_dma_interrupt_handler(
 	}
 
 	if (interrupts & LPAIF_IRQ_XRUN(chan)) {
-		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_XRUN(chan));
+		rv = regmap_write(map, reg,
+				LPAIF_IRQ_XRUN(chan) | val);
 		if (rv) {
 			dev_err(soc_runtime->dev,
 				"error writing to irqclear reg: %d\n", rv);
@@ -521,9 +734,8 @@  static irqreturn_t lpass_dma_interrupt_handler(
 	}
 
 	if (interrupts & LPAIF_IRQ_ERR(chan)) {
-		rv = regmap_write(drvdata->lpaif_map,
-				LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST),
-				LPAIF_IRQ_ERR(chan));
+		rv = regmap_write(map, reg,
+				LPAIF_IRQ_ERR(chan) | val);
 		if (rv) {
 			dev_err(soc_runtime->dev,
 				"error writing to irqclear reg: %d\n", rv);
@@ -534,6 +746,16 @@  static irqreturn_t lpass_dma_interrupt_handler(
 		ret = IRQ_HANDLED;
 	}
 
+	if (interrupts & val) {
+		rv = regmap_write(map, reg, val);
+		if (rv) {
+			dev_err(soc_runtime->dev,
+			"error writing to irqclear reg: %d\n", rv);
+			return IRQ_NONE;
+		}
+		ret = IRQ_HANDLED;
+	}
+
 	return ret;
 }
 
@@ -553,7 +775,8 @@  static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 
 	/* Handle per channel interrupts */
 	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
-		if (irqs & LPAIF_IRQ_ALL(chan) && drvdata->substream[chan]) {
+		if (irqs & LPAIF_IRQ_ALL(chan)
+			&& drvdata->substream[chan]) {
 			rv = lpass_dma_interrupt_handler(
 						drvdata->substream[chan],
 						drvdata, chan, irqs);
@@ -565,6 +788,39 @@  static irqreturn_t lpass_platform_lpaif_irq(int irq, void *data)
 	return IRQ_HANDLED;
 }
 
+#ifdef CONFIG_SND_SOC_LPASS_SC7180
+static irqreturn_t lpass_platform_hdmiif_irq(int irq, void *data)
+{
+	struct lpass_data *drvdata = data;
+	struct lpass_variant *v = drvdata->variant;
+	unsigned int irqs;
+	int rv, chan;
+
+	rv = regmap_read(drvdata->hdmiif_map,
+			LPASS_HDMITX_APP_IRQSTAT_REG(v), &irqs);
+	if (rv) {
+		pr_err("error reading from irqstat reg: %d\n", rv);
+		return IRQ_NONE;
+	}
+
+	/* Handle per channel interrupts */
+	for (chan = 0; chan < LPASS_MAX_DMA_CHANNELS; chan++) {
+		if (irqs & (LPAIF_IRQ_ALL(chan) | LPAIF_IRQ_HDMI_REQ_ON_PRELOAD(chan) |
+				LPAIF_IRQ_HDMI_METADONE |
+				LPAIF_IRQ_HDMI_SDEEP_AUD_DIS(chan))
+			&& drvdata->hdmi_substream[chan]) {
+			rv = lpass_dma_interrupt_handler(
+						drvdata->hdmi_substream[chan],
+						drvdata, chan, irqs);
+			if (rv != IRQ_HANDLED)
+				return rv;
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+#endif
+
 static int lpass_platform_pcm_new(struct snd_soc_component *component,
 				  struct snd_soc_pcm_runtime *soc_runtime)
 {
@@ -642,6 +898,13 @@  int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 	if (drvdata->lpaif_irq < 0)
 		return -ENODEV;
 
+	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
+			lpass_platform_lpaif_irq, 0, "lpass-irq-lpaif", drvdata);
+	if (ret) {
+		dev_err(&pdev->dev, "irq request failed: %d\n", ret);
+		return ret;
+	}
+
 	/* ensure audio hardware is disabled */
 	ret = regmap_write(drvdata->lpaif_map,
 			LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST), 0);
@@ -649,23 +912,40 @@  int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 		dev_err(&pdev->dev, "error writing to irqen reg: %d\n", ret);
 		return ret;
 	}
+	ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
+						 drvdata->lpaif_map);
+	if (ret) {
+		dev_err(&pdev->dev,
+			"error initializing dmactl fields: %d\n", ret);
+		return ret;
+	}
 
-	ret = devm_request_irq(&pdev->dev, drvdata->lpaif_irq,
-			lpass_platform_lpaif_irq, IRQF_TRIGGER_RISING,
-			"lpass-irq-lpaif", drvdata);
+#ifdef CONFIG_SND_SOC_LPASS_SC7180
+	drvdata->hdmiif_irq = platform_get_irq_byname(pdev, "lpass-irq-hdmi");
+	if (drvdata->hdmiif_irq < 0)
+		return -ENODEV;
+
+	ret = devm_request_irq(&pdev->dev, drvdata->hdmiif_irq,
+			lpass_platform_hdmiif_irq, 0, "lpass-irq-hdmi", drvdata);
 	if (ret) {
-		dev_err(&pdev->dev, "irq request failed: %d\n", ret);
+		dev_err(&pdev->dev, "irq hdmi request failed: %d\n", ret);
+		return ret;
+	}
+	ret = regmap_write(drvdata->hdmiif_map,
+			LPASS_HDMITX_APP_IRQEN_REG(v), 0);
+	if (ret) {
+		dev_err(&pdev->dev, "error writing to hdmi irqen reg: %d\n", ret);
 		return ret;
 	}
 
-	ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
-						 drvdata->lpaif_map);
+	ret = lpass_platform_alloc_hdmidmactl_fields(&pdev->dev,
+						 drvdata->hdmiif_map);
 	if (ret) {
 		dev_err(&pdev->dev,
-			"error initializing dmactl fields: %d\n", ret);
+			"error initializing hdmidmactl fields: %d\n", ret);
 		return ret;
 	}
-
+#endif
 	return devm_snd_soc_register_component(&pdev->dev,
 			&lpass_component_driver, NULL, 0);
 }
diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h
index 51c9991..e3fe63b 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -1,6 +1,6 @@ 
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2010-2011,2013-2015 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2010-2011,2013-2015,2020 The Linux Foundation. All rights reserved.
  *
  * lpass.h - Definitions for the QTi LPASS
  */
@@ -12,10 +12,14 @@ 
 #include <linux/compiler.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <dt-bindings/sound/sc7180-lpass.h>
 
 #define LPASS_AHBIX_CLOCK_FREQUENCY		131072000
 #define LPASS_MAX_MI2S_PORTS			(8)
 #define LPASS_MAX_DMA_CHANNELS			(8)
+#define LPASS_MAX_HDMI_DMA_CHANNELS		(4)
+
+
 
 struct lpaif_i2sctl {
 	struct regmap_field *loopback;
@@ -32,6 +36,9 @@  struct lpaif_i2sctl {
 
 struct lpaif_dmactl {
 	struct regmap_field *bursten;
+	struct regmap_field *burst8;
+	struct regmap_field *burst16;
+	struct regmap_field *dynburst;
 	struct regmap_field *wpscnt;
 	struct regmap_field *intf;
 	struct regmap_field *fifowm;
@@ -57,21 +64,25 @@  struct lpass_data {
 
 	/* low-power audio interface (LPAIF) registers */
 	void __iomem *lpaif;
+	void __iomem *hdmiif;
 
 	/* regmap backed by the low-power audio interface (LPAIF) registers */
 	struct regmap *lpaif_map;
+	struct regmap *hdmiif_map;
 
 	/* interrupts from the low-power audio interface (LPAIF) */
 	int lpaif_irq;
-
+	int hdmiif_irq;
 	/* SOC specific variations in the LPASS IP integration */
 	struct lpass_variant *variant;
 
 	/* bit map to keep track of static channel allocations */
 	unsigned long dma_ch_bit_map;
+	unsigned long hdmi_dma_ch_bit_map;
 
 	/* used it for handling interrupt per dma channel */
 	struct snd_pcm_substream *substream[LPASS_MAX_DMA_CHANNELS];
+	struct snd_pcm_substream *hdmi_substream[LPASS_MAX_HDMI_DMA_CHANNELS];
 
 	/* SOC specific clock list */
 	struct clk_bulk_data *clks;
@@ -81,22 +92,36 @@  struct lpass_data {
 	struct lpaif_i2sctl *i2sctl;
 	struct lpaif_dmactl *rd_dmactl;
 	struct lpaif_dmactl *wr_dmactl;
+	struct lpaif_dmactl *hdmi_rd_dmactl;
+	/* Regmap fields of HDMI_CTRL registers*/
+	struct lpass_hdmi_tx_ctl *tx_ctl;
+	struct lpass_hdmitx_legacy *legacy;
+	struct lpass_vbit_ctrl *vbit_ctl;
+	struct lpass_hdmi_tx_ch_msb *ch_msb[LPASS_MAX_HDMI_DMA_CHANNELS];
+	struct lpass_hdmi_tx_ch_lsb *ch_lsb[LPASS_MAX_HDMI_DMA_CHANNELS];
+	struct lpass_hdmi_tx_parity *tx_parity;
+	struct lpass_hdmitx_dmactl *hdmi_tx_dmactl[LPASS_MAX_HDMI_DMA_CHANNELS];
+	struct lpass_dp_metadata_ctl *meta_ctl;
+	struct lpass_sstream_ctl *sstream_ctl;
 };
 
 /* Vairant data per each SOC */
 struct lpass_variant {
-	u32	i2sctrl_reg_base;
-	u32	i2sctrl_reg_stride;
-	u32	i2s_ports;
 	u32	irq_reg_base;
 	u32	irq_reg_stride;
 	u32	irq_ports;
 	u32	rdma_reg_base;
 	u32	rdma_reg_stride;
 	u32	rdma_channels;
+	u32	hdmi_rdma_reg_base;
+	u32	hdmi_rdma_reg_stride;
+	u32	hdmi_rdma_channels;
 	u32	wrdma_reg_base;
 	u32	wrdma_reg_stride;
 	u32	wrdma_channels;
+	u32	i2sctrl_reg_base;
+	u32	i2sctrl_reg_stride;
+	u32	i2s_ports;
 
 	/* I2SCTL Register fields */
 	struct reg_field loopback;
@@ -109,8 +134,84 @@  struct lpass_variant {
 	struct reg_field wssrc;
 	struct reg_field bitwidth;
 
+	u32	hdmi_irq_reg_base;
+	u32	hdmi_irq_reg_stride;
+	u32	hdmi_irq_ports;
+
+	/* HDMI specific controls */
+	u32	hdmi_tx_ctl_addr;
+	u32	hdmi_legacy_addr;
+	u32	hdmi_vbit_addr;
+	u32	hdmi_ch_lsb_addr;
+	u32	hdmi_ch_msb_addr;
+	u32	ch_stride;
+	u32	hdmi_parity_addr;
+	u32	hdmi_dmactl_addr;
+	u32	hdmi_dma_stride;
+	u32	hdmi_DP_addr;
+	u32	hdmi_sstream_addr;
+
+	/* HDMI SSTREAM CTRL fields  */
+	struct reg_field sstream_en;
+	struct reg_field dma_sel;
+	struct reg_field auto_bbit_en;
+	struct reg_field layout;
+	struct reg_field layout_sp;
+	struct reg_field set_sp_on_en;
+	struct reg_field dp_audio;
+	struct reg_field dp_staffing_en;
+	struct reg_field dp_sp_b_hw_en;
+
+	/* HDMI DP METADATA CTL fields */
+	struct reg_field mute;
+	struct reg_field as_sdp_cc;
+	struct reg_field as_sdp_ct;
+	struct reg_field aif_db4;
+	struct reg_field frequency;
+	struct reg_field mst_index;
+	struct reg_field dptx_index;
+
+	/* HDMI TX CTRL fields */
+	struct reg_field soft_reset;
+	struct reg_field force_reset;
+
+	/* HDMI TX DMA CTRL */
+	struct reg_field use_hw_chs;
+	struct reg_field use_hw_usr;
+	struct reg_field hw_chs_sel;
+	struct reg_field hw_usr_sel;
+
+	/* HDMI VBIT CTRL */
+	struct reg_field replace_vbit;
+	struct reg_field vbit_stream;
+
+	/* HDMI TX LEGACY */
+	struct reg_field legacy_en;
+
+	/* HDMI TX PARITY */
+	struct reg_field calc_en;
+
+	/* HDMI CH LSB */
+	struct reg_field lsb_bits;
+
+	/* HDMI CH MSB */
+	struct reg_field msb_bits;
+
+	struct reg_field hdmi_rdma_bursten;
+	struct reg_field hdmi_rdma_burst8;
+	struct reg_field hdmi_rdma_burst16;
+	struct reg_field hdmi_rdma_dynburst;
+	struct reg_field hdmi_rdma_wpscnt;
+	struct reg_field hdmi_rdma_intf;
+	struct reg_field hdmi_rdma_fifowm;
+	struct reg_field hdmi_rdma_enable;
+	struct reg_field hdmi_rdma_dyncclk;
+
 	/* RD_DMA Register fields */
 	struct reg_field rdma_bursten;
+	struct reg_field rdma_burst8;
+	struct reg_field rdma_burst16;
+	struct reg_field rdma_dynburst;
 	struct reg_field rdma_wpscnt;
 	struct reg_field rdma_intf;
 	struct reg_field rdma_fifowm;
@@ -134,8 +235,8 @@  struct lpass_variant {
 	/* SOC specific initialization like clocks */
 	int (*init)(struct platform_device *pdev);
 	int (*exit)(struct platform_device *pdev);
-	int (*alloc_dma_channel)(struct lpass_data *data, int direction);
-	int (*free_dma_channel)(struct lpass_data *data, int ch);
+	int (*alloc_dma_channel)(struct lpass_data *data, int direction, unsigned int dai_id);
+	int (*free_dma_channel)(struct lpass_data *data, int ch, unsigned int dai_id);
 
 	/* SOC specific dais */
 	struct snd_soc_dai_driver *dai_driver;
@@ -154,5 +255,7 @@  int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev);
 int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev);
 int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai);
 extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops;
-
+extern const struct snd_soc_dai_ops asoc_qcom_lpass_hdmi_dai_ops;
+extern struct regmap_config lpass_hdmi_regmap_config;
+extern int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map);
 #endif /* __LPASS_H__ */