ASoC: qcom: lpass: Use regmap_field for i2sctl and dmactl registers

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>
Link: https://lore.kernel.org/r/1597402388-14112-6-git-send-email-rohitkr@codeaurora.org
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Rohit kumar 2020-08-14 16:23:01 +05:30 committed by Mark Brown
parent 5fd188215d
commit b5022a36d2
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
6 changed files with 402 additions and 147 deletions

View File

@ -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",

View File

@ -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,6 +105,8 @@ 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);
@ -92,28 +120,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 +220,42 @@ 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 (ret) {
dev_err(dai->dev, "error writing to i2sctl spkr mode: %d\n",
ret);
return ret;
}
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 (ret) {
dev_err(dai->dev, "error writing to i2sctl mic mode: %d\n",
ret);
return ret;
}
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",
@ -228,22 +285,20 @@ 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 +307,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 +330,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);
@ -599,6 +645,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,

View File

@ -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 *[]) {

View File

@ -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_BURSTEN_SINGLE 0
#define LPAIF_DMACTL_BURSTEN_INCR4 1
#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_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_MASK 0x0F0
#define LPAIF_DMACTL_AUDINTF_SHIFT 4
#define LPAIF_DMACTL_AUDINTF(id) (id << LPAIF_DMACTL_AUDINTF_SHIFT)
#define LPAIF_DMACTL_AUDINTF(id) id
#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_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_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_ENABLE_OFF 0
#define LPAIF_DMACTL_ENABLE_ON 1
#define LPAIF_DMACTL_DYNCLK_OFF 0
#define LPAIF_DMACTL_DYNCLK_ON 1
#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)
#endif /* __LPASS_LPAIF_REG_H__ */

View File

@ -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)
{
@ -134,11 +181,18 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
snd_pcm_format_t format = params_format(params);
unsigned int channels = params_channels(params);
unsigned int regval;
int ch, dir = substream->stream;
struct lpaif_dmactl *dmactl;
int id, dir = substream->stream;
int 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) {
@ -147,25 +201,39 @@ 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);
if (ret) {
dev_err(soc_runtime->dev, "error updating bursten field: %d\n", ret);
return 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 (bitwidth) {
case 16:
switch (channels) {
case 1:
case 2:
regval |= LPAIF_DMACTL_WPSCNT_ONE;
regval = LPAIF_DMACTL_WPSCNT_ONE;
break;
case 4:
regval |= LPAIF_DMACTL_WPSCNT_TWO;
regval = LPAIF_DMACTL_WPSCNT_TWO;
break;
case 6:
regval |= LPAIF_DMACTL_WPSCNT_THREE;
regval = LPAIF_DMACTL_WPSCNT_THREE;
break;
case 8:
regval |= LPAIF_DMACTL_WPSCNT_FOUR;
regval = LPAIF_DMACTL_WPSCNT_FOUR;
break;
default:
dev_err(soc_runtime->dev,
@ -178,19 +246,19 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
case 32:
switch (channels) {
case 1:
regval |= LPAIF_DMACTL_WPSCNT_ONE;
regval = LPAIF_DMACTL_WPSCNT_ONE;
break;
case 2:
regval |= LPAIF_DMACTL_WPSCNT_TWO;
regval = LPAIF_DMACTL_WPSCNT_TWO;
break;
case 4:
regval |= LPAIF_DMACTL_WPSCNT_FOUR;
regval = LPAIF_DMACTL_WPSCNT_FOUR;
break;
case 6:
regval |= LPAIF_DMACTL_WPSCNT_SIX;
regval = LPAIF_DMACTL_WPSCNT_SIX;
break;
case 8:
regval |= LPAIF_DMACTL_WPSCNT_EIGHT;
regval = LPAIF_DMACTL_WPSCNT_EIGHT;
break;
default:
dev_err(soc_runtime->dev,
@ -205,10 +273,9 @@ 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);
ret = regmap_fields_write(dmactl->wpscnt, id, 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;
}
@ -245,9 +312,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),
@ -276,9 +351,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);
@ -297,9 +370,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:
@ -325,10 +407,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);
@ -338,10 +418,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 +658,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);

View File

@ -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;
/* WR_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