[v3,3/8] ASoC: qcom: lpass: Use regmap_field for i2sctl and dmactl registers
diff mbox series

Message ID 1594184896-10629-4-git-send-email-rohitkr@codeaurora.org
State New
Headers show
Series
  • ASoC: qcom: Add support for SC7180 lpass variant
Related show

Commit Message

Rohit Kumar July 8, 2020, 5:08 a.m. UTC
I2SCTL and DMACTL registers has different bits alignment for newer
LPASS variants of SC7180 soc. Use REG_FIELD_ID() to define the
reg_fields in platform specific file and removed shifts and mask
macros for such registers from header file.

Signed-off-by: Rohit kumar <rohitkr@codeaurora.org>
---
 sound/soc/qcom/lpass-apq8016.c   |  24 ++++++
 sound/soc/qcom/lpass-cpu.c       | 163 +++++++++++++++++++++++----------------
 sound/soc/qcom/lpass-ipq806x.c   |  24 ++++++
 sound/soc/qcom/lpass-lpaif-reg.h | 157 +++++++++++++++++++------------------
 sound/soc/qcom/lpass-platform.c  | 151 +++++++++++++++++++++++++++---------
 sound/soc/qcom/lpass.h           |  53 +++++++++++++
 6 files changed, 398 insertions(+), 174 deletions(-)

Comments

Srinivas Kandagatla July 9, 2020, 9:26 a.m. UTC | #1
On 08/07/2020 06:08, Rohit kumar wrote:
> I2SCTL and DMACTL registers has different bits alignment for newer
> LPASS variants of SC7180 soc. Use REG_FIELD_ID() to define the
> reg_fields in platform specific file and removed shifts and mask
> macros for such registers from header file.
> 
> Signed-off-by: Rohit kumar <rohitkr@codeaurora.org>

Thanks Rohit for doing this, this looks much better now!
I have few minor comments..

> ---
>   sound/soc/qcom/lpass-apq8016.c   |  24 ++++++
>   sound/soc/qcom/lpass-cpu.c       | 163 +++++++++++++++++++++++----------------
>   sound/soc/qcom/lpass-ipq806x.c   |  24 ++++++
>   sound/soc/qcom/lpass-lpaif-reg.h | 157 +++++++++++++++++++------------------
>   sound/soc/qcom/lpass-platform.c  | 151 +++++++++++++++++++++++++++---------
>   sound/soc/qcom/lpass.h           |  53 +++++++++++++
>   6 files changed, 398 insertions(+), 174 deletions(-)
> 

index f0c7e93..f358d12 100644
> --- a/sound/soc/qcom/lpass-cpu.c
> +++ b/sound/soc/qcom/lpass-cpu.c
> @@ -29,6 +29,32 @@
>   #define LPASS_CPU_I2S_SD0_1_2_MASK	GENMASK(2, 0)
>   #define LPASS_CPU_I2S_SD0_1_2_3_MASK	GENMASK(3, 0)
>   


>   static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
>   		unsigned int freq, int dir)
>   {
> @@ -79,12 +105,13 @@ static int lpass_cpu_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);
> +	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
> +	unsigned int id = dai->driver->id;
>   	snd_pcm_format_t format = params_format(params);
>   	unsigned int channels = params_channels(params);
>   	unsigned int rate = params_rate(params);
>   	unsigned int mode;
> -	unsigned int regval;
> -	int bitwidth, ret;
> +	int bitwidth, ret, regval;

Why is this change?

>   
>   	bitwidth = snd_pcm_format_width(format);
>   	if (bitwidth < 0) {
> @@ -92,28 +119,45 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
>   		return bitwidth;
>   	}
>   
> -	regval = LPAIF_I2SCTL_LOOPBACK_DISABLE |
> -			LPAIF_I2SCTL_WSSRC_INTERNAL;
> +	ret = regmap_fields_write(i2sctl->loopback, id,
> +				 LPAIF_I2SCTL_LOOPBACK_DISABLE);
> +	if (ret) {
> +		dev_err(dai->dev, "error updating loopback field: %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = regmap_fields_write(i2sctl->wssrc, id,
> +				 LPAIF_I2SCTL_WSSRC_INTERNAL);
> +	if (ret) {
> +		dev_err(dai->dev, "error updating wssrc field: %d\n", ret);
> +		return ret;
> +	}
>   
>   	switch (bitwidth) {
>   	case 16:
> -		regval |= LPAIF_I2SCTL_BITWIDTH_16;
> +		regval = LPAIF_I2SCTL_BITWIDTH_16;
>   		break;
>   	case 24:
> -		regval |= LPAIF_I2SCTL_BITWIDTH_24;
> +		regval = LPAIF_I2SCTL_BITWIDTH_24;
>   		break;
>   	case 32:
> -		regval |= LPAIF_I2SCTL_BITWIDTH_32;
> +		regval = LPAIF_I2SCTL_BITWIDTH_32;
>   		break;
>   	default:
>   		dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth);
>   		return -EINVAL;
>   	}
>   
> +	ret = regmap_fields_write(i2sctl->bitwidth, id, regval);
> +	if (ret) {
> +		dev_err(dai->dev, "error updating bitwidth field: %d\n", ret);
> +		return ret;
> +	}
> +
>   	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
> -		mode = drvdata->mi2s_playback_sd_mode[dai->driver->id];
> +		mode = drvdata->mi2s_playback_sd_mode[id];
>   	else
> -		mode = drvdata->mi2s_capture_sd_mode[dai->driver->id];
> +		mode = drvdata->mi2s_capture_sd_mode[id];
>   
>   	if (!mode) {
>   		dev_err(dai->dev, "no line is assigned\n");
> @@ -175,30 +219,34 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
>   	}
>   
>   	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> -		regval |= LPAIF_I2SCTL_SPKMODE(mode);
> +		ret = regmap_fields_write(i2sctl->spkmode, id,
> +					 LPAIF_I2SCTL_SPKMODE(mode));
>   
>   		if (channels >= 2)
> -			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
> +			ret = regmap_fields_write(i2sctl->spkmono, id,
> +						 LPAIF_I2SCTL_SPKMONO_STEREO);
>   		else
> -			regval |= LPAIF_I2SCTL_SPKMONO_MONO;
> +			ret = regmap_fields_write(i2sctl->spkmono, id,
> +						 LPAIF_I2SCTL_SPKMONO_MONO);
>   	} else {
> -		regval |= LPAIF_I2SCTL_MICMODE(mode);
> +		ret = regmap_fields_write(i2sctl->micmode, id,
> +					 LPAIF_I2SCTL_MICMODE(mode));
>   
>   		if (channels >= 2)
> -			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
> +			ret = regmap_fields_write(i2sctl->micmono, id,
> +						 LPAIF_I2SCTL_MICMONO_STEREO);
>   		else
> -			regval |= LPAIF_I2SCTL_MICMONO_MONO;
> +			ret = regmap_fields_write(i2sctl->micmono, id,
> +						 LPAIF_I2SCTL_MICMONO_MONO);
>   	}
>   
> -	ret = regmap_write(drvdata->lpaif_map,
> -			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
> -			   regval);
>   	if (ret) {
> -		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
> +		dev_err(dai->dev, "error writing to i2sctl channels mode: %d\n",
> +			ret);
>   		return ret;
>   	}
>   
> -	ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
> +	ret = clk_set_rate(drvdata->mi2s_bit_clk[id],
>   			   rate * bitwidth * 2);
>   	if (ret) {
>   		dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n",
> @@ -209,41 +257,24 @@ static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
>   	return 0;
>   }
>   
> -static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
> -		struct snd_soc_dai *dai)
> -{
> -	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> -	int ret;
> -
> -	ret = regmap_write(drvdata->lpaif_map,
> -			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
> -			   0);
> -	if (ret)
> -		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
> -
> -	return ret;
> -}

Any particular reason why this function remove
> -
>   static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
>   		struct snd_soc_dai *dai)
>   {
>   	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
> +	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
> +	unsigned int id = dai->driver->id;
>   	int ret;
> -	unsigned int val, mask;
>   
>   	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
> -		val = LPAIF_I2SCTL_SPKEN_ENABLE;
> -		mask = LPAIF_I2SCTL_SPKEN_MASK;
> -	} else  {
> -		val = LPAIF_I2SCTL_MICEN_ENABLE;
> -		mask = LPAIF_I2SCTL_MICEN_MASK;
> +		ret = regmap_fields_write(i2sctl->spken, id,
> +					 LPAIF_I2SCTL_SPKEN_ENABLE);
> +	} else {
> +		ret = regmap_fields_write(i2sctl->micen, id,
> +					 LPAIF_I2SCTL_MICEN_ENABLE);
>   	}
>   
> -	ret = regmap_update_bits(drvdata->lpaif_map,
> -			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
> -			mask, val);
>   	if (ret)
> -		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
> +		dev_err(dai->dev, "error writing to i2sctl enable: %d\n", ret);
>   
>   	return ret;
>   }
...
> @@ -304,7 +326,6 @@ const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
>   	.startup	= lpass_cpu_daiops_startup,
>   	.shutdown	= lpass_cpu_daiops_shutdown,
>   	.hw_params	= lpass_cpu_daiops_hw_params,
> -	.hw_free	= lpass_cpu_daiops_hw_free,
>   	.prepare	= lpass_cpu_daiops_prepare,
>   	.trigger	= lpass_cpu_daiops_trigger,
>   };
> @@ -599,6 +620,18 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
>   		}
>   	}
>   
> +	/* Allocation for i2sctl regmap fields */
> +	drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
> +					GFP_KERNEL);
> +
> +	/* Initialize bitfields for dai I2SCTL register */
> +	ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
> +						drvdata->lpaif_map);
> +	if (ret) {
> +		dev_err(dev, "error init i2sctl field: %d\n", ret);
> +		return ret;
> +	}
> +
>   	ret = devm_snd_soc_register_component(dev,
>   					      &lpass_cpu_comp_driver,
>   					      variant->dai_driver,

> diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
> index 72a3e2f..5258e60 100644
> --- a/sound/soc/qcom/lpass-lpaif-reg.h
> +++ b/sound/soc/qcom/lpass-lpaif-reg.h
> @@ -12,15 +12,12 @@
...
>   #endif /* __LPASS_LPAIF_REG_H__ */
> diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
> index 34f7fd1..445ca193 100644
> --- a/sound/soc/qcom/lpass-platform.c
> +++ b/sound/soc/qcom/lpass-platform.c
> @@ -50,6 +50,53 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
>   	.fifo_size		=	0,
>   };
>   
...
>   static int lpass_platform_pcmops_open(struct snd_soc_component *component,
>   				      struct snd_pcm_substream *substream)
>   {
> @@ -59,9 +106,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;
>   
> -	data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);

Does this change belong in this patch?

>   	if (!data)
>   		return -ENOMEM;
>   
> @@ -111,13 +158,13 @@ static int lpass_platform_pcmops_close(struct snd_soc_component *component,
>   	struct snd_pcm_runtime *runtime = substream->runtime;
>   	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
>   	struct lpass_variant *v = drvdata->variant;
> -	struct lpass_pcm_data *data;
> +	struct lpass_pcm_data *data = runtime->private_data;
>   
> -	data = runtime->private_data;
>   	drvdata->substream[data->dma_ch] = NULL;
>   	if (v->free_dma_channel)
>   		v->free_dma_channel(drvdata, data->dma_ch);
>   
> +	kfree(data);
>   	return 0;
>   }
>   
>   
>   	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 450020e..4294ec2 100644
> --- a/sound/soc/qcom/lpass.h
> +++ b/sound/soc/qcom/lpass.h
> @@ -17,6 +17,28 @@
>   #define LPASS_MAX_MI2S_PORTS			(8)
>   #define LPASS_MAX_DMA_CHANNELS			(8)
>   
...

>   /* Both the CPU DAI and platform drivers will access this data */
>   struct lpass_data {
>   
> @@ -55,6 +77,10 @@ struct lpass_data {
>   	struct clk_bulk_data *clks;
>   	int num_clks;
>   
> +	/* Regmap fields of I2SCTL & DMACTL registers bitfields */
> +	struct lpaif_i2sctl *i2sctl;
> +	struct lpaif_dmactl *rd_dmactl;
> +	struct lpaif_dmactl *wr_dmactl;
>   };
>   
>   /* Vairant data per each SOC */
> @@ -72,6 +98,33 @@ struct lpass_variant {
>   	u32	wrdma_reg_stride;
>   	u32	wrdma_channels;
>   

Above two along with rddma members can be removed, these become 
redundant after adding regmap field!


> +	/* I2SCTL Register fields */
> +	struct reg_field loopback;
> +	struct reg_field spken;
> +	struct reg_field spkmode;
> +	struct reg_field spkmono;
> +	struct reg_field micen;
> +	struct reg_field micmode;
> +	struct reg_field micmono;
> +	struct reg_field wssrc;
> +	struct reg_field bitwidth;
> +
> +	/* RD_DMA Register fields */
> +	struct reg_field rdma_bursten;
> +	struct reg_field rdma_wpscnt;
> +	struct reg_field rdma_intf;
> +	struct reg_field rdma_fifowm;
> +	struct reg_field rdma_enable;
> +	struct reg_field rdma_dyncclk;
> +
> +	/* RD_DMA Register fields */
> +	struct reg_field wrdma_bursten;
> +	struct reg_field wrdma_wpscnt;
> +	struct reg_field wrdma_intf;
> +	struct reg_field wrdma_fifowm;
> +	struct reg_field wrdma_enable;
> +	struct reg_field wrdma_dyncclk;
> +
>   	/**
>   	 * on SOCs like APQ8016 the channel control bits start
>   	 * at different offset to ipq806x
>
Rohit Kumar July 9, 2020, 9:57 a.m. UTC | #2
Thanks Srini for reviewing.

On 7/9/2020 2:56 PM, Srinivas Kandagatla wrote:
>
>
> On 08/07/2020 06:08, Rohit kumar wrote:
>> I2SCTL and DMACTL registers has different bits alignment for newer
>> LPASS variants of SC7180 soc. Use REG_FIELD_ID() to define the
>> reg_fields in platform specific file and removed shifts and mask
>> macros for such registers from header file.
>>
>> Signed-off-by: Rohit kumar <rohitkr@codeaurora.org>
>
> Thanks Rohit for doing this, this looks much better now!
> I have few minor comments..
>
>> ---
>>   sound/soc/qcom/lpass-apq8016.c   |  24 ++++++
>>   sound/soc/qcom/lpass-cpu.c       | 163 
>> +++++++++++++++++++++++----------------
>>   sound/soc/qcom/lpass-ipq806x.c   |  24 ++++++
>>   sound/soc/qcom/lpass-lpaif-reg.h | 157 
>> +++++++++++++++++++------------------
>>   sound/soc/qcom/lpass-platform.c  | 151 
>> +++++++++++++++++++++++++++---------
>>   sound/soc/qcom/lpass.h           |  53 +++++++++++++
>>   6 files changed, 398 insertions(+), 174 deletions(-)
>>
>
> index f0c7e93..f358d12 100644
>> --- a/sound/soc/qcom/lpass-cpu.c
>> +++ b/sound/soc/qcom/lpass-cpu.c
>> @@ -29,6 +29,32 @@
>>   #define LPASS_CPU_I2S_SD0_1_2_MASK    GENMASK(2, 0)
>>   #define LPASS_CPU_I2S_SD0_1_2_3_MASK    GENMASK(3, 0)
>
>
>>   static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int 
>> clk_id,
>>           unsigned int freq, int dir)
>>   {
>> @@ -79,12 +105,13 @@ static int lpass_cpu_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);
>> +    struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
>> +    unsigned int id = dai->driver->id;
>>       snd_pcm_format_t format = params_format(params);
>>       unsigned int channels = params_channels(params);
>>       unsigned int rate = params_rate(params);
>>       unsigned int mode;
>> -    unsigned int regval;
>> -    int bitwidth, ret;
>> +    int bitwidth, ret, regval;
>
> Why is this change?

Sorry, It came as part of previous patchset. regval was removed in 
patchv2  and

bitwidth variable was used to configure both clk and i2sctl register, 
which was not proper.

Added regval again. I will repost this patch without this change.

>
>>         bitwidth = snd_pcm_format_width(format);
>>       if (bitwidth < 0) {
>> @@ -92,28 +119,45 @@ static int lpass_cpu_daiops_hw_params(struct 
>> snd_pcm_substream *substream,
>>           return bitwidth;
>>       }
>>   -    regval = LPAIF_I2SCTL_LOOPBACK_DISABLE |
>> -            LPAIF_I2SCTL_WSSRC_INTERNAL;
>> +    ret = regmap_fields_write(i2sctl->loopback, id,
>> +                 LPAIF_I2SCTL_LOOPBACK_DISABLE);
>> +    if (ret) {
>> +        dev_err(dai->dev, "error updating loopback field: %d\n", ret);
>> +        return ret;
>> +    }
>> +
>> +    ret = regmap_fields_write(i2sctl->wssrc, id,
>> +                 LPAIF_I2SCTL_WSSRC_INTERNAL);
>> +    if (ret) {
>> +        dev_err(dai->dev, "error updating wssrc field: %d\n", ret);
>> +        return ret;
>> +    }
>>         switch (bitwidth) {
>>       case 16:
>> -        regval |= LPAIF_I2SCTL_BITWIDTH_16;
>> +        regval = LPAIF_I2SCTL_BITWIDTH_16;
>>           break;
>>       case 24:
>> -        regval |= LPAIF_I2SCTL_BITWIDTH_24;
>> +        regval = LPAIF_I2SCTL_BITWIDTH_24;
>>           break;
>>       case 32:
>> -        regval |= LPAIF_I2SCTL_BITWIDTH_32;
>> +        regval = LPAIF_I2SCTL_BITWIDTH_32;
>>           break;
>>       default:
>>           dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth);
>>           return -EINVAL;
>>       }
>>   +    ret = regmap_fields_write(i2sctl->bitwidth, id, regval);
>> +    if (ret) {
>> +        dev_err(dai->dev, "error updating bitwidth field: %d\n", ret);
>> +        return ret;
>> +    }
>> +
>>       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
>> -        mode = drvdata->mi2s_playback_sd_mode[dai->driver->id];
>> +        mode = drvdata->mi2s_playback_sd_mode[id];
>>       else
>> -        mode = drvdata->mi2s_capture_sd_mode[dai->driver->id];
>> +        mode = drvdata->mi2s_capture_sd_mode[id];
>>         if (!mode) {
>>           dev_err(dai->dev, "no line is assigned\n");
>> @@ -175,30 +219,34 @@ static int lpass_cpu_daiops_hw_params(struct 
>> snd_pcm_substream *substream,
>>       }
>>         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>> -        regval |= LPAIF_I2SCTL_SPKMODE(mode);
>> +        ret = regmap_fields_write(i2sctl->spkmode, id,
>> +                     LPAIF_I2SCTL_SPKMODE(mode));
>>             if (channels >= 2)
>> -            regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
>> +            ret = regmap_fields_write(i2sctl->spkmono, id,
>> +                         LPAIF_I2SCTL_SPKMONO_STEREO);
>>           else
>> -            regval |= LPAIF_I2SCTL_SPKMONO_MONO;
>> +            ret = regmap_fields_write(i2sctl->spkmono, id,
>> +                         LPAIF_I2SCTL_SPKMONO_MONO);
>>       } else {
>> -        regval |= LPAIF_I2SCTL_MICMODE(mode);
>> +        ret = regmap_fields_write(i2sctl->micmode, id,
>> +                     LPAIF_I2SCTL_MICMODE(mode));
>>             if (channels >= 2)
>> -            regval |= LPAIF_I2SCTL_MICMONO_STEREO;
>> +            ret = regmap_fields_write(i2sctl->micmono, id,
>> +                         LPAIF_I2SCTL_MICMONO_STEREO);
>>           else
>> -            regval |= LPAIF_I2SCTL_MICMONO_MONO;
>> +            ret = regmap_fields_write(i2sctl->micmono, id,
>> +                         LPAIF_I2SCTL_MICMONO_MONO);
>>       }
>>   -    ret = regmap_write(drvdata->lpaif_map,
>> -               LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>> -               regval);
>>       if (ret) {
>> -        dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
>> +        dev_err(dai->dev, "error writing to i2sctl channels mode: 
>> %d\n",
>> +            ret);
>>           return ret;
>>       }
>>   -    ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
>> +    ret = clk_set_rate(drvdata->mi2s_bit_clk[id],
>>                  rate * bitwidth * 2);
>>       if (ret) {
>>           dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n",
>> @@ -209,41 +257,24 @@ static int lpass_cpu_daiops_hw_params(struct 
>> snd_pcm_substream *substream,
>>       return 0;
>>   }
>>   -static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream 
>> *substream,
>> -        struct snd_soc_dai *dai)
>> -{
>> -    struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>> -    int ret;
>> -
>> -    ret = regmap_write(drvdata->lpaif_map,
>> -               LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>> -               0);
>> -    if (ret)
>> -        dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
>> -
>> -    return ret;
>> -}
>
> Any particular reason why this function remove

This was causing issue in playback/capture concurrency. It sets I2SCTL 
register value to 0

when usecase ends. However, playback/capture specific bits are already 
cleared during trigger() stop

function. So, this is not needed.

>> -
>>   static int lpass_cpu_daiops_prepare(struct snd_pcm_substream 
>> *substream,
>>           struct snd_soc_dai *dai)
>>   {
>>       struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>> +    struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
>> +    unsigned int id = dai->driver->id;
>>       int ret;
>> -    unsigned int val, mask;
>>         if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
>> -        val = LPAIF_I2SCTL_SPKEN_ENABLE;
>> -        mask = LPAIF_I2SCTL_SPKEN_MASK;
>> -    } else  {
>> -        val = LPAIF_I2SCTL_MICEN_ENABLE;
>> -        mask = LPAIF_I2SCTL_MICEN_MASK;
>> +        ret = regmap_fields_write(i2sctl->spken, id,
>> +                     LPAIF_I2SCTL_SPKEN_ENABLE);
>> +    } else {
>> +        ret = regmap_fields_write(i2sctl->micen, id,
>> +                     LPAIF_I2SCTL_MICEN_ENABLE);
>>       }
>>   -    ret = regmap_update_bits(drvdata->lpaif_map,
>> -            LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>> -            mask, val);
>>       if (ret)
>> -        dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
>> +        dev_err(dai->dev, "error writing to i2sctl enable: %d\n", ret);
>>         return ret;
>>   }
> ...
>> @@ -304,7 +326,6 @@ const struct snd_soc_dai_ops 
>> asoc_qcom_lpass_cpu_dai_ops = {
>>       .startup    = lpass_cpu_daiops_startup,
>>       .shutdown    = lpass_cpu_daiops_shutdown,
>>       .hw_params    = lpass_cpu_daiops_hw_params,
>> -    .hw_free    = lpass_cpu_daiops_hw_free,
>>       .prepare    = lpass_cpu_daiops_prepare,
>>       .trigger    = lpass_cpu_daiops_trigger,
>>   };
>> @@ -599,6 +620,18 @@ int asoc_qcom_lpass_cpu_platform_probe(struct 
>> platform_device *pdev)
>>           }
>>       }
>>   +    /* Allocation for i2sctl regmap fields */
>> +    drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct 
>> lpaif_i2sctl),
>> +                    GFP_KERNEL);
>> +
>> +    /* Initialize bitfields for dai I2SCTL register */
>> +    ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
>> +                        drvdata->lpaif_map);
>> +    if (ret) {
>> +        dev_err(dev, "error init i2sctl field: %d\n", ret);
>> +        return ret;
>> +    }
>> +
>>       ret = devm_snd_soc_register_component(dev,
>>                             &lpass_cpu_comp_driver,
>>                             variant->dai_driver,
>
>> diff --git a/sound/soc/qcom/lpass-lpaif-reg.h 
>> b/sound/soc/qcom/lpass-lpaif-reg.h
>> index 72a3e2f..5258e60 100644
>> --- a/sound/soc/qcom/lpass-lpaif-reg.h
>> +++ b/sound/soc/qcom/lpass-lpaif-reg.h
>> @@ -12,15 +12,12 @@
> ...
>>   #endif /* __LPASS_LPAIF_REG_H__ */
>> diff --git a/sound/soc/qcom/lpass-platform.c 
>> b/sound/soc/qcom/lpass-platform.c
>> index 34f7fd1..445ca193 100644
>> --- a/sound/soc/qcom/lpass-platform.c
>> +++ b/sound/soc/qcom/lpass-platform.c
>> @@ -50,6 +50,53 @@ static const struct snd_pcm_hardware 
>> lpass_platform_pcm_hardware = {
>>       .fifo_size        =    0,
>>   };
> ...
>>   static int lpass_platform_pcmops_open(struct snd_soc_component 
>> *component,
>>                         struct snd_pcm_substream *substream)
>>   {
>> @@ -59,9 +106,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;
>>   -    data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
>> +    data = kzalloc(sizeof(*data), GFP_KERNEL);
>
> Does this change belong in this patch?


As part of this change, I fixed memory leak too by adding kfree() in close()

However, this was causing issue as memory was allocated using 
devm_kzalloc().

Should I move it to different patch?

>
>>       if (!data)
>>           return -ENOMEM;
>>   @@ -111,13 +158,13 @@ static int lpass_platform_pcmops_close(struct 
>> snd_soc_component *component,
>>       struct snd_pcm_runtime *runtime = substream->runtime;
>>       struct lpass_data *drvdata = 
>> snd_soc_component_get_drvdata(component);
>>       struct lpass_variant *v = drvdata->variant;
>> -    struct lpass_pcm_data *data;
>> +    struct lpass_pcm_data *data = runtime->private_data;
>>   -    data = runtime->private_data;
>>       drvdata->substream[data->dma_ch] = NULL;
>>       if (v->free_dma_channel)
>>           v->free_dma_channel(drvdata, data->dma_ch);
>>   +    kfree(data);
>>       return 0;
>>   }
>>           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 450020e..4294ec2 100644
>> --- a/sound/soc/qcom/lpass.h
>> +++ b/sound/soc/qcom/lpass.h
>> @@ -17,6 +17,28 @@
>>   #define LPASS_MAX_MI2S_PORTS            (8)
>>   #define LPASS_MAX_DMA_CHANNELS            (8)
> ...
>
>>   /* Both the CPU DAI and platform drivers will access this data */
>>   struct lpass_data {
>>   @@ -55,6 +77,10 @@ struct lpass_data {
>>       struct clk_bulk_data *clks;
>>       int num_clks;
>>   +    /* Regmap fields of I2SCTL & DMACTL registers bitfields */
>> +    struct lpaif_i2sctl *i2sctl;
>> +    struct lpaif_dmactl *rd_dmactl;
>> +    struct lpaif_dmactl *wr_dmactl;
>>   };
>>     /* Vairant data per each SOC */
>> @@ -72,6 +98,33 @@ struct lpass_variant {
>>       u32    wrdma_reg_stride;
>>       u32    wrdma_channels;
>
> Above two along with rddma members can be removed, these become 
> redundant after adding regmap field!
>
wrdma_channels is used in alloc_dma_channel() to get the channel id.

Also, both are used for other DMA registers such as LPAIF_RDMABASE_REG,

LPAIF_RDMABUFF_REG, LPAIF_RDMACURR_REG, etc.

>
>> +    /* I2SCTL Register fields */
>> +    struct reg_field loopback;
>> +    struct reg_field spken;
>> +    struct reg_field spkmode;
>> +    struct reg_field spkmono;
>> +    struct reg_field micen;
>> +    struct reg_field micmode;
>> +    struct reg_field micmono;
>> +    struct reg_field wssrc;
>> +    struct reg_field bitwidth;
>> +
>> +    /* RD_DMA Register fields */
>> +    struct reg_field rdma_bursten;
>> +    struct reg_field rdma_wpscnt;
>> +    struct reg_field rdma_intf;
>> +    struct reg_field rdma_fifowm;
>> +    struct reg_field rdma_enable;
>> +    struct reg_field rdma_dyncclk;
>> +
>> +    /* RD_DMA Register fields */
>> +    struct reg_field wrdma_bursten;
>> +    struct reg_field wrdma_wpscnt;
>> +    struct reg_field wrdma_intf;
>> +    struct reg_field wrdma_fifowm;
>> +    struct reg_field wrdma_enable;
>> +    struct reg_field wrdma_dyncclk;
>> +
>>       /**
>>        * on SOCs like APQ8016 the channel control bits start
>>        * at different offset to ipq806x
>>
Thanks,

Rohit
Srinivas Kandagatla July 9, 2020, 10:06 a.m. UTC | #3
On 09/07/2020 10:57, Rohit Kumar wrote:
> Thanks Srini for reviewing.
> 
> On 7/9/2020 2:56 PM, Srinivas Kandagatla wrote:
>>
>>
>> On 08/07/2020 06:08, Rohit kumar wrote:
>>> I2SCTL and DMACTL registers has different bits alignment for newer
>>> LPASS variants of SC7180 soc. Use REG_FIELD_ID() to define the
>>> reg_fields in platform specific file and removed shifts and mask
>>> macros for such registers from header file.
>>>
>>> Signed-off-by: Rohit kumar <rohitkr@codeaurora.org>
>>
>> Thanks Rohit for doing this, this looks much better now!
>> I have few minor comments..
>>
>>> ---
>>>   sound/soc/qcom/lpass-apq8016.c   |  24 ++++++
>>>   sound/soc/qcom/lpass-cpu.c       | 163 
>>> +++++++++++++++++++++++----------------
>>>   sound/soc/qcom/lpass-ipq806x.c   |  24 ++++++
>>>   sound/soc/qcom/lpass-lpaif-reg.h | 157 
>>> +++++++++++++++++++------------------
>>>   sound/soc/qcom/lpass-platform.c  | 151 
>>> +++++++++++++++++++++++++++---------
>>>   sound/soc/qcom/lpass.h           |  53 +++++++++++++
>>>   6 files changed, 398 insertions(+), 174 deletions(-)
>>>
>>
>> index f0c7e93..f358d12 100644
>>> --- a/sound/soc/qcom/lpass-cpu.c
>>> +++ b/sound/soc/qcom/lpass-cpu.c
>>> @@ -29,6 +29,32 @@
>>>   #define LPASS_CPU_I2S_SD0_1_2_MASK    GENMASK(2, 0)
>>>   #define LPASS_CPU_I2S_SD0_1_2_3_MASK    GENMASK(3, 0)
>>
>>
>>>   }
>>>   -static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream 
>>> *substream,
>>> -        struct snd_soc_dai *dai)
>>> -{
>>> -    struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>>> -    int ret;
>>> -
>>> -    ret = regmap_write(drvdata->lpaif_map,
>>> -               LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>>> -               0);
>>> -    if (ret)
>>> -        dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
>>> -
>>> -    return ret;
>>> -}
>>
>> Any particular reason why this function remove
> 
> This was causing issue in playback/capture concurrency. It sets I2SCTL 
> register value to 0
> 
> when usecase ends. However, playback/capture specific bits are already 
> cleared during trigger() stop
> 
> function. So, this is not needed.

This should be sent as separate fix with fixes tag!

> 
>
>>
>>> diff --git a/sound/soc/qcom/lpass-lpaif-reg.h 
>>> b/sound/soc/qcom/lpass-lpaif-reg.h
>>> index 72a3e2f..5258e60 100644
>>> --- a/sound/soc/qcom/lpass-lpaif-reg.h
>>> +++ b/sound/soc/qcom/lpass-lpaif-reg.h
>>> @@ -12,15 +12,12 @@
>> ...
>>>   #endif /* __LPASS_LPAIF_REG_H__ */
>>> diff --git a/sound/soc/qcom/lpass-platform.c 
>>> b/sound/soc/qcom/lpass-platform.c
>>> index 34f7fd1..445ca193 100644
>>> --- a/sound/soc/qcom/lpass-platform.c
>>> +++ b/sound/soc/qcom/lpass-platform.c
>>> @@ -50,6 +50,53 @@ static const struct snd_pcm_hardware 
>>> lpass_platform_pcm_hardware = {
>>>       .fifo_size        =    0,
>>>   };
>> ...
>>>   static int lpass_platform_pcmops_open(struct snd_soc_component 
>>> *component,
>>>                         struct snd_pcm_substream *substream)
>>>   {
>>> @@ -59,9 +106,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;
>>>   -    data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
>>> +    data = kzalloc(sizeof(*data), GFP_KERNEL);
>>
>> Does this change belong in this patch?
> 
> 
> As part of this change, I fixed memory leak too by adding kfree() in 
> close()
> 
> However, this was causing issue as memory was allocated using 
> devm_kzalloc().
> 
> Should I move it to different patch?

That would be the right thing to do, can also add fixes tag!


> 
>>
>>>       if (!data)
>>>           return -ENOMEM;
>>>   @@ -111,13 +158,13 @@ static int lpass_platform_pcmops_close(struct 
>>> snd_soc_component *component,
>>>       struct snd_pcm_runtime *runtime = substream->runtime;
>>>       struct lpass_data *drvdata = 
>>> snd_soc_component_get_drvdata(component);
>>>       struct lpass_variant *v = drvdata->variant;

>>
>> Above two along with rddma members can be removed, these become 
>> redundant after adding regmap field!
>>
> wrdma_channels is used in alloc_dma_channel() to get the channel id.
> 
> Also, both are used for other DMA registers such as LPAIF_RDMABASE_REG,
> 
> LPAIF_RDMABUFF_REG, LPAIF_RDMACURR_REG, etc.
> 
Ah I see we are still using this in lpass_cpu_regmap_writeable!
ignore my previous comments about removing them!

--srini
Rohit Kumar July 9, 2020, 10:14 a.m. UTC | #4
On 7/9/2020 3:36 PM, Srinivas Kandagatla wrote:
>
>
> On 09/07/2020 10:57, Rohit Kumar wrote:
>> Thanks Srini for reviewing.
>>
>> On 7/9/2020 2:56 PM, Srinivas Kandagatla wrote:
>>>
>>>
>>> On 08/07/2020 06:08, Rohit kumar wrote:
>>>> I2SCTL and DMACTL registers has different bits alignment for newer
>>>> LPASS variants of SC7180 soc. Use REG_FIELD_ID() to define the
>>>> reg_fields in platform specific file and removed shifts and mask
>>>> macros for such registers from header file.
>>>>
>>>> Signed-off-by: Rohit kumar <rohitkr@codeaurora.org>
>>>
>>> Thanks Rohit for doing this, this looks much better now!
>>> I have few minor comments..
>>>
>>>> ---
>>>>   sound/soc/qcom/lpass-apq8016.c   |  24 ++++++
>>>>   sound/soc/qcom/lpass-cpu.c       | 163 
>>>> +++++++++++++++++++++++----------------
>>>>   sound/soc/qcom/lpass-ipq806x.c   |  24 ++++++
>>>>   sound/soc/qcom/lpass-lpaif-reg.h | 157 
>>>> +++++++++++++++++++------------------
>>>>   sound/soc/qcom/lpass-platform.c  | 151 
>>>> +++++++++++++++++++++++++++---------
>>>>   sound/soc/qcom/lpass.h           |  53 +++++++++++++
>>>>   6 files changed, 398 insertions(+), 174 deletions(-)
>>>>
>>>
>>> index f0c7e93..f358d12 100644
>>>> --- a/sound/soc/qcom/lpass-cpu.c
>>>> +++ b/sound/soc/qcom/lpass-cpu.c
>>>> @@ -29,6 +29,32 @@
>>>>   #define LPASS_CPU_I2S_SD0_1_2_MASK    GENMASK(2, 0)
>>>>   #define LPASS_CPU_I2S_SD0_1_2_3_MASK    GENMASK(3, 0)
>>>
>>>
>>>>   }
>>>>   -static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream 
>>>> *substream,
>>>> -        struct snd_soc_dai *dai)
>>>> -{
>>>> -    struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
>>>> -    int ret;
>>>> -
>>>> -    ret = regmap_write(drvdata->lpaif_map,
>>>> -               LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
>>>> -               0);
>>>> -    if (ret)
>>>> -        dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
>>>> -
>>>> -    return ret;
>>>> -}
>>>
>>> Any particular reason why this function remove
>>
>> This was causing issue in playback/capture concurrency. It sets 
>> I2SCTL register value to 0
>>
>> when usecase ends. However, playback/capture specific bits are 
>> already cleared during trigger() stop
>>
>> function. So, this is not needed.
>
> This should be sent as separate fix with fixes tag!
Ok. Will create separate patch with fixes tag and post.
>
>>
>>
>>>
>>>> diff --git a/sound/soc/qcom/lpass-lpaif-reg.h 
>>>> b/sound/soc/qcom/lpass-lpaif-reg.h
>>>> index 72a3e2f..5258e60 100644
>>>> --- a/sound/soc/qcom/lpass-lpaif-reg.h
>>>> +++ b/sound/soc/qcom/lpass-lpaif-reg.h
>>>> @@ -12,15 +12,12 @@
>>> ...
>>>>   #endif /* __LPASS_LPAIF_REG_H__ */
>>>> diff --git a/sound/soc/qcom/lpass-platform.c 
>>>> b/sound/soc/qcom/lpass-platform.c
>>>> index 34f7fd1..445ca193 100644
>>>> --- a/sound/soc/qcom/lpass-platform.c
>>>> +++ b/sound/soc/qcom/lpass-platform.c
>>>> @@ -50,6 +50,53 @@ static const struct snd_pcm_hardware 
>>>> lpass_platform_pcm_hardware = {
>>>>       .fifo_size        =    0,
>>>>   };
>>> ...
>>>>   static int lpass_platform_pcmops_open(struct snd_soc_component 
>>>> *component,
>>>>                         struct snd_pcm_substream *substream)
>>>>   {
>>>> @@ -59,9 +106,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;
>>>>   -    data = devm_kzalloc(soc_runtime->dev, sizeof(*data), 
>>>> GFP_KERNEL);
>>>> +    data = kzalloc(sizeof(*data), GFP_KERNEL);
>>>
>>> Does this change belong in this patch?
>>
>>
>> As part of this change, I fixed memory leak too by adding kfree() in 
>> close()
>>
>> However, this was causing issue as memory was allocated using 
>> devm_kzalloc().
>>
>> Should I move it to different patch?
>
> That would be the right thing to do, can also add fixes tag!


Sure, Will do that in next spin.

>
>
>>
>>>
>>>>       if (!data)
>>>>           return -ENOMEM;
>>>>   @@ -111,13 +158,13 @@ static int 
>>>> lpass_platform_pcmops_close(struct snd_soc_component *component,
>>>>       struct snd_pcm_runtime *runtime = substream->runtime;
>>>>       struct lpass_data *drvdata = 
>>>> snd_soc_component_get_drvdata(component);
>>>>       struct lpass_variant *v = drvdata->variant;
>
>>>
>>> Above two along with rddma members can be removed, these become 
>>> redundant after adding regmap field!
>>>
>> wrdma_channels is used in alloc_dma_channel() to get the channel id.
>>
>> Also, both are used for other DMA registers such as LPAIF_RDMABASE_REG,
>>
>> LPAIF_RDMABUFF_REG, LPAIF_RDMACURR_REG, etc.
>>
> Ah I see we are still using this in lpass_cpu_regmap_writeable!
> ignore my previous comments about removing them!
>
> --srini

Patch
diff mbox series

diff --git a/sound/soc/qcom/lpass-apq8016.c b/sound/soc/qcom/lpass-apq8016.c
index fe4c258..dd9e3dd 100644
--- a/sound/soc/qcom/lpass-apq8016.c
+++ b/sound/soc/qcom/lpass-apq8016.c
@@ -240,6 +240,30 @@  static struct lpass_variant apq8016_data = {
 	.wrdma_reg_stride	= 0x1000,
 	.wrdma_channel_start	= 5,
 	.wrdma_channels		= 2,
+	.loopback		= REG_FIELD_ID(0x1000, 15, 15, 4, 0x1000),
+	.spken			= REG_FIELD_ID(0x1000, 14, 14, 4, 0x1000),
+	.spkmode		= REG_FIELD_ID(0x1000, 10, 13, 4, 0x1000),
+	.spkmono		= REG_FIELD_ID(0x1000, 9, 9, 4, 0x1000),
+	.micen			= REG_FIELD_ID(0x1000, 8, 8, 4, 0x1000),
+	.micmode		= REG_FIELD_ID(0x1000, 4, 7, 4, 0x1000),
+	.micmono		= REG_FIELD_ID(0x1000, 3, 3, 4, 0x1000),
+	.wssrc			= REG_FIELD_ID(0x1000, 2, 2, 4, 0x1000),
+	.bitwidth		= REG_FIELD_ID(0x1000, 0, 0, 4, 0x1000),
+
+	.rdma_dyncclk		= REG_FIELD_ID(0x8400, 12, 12, 2, 0x1000),
+	.rdma_bursten		= REG_FIELD_ID(0x8400, 11, 11, 2, 0x1000),
+	.rdma_wpscnt		= REG_FIELD_ID(0x8400, 8, 10, 2, 0x1000),
+	.rdma_intf		= REG_FIELD_ID(0x8400, 4, 7, 2, 0x1000),
+	.rdma_fifowm		= REG_FIELD_ID(0x8400, 1, 3, 2, 0x1000),
+	.rdma_enable		= REG_FIELD_ID(0x8400, 0, 0, 2, 0x1000),
+
+	.wrdma_dyncclk		= REG_FIELD_ID(0xB000, 12, 12, 2, 0x1000),
+	.wrdma_bursten		= REG_FIELD_ID(0xB000, 11, 11, 2, 0x1000),
+	.wrdma_wpscnt		= REG_FIELD_ID(0xB000, 8, 10, 2, 0x1000),
+	.wrdma_intf		= REG_FIELD_ID(0xB000, 4, 7, 2, 0x1000),
+	.wrdma_fifowm		= REG_FIELD_ID(0xB000, 1, 3, 2, 0x1000),
+	.wrdma_enable		= REG_FIELD_ID(0xB000, 0, 0, 2, 0x1000),
+
 	.clk_name		= (const char*[]) {
 				   "pcnoc-mport-clk",
 				   "pcnoc-sway-clk",
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index f0c7e93..f358d12 100644
--- a/sound/soc/qcom/lpass-cpu.c
+++ b/sound/soc/qcom/lpass-cpu.c
@@ -29,6 +29,32 @@ 
 #define LPASS_CPU_I2S_SD0_1_2_MASK	GENMASK(2, 0)
 #define LPASS_CPU_I2S_SD0_1_2_3_MASK	GENMASK(3, 0)
 
+static int lpass_cpu_init_i2sctl_bitfields(struct device *dev,
+			struct lpaif_i2sctl *i2sctl, struct regmap *map)
+{
+	struct lpass_data *drvdata = dev_get_drvdata(dev);
+	struct lpass_variant *v = drvdata->variant;
+
+	i2sctl->loopback = devm_regmap_field_alloc(dev, map, v->loopback);
+	i2sctl->spken = devm_regmap_field_alloc(dev, map, v->spken);
+	i2sctl->spkmode = devm_regmap_field_alloc(dev, map, v->spkmode);
+	i2sctl->spkmono = devm_regmap_field_alloc(dev, map, v->spkmono);
+	i2sctl->micen = devm_regmap_field_alloc(dev, map, v->micen);
+	i2sctl->micmode = devm_regmap_field_alloc(dev, map, v->micmode);
+	i2sctl->micmono = devm_regmap_field_alloc(dev, map, v->micmono);
+	i2sctl->wssrc = devm_regmap_field_alloc(dev, map, v->wssrc);
+	i2sctl->bitwidth = devm_regmap_field_alloc(dev, map, v->bitwidth);
+
+	if (IS_ERR(i2sctl->loopback) || IS_ERR(i2sctl->spken) ||
+	    IS_ERR(i2sctl->spkmode) || IS_ERR(i2sctl->spkmono) ||
+	    IS_ERR(i2sctl->micen) || IS_ERR(i2sctl->micmode) ||
+	    IS_ERR(i2sctl->micmono) || IS_ERR(i2sctl->wssrc) ||
+	    IS_ERR(i2sctl->bitwidth))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
 		unsigned int freq, int dir)
 {
@@ -79,12 +105,13 @@  static int lpass_cpu_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);
+	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
+	unsigned int id = dai->driver->id;
 	snd_pcm_format_t format = params_format(params);
 	unsigned int channels = params_channels(params);
 	unsigned int rate = params_rate(params);
 	unsigned int mode;
-	unsigned int regval;
-	int bitwidth, ret;
+	int bitwidth, ret, regval;
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
@@ -92,28 +119,45 @@  static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 		return bitwidth;
 	}
 
-	regval = LPAIF_I2SCTL_LOOPBACK_DISABLE |
-			LPAIF_I2SCTL_WSSRC_INTERNAL;
+	ret = regmap_fields_write(i2sctl->loopback, id,
+				 LPAIF_I2SCTL_LOOPBACK_DISABLE);
+	if (ret) {
+		dev_err(dai->dev, "error updating loopback field: %d\n", ret);
+		return ret;
+	}
+
+	ret = regmap_fields_write(i2sctl->wssrc, id,
+				 LPAIF_I2SCTL_WSSRC_INTERNAL);
+	if (ret) {
+		dev_err(dai->dev, "error updating wssrc field: %d\n", ret);
+		return ret;
+	}
 
 	switch (bitwidth) {
 	case 16:
-		regval |= LPAIF_I2SCTL_BITWIDTH_16;
+		regval = LPAIF_I2SCTL_BITWIDTH_16;
 		break;
 	case 24:
-		regval |= LPAIF_I2SCTL_BITWIDTH_24;
+		regval = LPAIF_I2SCTL_BITWIDTH_24;
 		break;
 	case 32:
-		regval |= LPAIF_I2SCTL_BITWIDTH_32;
+		regval = LPAIF_I2SCTL_BITWIDTH_32;
 		break;
 	default:
 		dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth);
 		return -EINVAL;
 	}
 
+	ret = regmap_fields_write(i2sctl->bitwidth, id, regval);
+	if (ret) {
+		dev_err(dai->dev, "error updating bitwidth field: %d\n", ret);
+		return ret;
+	}
+
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
-		mode = drvdata->mi2s_playback_sd_mode[dai->driver->id];
+		mode = drvdata->mi2s_playback_sd_mode[id];
 	else
-		mode = drvdata->mi2s_capture_sd_mode[dai->driver->id];
+		mode = drvdata->mi2s_capture_sd_mode[id];
 
 	if (!mode) {
 		dev_err(dai->dev, "no line is assigned\n");
@@ -175,30 +219,34 @@  static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	}
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		regval |= LPAIF_I2SCTL_SPKMODE(mode);
+		ret = regmap_fields_write(i2sctl->spkmode, id,
+					 LPAIF_I2SCTL_SPKMODE(mode));
 
 		if (channels >= 2)
-			regval |= LPAIF_I2SCTL_SPKMONO_STEREO;
+			ret = regmap_fields_write(i2sctl->spkmono, id,
+						 LPAIF_I2SCTL_SPKMONO_STEREO);
 		else
-			regval |= LPAIF_I2SCTL_SPKMONO_MONO;
+			ret = regmap_fields_write(i2sctl->spkmono, id,
+						 LPAIF_I2SCTL_SPKMONO_MONO);
 	} else {
-		regval |= LPAIF_I2SCTL_MICMODE(mode);
+		ret = regmap_fields_write(i2sctl->micmode, id,
+					 LPAIF_I2SCTL_MICMODE(mode));
 
 		if (channels >= 2)
-			regval |= LPAIF_I2SCTL_MICMONO_STEREO;
+			ret = regmap_fields_write(i2sctl->micmono, id,
+						 LPAIF_I2SCTL_MICMONO_STEREO);
 		else
-			regval |= LPAIF_I2SCTL_MICMONO_MONO;
+			ret = regmap_fields_write(i2sctl->micmono, id,
+						 LPAIF_I2SCTL_MICMONO_MONO);
 	}
 
-	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
-			   regval);
 	if (ret) {
-		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
+		dev_err(dai->dev, "error writing to i2sctl channels mode: %d\n",
+			ret);
 		return ret;
 	}
 
-	ret = clk_set_rate(drvdata->mi2s_bit_clk[dai->driver->id],
+	ret = clk_set_rate(drvdata->mi2s_bit_clk[id],
 			   rate * bitwidth * 2);
 	if (ret) {
 		dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n",
@@ -209,41 +257,24 @@  static int lpass_cpu_daiops_hw_params(struct snd_pcm_substream *substream,
 	return 0;
 }
 
-static int lpass_cpu_daiops_hw_free(struct snd_pcm_substream *substream,
-		struct snd_soc_dai *dai)
-{
-	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
-	int ret;
-
-	ret = regmap_write(drvdata->lpaif_map,
-			   LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
-			   0);
-	if (ret)
-		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
-
-	return ret;
-}
-
 static int lpass_cpu_daiops_prepare(struct snd_pcm_substream *substream,
 		struct snd_soc_dai *dai)
 {
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
+	unsigned int id = dai->driver->id;
 	int ret;
-	unsigned int val, mask;
 
 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-		val = LPAIF_I2SCTL_SPKEN_ENABLE;
-		mask = LPAIF_I2SCTL_SPKEN_MASK;
-	} else  {
-		val = LPAIF_I2SCTL_MICEN_ENABLE;
-		mask = LPAIF_I2SCTL_MICEN_MASK;
+		ret = regmap_fields_write(i2sctl->spken, id,
+					 LPAIF_I2SCTL_SPKEN_ENABLE);
+	} else {
+		ret = regmap_fields_write(i2sctl->micen, id,
+					 LPAIF_I2SCTL_MICEN_ENABLE);
 	}
 
-	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
-			mask, val);
 	if (ret)
-		dev_err(dai->dev, "error writing to i2sctl reg: %d\n", ret);
+		dev_err(dai->dev, "error writing to i2sctl enable: %d\n", ret);
 
 	return ret;
 }
@@ -252,25 +283,21 @@  static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 		int cmd, struct snd_soc_dai *dai)
 {
 	struct lpass_data *drvdata = snd_soc_dai_get_drvdata(dai);
+	struct lpaif_i2sctl *i2sctl = drvdata->i2sctl;
+	unsigned int id = dai->driver->id;
 	int ret = -EINVAL;
-	unsigned int val, mask;
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			val = LPAIF_I2SCTL_SPKEN_ENABLE;
-			mask = LPAIF_I2SCTL_SPKEN_MASK;
+			ret = regmap_fields_write(i2sctl->spken, id,
+						 LPAIF_I2SCTL_SPKEN_ENABLE);
 		} else  {
-			val = LPAIF_I2SCTL_MICEN_ENABLE;
-			mask = LPAIF_I2SCTL_MICEN_MASK;
+			ret = regmap_fields_write(i2sctl->micen, id,
+						 LPAIF_I2SCTL_MICEN_ENABLE);
 		}
-
-		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(drvdata->variant,
-						dai->driver->id),
-				mask, val);
 		if (ret)
 			dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
 				ret);
@@ -279,17 +306,12 @@  static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-			val = LPAIF_I2SCTL_SPKEN_DISABLE;
-			mask = LPAIF_I2SCTL_SPKEN_MASK;
+			ret = regmap_fields_write(i2sctl->spken, id,
+						 LPAIF_I2SCTL_SPKEN_DISABLE);
 		} else  {
-			val = LPAIF_I2SCTL_MICEN_DISABLE;
-			mask = LPAIF_I2SCTL_MICEN_MASK;
+			ret = regmap_fields_write(i2sctl->micen, id,
+						 LPAIF_I2SCTL_MICEN_DISABLE);
 		}
-
-		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_I2SCTL_REG(drvdata->variant,
-						dai->driver->id),
-				mask, val);
 		if (ret)
 			dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
 				ret);
@@ -304,7 +326,6 @@  const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = {
 	.startup	= lpass_cpu_daiops_startup,
 	.shutdown	= lpass_cpu_daiops_shutdown,
 	.hw_params	= lpass_cpu_daiops_hw_params,
-	.hw_free	= lpass_cpu_daiops_hw_free,
 	.prepare	= lpass_cpu_daiops_prepare,
 	.trigger	= lpass_cpu_daiops_trigger,
 };
@@ -599,6 +620,18 @@  int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
 		}
 	}
 
+	/* Allocation for i2sctl regmap fields */
+	drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
+					GFP_KERNEL);
+
+	/* Initialize bitfields for dai I2SCTL register */
+	ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
+						drvdata->lpaif_map);
+	if (ret) {
+		dev_err(dev, "error init i2sctl field: %d\n", ret);
+		return ret;
+	}
+
 	ret = devm_snd_soc_register_component(dev,
 					      &lpass_cpu_comp_driver,
 					      variant->dai_driver,
diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c
index b7c0586..72f09b3 100644
--- a/sound/soc/qcom/lpass-ipq806x.c
+++ b/sound/soc/qcom/lpass-ipq806x.c
@@ -123,6 +123,30 @@  static struct lpass_variant ipq806x_data = {
 	.wrdma_reg_stride	= 0x1000,
 	.wrdma_channel_start	= 5,
 	.wrdma_channels		= 4,
+	.loopback		= REG_FIELD_ID(0x0010, 15, 15, 5, 0x4),
+	.spken			= REG_FIELD_ID(0x0010, 14, 14, 5, 0x4),
+	.spkmode		= REG_FIELD_ID(0x0010, 10, 13, 5, 0x4),
+	.spkmono		= REG_FIELD_ID(0x0010, 9, 9, 5, 0x4),
+	.micen			= REG_FIELD_ID(0x0010, 8, 8, 5, 0x4),
+	.micmode		= REG_FIELD_ID(0x0010, 4, 7, 5, 0x4),
+	.micmono		= REG_FIELD_ID(0x0010, 3, 3, 5, 0x4),
+	.wssrc			= REG_FIELD_ID(0x0010, 2, 2, 5, 0x4),
+	.bitwidth		= REG_FIELD_ID(0x0010, 0, 0, 5, 0x4),
+
+	.rdma_dyncclk		= REG_FIELD_ID(0x6000, 12, 12, 4, 0x1000),
+	.rdma_bursten		= REG_FIELD_ID(0x6000, 11, 11, 4, 0x1000),
+	.rdma_wpscnt		= REG_FIELD_ID(0x6000, 8, 10, 4, 0x1000),
+	.rdma_intf		= REG_FIELD_ID(0x6000, 4, 7, 4, 0x1000),
+	.rdma_fifowm		= REG_FIELD_ID(0x6000, 1, 3, 4, 0x1000),
+	.rdma_enable		= REG_FIELD_ID(0x6000, 0, 0, 4, 0x1000),
+
+	.wrdma_dyncclk		= REG_FIELD_ID(0xB000, 12, 12, 4, 0x1000),
+	.wrdma_bursten		= REG_FIELD_ID(0xB000, 11, 11, 4, 0x1000),
+	.wrdma_wpscnt		= REG_FIELD_ID(0xB000, 8, 10, 4, 0x1000),
+	.wrdma_intf		= REG_FIELD_ID(0xB000, 4, 7, 4, 0x1000),
+	.wrdma_fifowm		= REG_FIELD_ID(0xB000, 1, 3, 4, 0x1000),
+	.wrdma_enable		= REG_FIELD_ID(0xB000, 0, 0, 4, 0x1000),
+
 	.dai_driver		= &ipq806x_lpass_cpu_dai_driver,
 	.num_dai		= 1,
 	.dai_osr_clk_names	= (const char *[]) {
diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h
index 72a3e2f..5258e60 100644
--- a/sound/soc/qcom/lpass-lpaif-reg.h
+++ b/sound/soc/qcom/lpass-lpaif-reg.h
@@ -12,15 +12,12 @@ 
 	(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
 
 #define LPAIF_I2SCTL_REG(v, port)	LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port))
-#define LPAIF_I2SCTL_LOOPBACK_MASK	0x8000
-#define LPAIF_I2SCTL_LOOPBACK_SHIFT	15
-#define LPAIF_I2SCTL_LOOPBACK_DISABLE	(0 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
-#define LPAIF_I2SCTL_LOOPBACK_ENABLE	(1 << LPAIF_I2SCTL_LOOPBACK_SHIFT)
 
-#define LPAIF_I2SCTL_SPKEN_MASK		0x4000
-#define LPAIF_I2SCTL_SPKEN_SHIFT	14
-#define LPAIF_I2SCTL_SPKEN_DISABLE	(0 << LPAIF_I2SCTL_SPKEN_SHIFT)
-#define LPAIF_I2SCTL_SPKEN_ENABLE	(1 << LPAIF_I2SCTL_SPKEN_SHIFT)
+#define LPAIF_I2SCTL_LOOPBACK_DISABLE	0
+#define LPAIF_I2SCTL_LOOPBACK_ENABLE	1
+
+#define LPAIF_I2SCTL_SPKEN_DISABLE	0
+#define LPAIF_I2SCTL_SPKEN_ENABLE	1
 
 #define LPAIF_I2SCTL_MODE_NONE		0
 #define LPAIF_I2SCTL_MODE_SD0		1
@@ -31,40 +28,37 @@ 
 #define LPAIF_I2SCTL_MODE_QUAD23	6
 #define LPAIF_I2SCTL_MODE_6CH		7
 #define LPAIF_I2SCTL_MODE_8CH		8
+#define LPAIF_I2SCTL_MODE_10CH		9
+#define LPAIF_I2SCTL_MODE_12CH		10
+#define LPAIF_I2SCTL_MODE_14CH		11
+#define LPAIF_I2SCTL_MODE_16CH		12
+#define LPAIF_I2SCTL_MODE_SD4		13
+#define LPAIF_I2SCTL_MODE_SD5		14
+#define LPAIF_I2SCTL_MODE_SD6		15
+#define LPAIF_I2SCTL_MODE_SD7		16
+#define LPAIF_I2SCTL_MODE_QUAD45	17
+#define LPAIF_I2SCTL_MODE_QUAD47	18
+#define LPAIF_I2SCTL_MODE_8CH_2		19
 
-#define LPAIF_I2SCTL_SPKMODE_MASK	0x3C00
-#define LPAIF_I2SCTL_SPKMODE_SHIFT	10
-#define LPAIF_I2SCTL_SPKMODE(mode)	((mode) << LPAIF_I2SCTL_SPKMODE_SHIFT)
+#define LPAIF_I2SCTL_SPKMODE(mode)	mode
 
-#define LPAIF_I2SCTL_SPKMONO_MASK	0x0200
-#define LPAIF_I2SCTL_SPKMONO_SHIFT	9
-#define LPAIF_I2SCTL_SPKMONO_STEREO	(0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
-#define LPAIF_I2SCTL_SPKMONO_MONO	(1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
+#define LPAIF_I2SCTL_SPKMONO_STEREO	0
+#define LPAIF_I2SCTL_SPKMONO_MONO	1
 
-#define LPAIF_I2SCTL_MICEN_MASK		GENMASK(8, 8)
-#define LPAIF_I2SCTL_MICEN_SHIFT	8
-#define LPAIF_I2SCTL_MICEN_DISABLE	(0 << LPAIF_I2SCTL_MICEN_SHIFT)
-#define LPAIF_I2SCTL_MICEN_ENABLE	(1 << LPAIF_I2SCTL_MICEN_SHIFT)
+#define LPAIF_I2SCTL_MICEN_DISABLE	0
+#define LPAIF_I2SCTL_MICEN_ENABLE	1
 
-#define LPAIF_I2SCTL_MICMODE_MASK	GENMASK(7, 4)
-#define LPAIF_I2SCTL_MICMODE_SHIFT	4
-#define LPAIF_I2SCTL_MICMODE(mode)	((mode) << LPAIF_I2SCTL_MICMODE_SHIFT)
+#define LPAIF_I2SCTL_MICMODE(mode)	mode
 
-#define LPAIF_I2SCTL_MIMONO_MASK	GENMASK(3, 3)
-#define LPAIF_I2SCTL_MICMONO_SHIFT	3
-#define LPAIF_I2SCTL_MICMONO_STEREO	(0 << LPAIF_I2SCTL_MICMONO_SHIFT)
-#define LPAIF_I2SCTL_MICMONO_MONO	(1 << LPAIF_I2SCTL_MICMONO_SHIFT)
+#define LPAIF_I2SCTL_MICMONO_STEREO	0
+#define LPAIF_I2SCTL_MICMONO_MONO	1
 
-#define LPAIF_I2SCTL_WSSRC_MASK		0x0004
-#define LPAIF_I2SCTL_WSSRC_SHIFT	2
-#define LPAIF_I2SCTL_WSSRC_INTERNAL	(0 << LPAIF_I2SCTL_WSSRC_SHIFT)
-#define LPAIF_I2SCTL_WSSRC_EXTERNAL	(1 << LPAIF_I2SCTL_WSSRC_SHIFT)
+#define LPAIF_I2SCTL_WSSRC_INTERNAL	0
+#define LPAIF_I2SCTL_WSSRC_EXTERNAL	1
 
-#define LPAIF_I2SCTL_BITWIDTH_MASK	0x0003
-#define LPAIF_I2SCTL_BITWIDTH_SHIFT	0
-#define LPAIF_I2SCTL_BITWIDTH_16	(0 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_24	(1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
-#define LPAIF_I2SCTL_BITWIDTH_32	(2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
+#define LPAIF_I2SCTL_BITWIDTH_16	0
+#define LPAIF_I2SCTL_BITWIDTH_24	1
+#define LPAIF_I2SCTL_BITWIDTH_32	2
 
 /* LPAIF IRQ */
 #define LPAIF_IRQ_REG_ADDR(v, addr, port) \
@@ -121,42 +115,59 @@ 
 #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_DMACTL_BURSTEN_MASK	0x800
-#define LPAIF_DMACTL_BURSTEN_SHIFT	11
-#define LPAIF_DMACTL_BURSTEN_SINGLE	(0 << LPAIF_DMACTL_BURSTEN_SHIFT)
-#define LPAIF_DMACTL_BURSTEN_INCR4	(1 << LPAIF_DMACTL_BURSTEN_SHIFT)
-
-#define LPAIF_DMACTL_WPSCNT_MASK	0x700
-#define LPAIF_DMACTL_WPSCNT_SHIFT	8
-#define LPAIF_DMACTL_WPSCNT_ONE	(0 << LPAIF_DMACTL_WPSCNT_SHIFT)
-#define LPAIF_DMACTL_WPSCNT_TWO	(1 << LPAIF_DMACTL_WPSCNT_SHIFT)
-#define LPAIF_DMACTL_WPSCNT_THREE	(2 << LPAIF_DMACTL_WPSCNT_SHIFT)
-#define LPAIF_DMACTL_WPSCNT_FOUR	(3 << LPAIF_DMACTL_WPSCNT_SHIFT)
-#define LPAIF_DMACTL_WPSCNT_SIX	(5 << LPAIF_DMACTL_WPSCNT_SHIFT)
-#define LPAIF_DMACTL_WPSCNT_EIGHT	(7 << LPAIF_DMACTL_WPSCNT_SHIFT)
-
-#define LPAIF_DMACTL_AUDINTF_MASK	0x0F0
-#define LPAIF_DMACTL_AUDINTF_SHIFT	4
-#define LPAIF_DMACTL_AUDINTF(id)	(id << LPAIF_DMACTL_AUDINTF_SHIFT)
-
-#define LPAIF_DMACTL_FIFOWM_MASK	0x00E
-#define LPAIF_DMACTL_FIFOWM_SHIFT	1
-#define LPAIF_DMACTL_FIFOWM_1		(0 << LPAIF_DMACTL_FIFOWM_SHIFT)
-#define LPAIF_DMACTL_FIFOWM_2		(1 << LPAIF_DMACTL_FIFOWM_SHIFT)
-#define LPAIF_DMACTL_FIFOWM_3		(2 << LPAIF_DMACTL_FIFOWM_SHIFT)
-#define LPAIF_DMACTL_FIFOWM_4		(3 << LPAIF_DMACTL_FIFOWM_SHIFT)
-#define LPAIF_DMACTL_FIFOWM_5		(4 << LPAIF_DMACTL_FIFOWM_SHIFT)
-#define LPAIF_DMACTL_FIFOWM_6		(5 << LPAIF_DMACTL_FIFOWM_SHIFT)
-#define LPAIF_DMACTL_FIFOWM_7		(6 << LPAIF_DMACTL_FIFOWM_SHIFT)
-#define LPAIF_DMACTL_FIFOWM_8		(7 << LPAIF_DMACTL_FIFOWM_SHIFT)
-
-#define LPAIF_DMACTL_ENABLE_MASK	0x1
-#define LPAIF_DMACTL_ENABLE_SHIFT	0
-#define LPAIF_DMACTL_ENABLE_OFF	(0 << LPAIF_DMACTL_ENABLE_SHIFT)
-#define LPAIF_DMACTL_ENABLE_ON		(1 << LPAIF_DMACTL_ENABLE_SHIFT)
-
-#define LPAIF_DMACTL_DYNCLK_MASK	BIT(12)
-#define LPAIF_DMACTL_DYNCLK_SHIFT	12
-#define LPAIF_DMACTL_DYNCLK_OFF	(0 << LPAIF_DMACTL_DYNCLK_SHIFT)
-#define LPAIF_DMACTL_DYNCLK_ON		(1 << LPAIF_DMACTL_DYNCLK_SHIFT)
+#define LPAIF_DMACTL_BURSTEN_SINGLE	0
+#define LPAIF_DMACTL_BURSTEN_INCR4	1
+
+#define LPAIF_DMACTL_WPSCNT_ONE		0
+#define LPAIF_DMACTL_WPSCNT_TWO		1
+#define LPAIF_DMACTL_WPSCNT_THREE	2
+#define LPAIF_DMACTL_WPSCNT_FOUR	3
+#define LPAIF_DMACTL_WPSCNT_SIX		5
+#define LPAIF_DMACTL_WPSCNT_EIGHT	7
+#define LPAIF_DMACTL_WPSCNT_TEN		9
+#define LPAIF_DMACTL_WPSCNT_TWELVE	11
+#define LPAIF_DMACTL_WPSCNT_FOURTEEN	13
+#define LPAIF_DMACTL_WPSCNT_SIXTEEN	15
+
+#define LPAIF_DMACTL_AUDINTF(id)	id
+
+#define LPAIF_DMACTL_FIFOWM_1		0
+#define LPAIF_DMACTL_FIFOWM_2		1
+#define LPAIF_DMACTL_FIFOWM_3		2
+#define LPAIF_DMACTL_FIFOWM_4		3
+#define LPAIF_DMACTL_FIFOWM_5		4
+#define LPAIF_DMACTL_FIFOWM_6		5
+#define LPAIF_DMACTL_FIFOWM_7		6
+#define LPAIF_DMACTL_FIFOWM_8		7
+#define LPAIF_DMACTL_FIFOWM_9		8
+#define LPAIF_DMACTL_FIFOWM_10		9
+#define LPAIF_DMACTL_FIFOWM_11		10
+#define LPAIF_DMACTL_FIFOWM_12		11
+#define LPAIF_DMACTL_FIFOWM_13		12
+#define LPAIF_DMACTL_FIFOWM_14		13
+#define LPAIF_DMACTL_FIFOWM_15		14
+#define LPAIF_DMACTL_FIFOWM_16		15
+#define LPAIF_DMACTL_FIFOWM_17		16
+#define LPAIF_DMACTL_FIFOWM_18		17
+#define LPAIF_DMACTL_FIFOWM_19		18
+#define LPAIF_DMACTL_FIFOWM_20		19
+#define LPAIF_DMACTL_FIFOWM_21		20
+#define LPAIF_DMACTL_FIFOWM_22		21
+#define LPAIF_DMACTL_FIFOWM_23		22
+#define LPAIF_DMACTL_FIFOWM_24		23
+#define LPAIF_DMACTL_FIFOWM_25		24
+#define LPAIF_DMACTL_FIFOWM_26		25
+#define LPAIF_DMACTL_FIFOWM_27		26
+#define LPAIF_DMACTL_FIFOWM_28		27
+#define LPAIF_DMACTL_FIFOWM_29		28
+#define LPAIF_DMACTL_FIFOWM_30		29
+#define LPAIF_DMACTL_FIFOWM_31		30
+#define LPAIF_DMACTL_FIFOWM_32		31
+
+#define LPAIF_DMACTL_ENABLE_OFF		0
+#define LPAIF_DMACTL_ENABLE_ON		1
+
+#define LPAIF_DMACTL_DYNCLK_OFF		0
+#define LPAIF_DMACTL_DYNCLK_ON		1
+
 #endif /* __LPASS_LPAIF_REG_H__ */
diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c
index 34f7fd1..445ca193 100644
--- a/sound/soc/qcom/lpass-platform.c
+++ b/sound/soc/qcom/lpass-platform.c
@@ -50,6 +50,53 @@  static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
 	.fifo_size		=	0,
 };
 
+static int lpass_platform_alloc_dmactl_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, *wr_dmactl;
+
+	drvdata->rd_dmactl = devm_kzalloc(dev, sizeof(struct lpaif_dmactl),
+					  GFP_KERNEL);
+	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);
+
+	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))
+		return -EINVAL;
+
+	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))
+		return -EINVAL;
+
+	return 0;
+}
+
 static int lpass_platform_pcmops_open(struct snd_soc_component *component,
 				      struct snd_pcm_substream *substream)
 {
@@ -59,9 +106,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;
 
-	data = devm_kzalloc(soc_runtime->dev, sizeof(*data), GFP_KERNEL);
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
@@ -111,13 +158,13 @@  static int lpass_platform_pcmops_close(struct snd_soc_component *component,
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct lpass_data *drvdata = snd_soc_component_get_drvdata(component);
 	struct lpass_variant *v = drvdata->variant;
-	struct lpass_pcm_data *data;
+	struct lpass_pcm_data *data = runtime->private_data;
 
-	data = runtime->private_data;
 	drvdata->substream[data->dma_ch] = NULL;
 	if (v->free_dma_channel)
 		v->free_dma_channel(drvdata, data->dma_ch);
 
+	kfree(data);
 	return 0;
 }
 
@@ -132,12 +179,19 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 	struct lpass_variant *v = drvdata->variant;
 	snd_pcm_format_t format = params_format(params);
 	unsigned int channels = params_channels(params);
-	unsigned int regval;
-	int ch, dir = substream->stream;
-	int bitwidth;
+	struct lpaif_dmactl *dmactl;
+	int dir = substream->stream;
+	int id, bitwidth;
 	int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start;
 
-	ch = pcm_data->dma_ch;
+
+	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
+		dmactl = drvdata->rd_dmactl;
+		id = pcm_data->dma_ch;
+	} else {
+		dmactl = drvdata->wr_dmactl;
+		id = pcm_data->dma_ch - v->wrdma_channel_start;
+	}
 
 	bitwidth = snd_pcm_format_width(format);
 	if (bitwidth < 0) {
@@ -146,25 +200,29 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 		return bitwidth;
 	}
 
-	regval = LPAIF_DMACTL_BURSTEN_INCR4 |
-			LPAIF_DMACTL_AUDINTF(dma_port) |
-			LPAIF_DMACTL_FIFOWM_8;
+	ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4);
+	ret = regmap_fields_write(dmactl->fifowm, id, LPAIF_DMACTL_FIFOWM_8);
+	ret = regmap_fields_write(dmactl->intf, id, LPAIF_DMACTL_AUDINTF(dma_port));
 
 	switch (bitwidth) {
 	case 16:
 		switch (channels) {
 		case 1:
 		case 2:
-			regval |= LPAIF_DMACTL_WPSCNT_ONE;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_ONE);
 			break;
 		case 4:
-			regval |= LPAIF_DMACTL_WPSCNT_TWO;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_TWO);
 			break;
 		case 6:
-			regval |= LPAIF_DMACTL_WPSCNT_THREE;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_THREE);
 			break;
 		case 8:
-			regval |= LPAIF_DMACTL_WPSCNT_FOUR;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_FOUR);
 			break;
 		default:
 			dev_err(soc_runtime->dev,
@@ -177,19 +235,24 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 	case 32:
 		switch (channels) {
 		case 1:
-			regval |= LPAIF_DMACTL_WPSCNT_ONE;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_ONE);
 			break;
 		case 2:
-			regval |= LPAIF_DMACTL_WPSCNT_TWO;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_TWO);
 			break;
 		case 4:
-			regval |= LPAIF_DMACTL_WPSCNT_FOUR;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_FOUR);
 			break;
 		case 6:
-			regval |= LPAIF_DMACTL_WPSCNT_SIX;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_SIX);
 			break;
 		case 8:
-			regval |= LPAIF_DMACTL_WPSCNT_EIGHT;
+			ret = regmap_fields_write(dmactl->wpscnt, id,
+						 LPAIF_DMACTL_WPSCNT_EIGHT);
 			break;
 		default:
 			dev_err(soc_runtime->dev,
@@ -204,10 +267,8 @@  static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
 		return -EINVAL;
 	}
 
-	ret = regmap_write(drvdata->lpaif_map,
-			LPAIF_DMACTL_REG(v, ch, dir), regval);
 	if (ret) {
-		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
+		dev_err(soc_runtime->dev, "error writing to dmactl reg: %d\n",
 			ret);
 		return ret;
 	}
@@ -244,9 +305,17 @@  static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
-	int ret, ch, dir = substream->stream;
+	struct lpaif_dmactl *dmactl;
+	int ret, id, ch, dir = substream->stream;
 
 	ch = pcm_data->dma_ch;
+	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
+		dmactl = drvdata->rd_dmactl;
+		id = pcm_data->dma_ch;
+	} else {
+		dmactl = drvdata->wr_dmactl;
+		id = pcm_data->dma_ch - v->wrdma_channel_start;
+	}
 
 	ret = regmap_write(drvdata->lpaif_map,
 			LPAIF_DMABASE_REG(v, ch, dir),
@@ -275,9 +344,7 @@  static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
 		return ret;
 	}
 
-	ret = regmap_update_bits(drvdata->lpaif_map,
-			LPAIF_DMACTL_REG(v, ch, dir),
-			LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON);
+	ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
 	if (ret) {
 		dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
 			ret);
@@ -296,9 +363,18 @@  static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 	struct snd_pcm_runtime *rt = substream->runtime;
 	struct lpass_pcm_data *pcm_data = rt->private_data;
 	struct lpass_variant *v = drvdata->variant;
-	int ret, ch, dir = substream->stream;
+	struct lpaif_dmactl *dmactl;
+	int ret, ch, id;
+	int dir = substream->stream;
 
 	ch = pcm_data->dma_ch;
+	if (dir ==  SNDRV_PCM_STREAM_PLAYBACK) {
+		dmactl = drvdata->rd_dmactl;
+		id = pcm_data->dma_ch;
+	} else {
+		dmactl = drvdata->wr_dmactl;
+		id = pcm_data->dma_ch - v->wrdma_channel_start;
+	}
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
@@ -324,10 +400,8 @@  static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 			return ret;
 		}
 
-		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_DMACTL_REG(v, ch, dir),
-				LPAIF_DMACTL_ENABLE_MASK,
-				LPAIF_DMACTL_ENABLE_ON);
+		ret = regmap_fields_write(dmactl->enable, id,
+					 LPAIF_DMACTL_ENABLE_ON);
 		if (ret) {
 			dev_err(soc_runtime->dev,
 				"error writing to rdmactl reg: %d\n", ret);
@@ -337,10 +411,8 @@  static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		ret = regmap_update_bits(drvdata->lpaif_map,
-				LPAIF_DMACTL_REG(v, ch, dir),
-				LPAIF_DMACTL_ENABLE_MASK,
-				LPAIF_DMACTL_ENABLE_OFF);
+		ret = regmap_fields_write(dmactl->enable, id,
+					 LPAIF_DMACTL_ENABLE_OFF);
 		if (ret) {
 			dev_err(soc_runtime->dev,
 				"error writing to rdmactl reg: %d\n", ret);
@@ -580,6 +652,13 @@  int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
 		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;
+	}
 
 	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 450020e..4294ec2 100644
--- a/sound/soc/qcom/lpass.h
+++ b/sound/soc/qcom/lpass.h
@@ -17,6 +17,28 @@ 
 #define LPASS_MAX_MI2S_PORTS			(8)
 #define LPASS_MAX_DMA_CHANNELS			(8)
 
+struct lpaif_i2sctl {
+	struct regmap_field *loopback;
+	struct regmap_field *spken;
+	struct regmap_field *spkmode;
+	struct regmap_field *spkmono;
+	struct regmap_field *micen;
+	struct regmap_field *micmode;
+	struct regmap_field *micmono;
+	struct regmap_field *wssrc;
+	struct regmap_field *bitwidth;
+};
+
+
+struct lpaif_dmactl {
+	struct regmap_field *bursten;
+	struct regmap_field *wpscnt;
+	struct regmap_field *intf;
+	struct regmap_field *fifowm;
+	struct regmap_field *enable;
+	struct regmap_field *dyncclk;
+};
+
 /* Both the CPU DAI and platform drivers will access this data */
 struct lpass_data {
 
@@ -55,6 +77,10 @@  struct lpass_data {
 	struct clk_bulk_data *clks;
 	int num_clks;
 
+	/* Regmap fields of I2SCTL & DMACTL registers bitfields */
+	struct lpaif_i2sctl *i2sctl;
+	struct lpaif_dmactl *rd_dmactl;
+	struct lpaif_dmactl *wr_dmactl;
 };
 
 /* Vairant data per each SOC */
@@ -72,6 +98,33 @@  struct lpass_variant {
 	u32	wrdma_reg_stride;
 	u32	wrdma_channels;
 
+	/* I2SCTL Register fields */
+	struct reg_field loopback;
+	struct reg_field spken;
+	struct reg_field spkmode;
+	struct reg_field spkmono;
+	struct reg_field micen;
+	struct reg_field micmode;
+	struct reg_field micmono;
+	struct reg_field wssrc;
+	struct reg_field bitwidth;
+
+	/* RD_DMA Register fields */
+	struct reg_field rdma_bursten;
+	struct reg_field rdma_wpscnt;
+	struct reg_field rdma_intf;
+	struct reg_field rdma_fifowm;
+	struct reg_field rdma_enable;
+	struct reg_field rdma_dyncclk;
+
+	/* RD_DMA Register fields */
+	struct reg_field wrdma_bursten;
+	struct reg_field wrdma_wpscnt;
+	struct reg_field wrdma_intf;
+	struct reg_field wrdma_fifowm;
+	struct reg_field wrdma_enable;
+	struct reg_field wrdma_dyncclk;
+
 	/**
 	 * on SOCs like APQ8016 the channel control bits start
 	 * at different offset to ipq806x