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@xxxxxxxxxxxxxx>
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?
wrdma_channels is used in alloc_dma_channel() to get the channel id.
ÂÂÂÂÂ 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!
Thanks,
+ÂÂÂ /* 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