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_reg_stride = 0x1000,
.wrdma_channel_start = 5, .wrdma_channel_start = 5,
.wrdma_channels = 2, .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*[]) { .clk_name = (const char*[]) {
"pcnoc-mport-clk", "pcnoc-mport-clk",
"pcnoc-sway-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_MASK GENMASK(2, 0)
#define LPASS_CPU_I2S_SD0_1_2_3_MASK GENMASK(3, 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, static int lpass_cpu_daiops_set_sysclk(struct snd_soc_dai *dai, int clk_id,
unsigned int freq, int dir) 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 snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{ {
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(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); snd_pcm_format_t format = params_format(params);
unsigned int channels = params_channels(params); unsigned int channels = params_channels(params);
unsigned int rate = params_rate(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; return bitwidth;
} }
regval = LPAIF_I2SCTL_LOOPBACK_DISABLE | ret = regmap_fields_write(i2sctl->loopback, id,
LPAIF_I2SCTL_WSSRC_INTERNAL; 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) { switch (bitwidth) {
case 16: case 16:
regval |= LPAIF_I2SCTL_BITWIDTH_16; regval = LPAIF_I2SCTL_BITWIDTH_16;
break; break;
case 24: case 24:
regval |= LPAIF_I2SCTL_BITWIDTH_24; regval = LPAIF_I2SCTL_BITWIDTH_24;
break; break;
case 32: case 32:
regval |= LPAIF_I2SCTL_BITWIDTH_32; regval = LPAIF_I2SCTL_BITWIDTH_32;
break; break;
default: default:
dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth); dev_err(dai->dev, "invalid bitwidth given: %d\n", bitwidth);
return -EINVAL; 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) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
mode = drvdata->mi2s_playback_sd_mode[dai->driver->id]; mode = drvdata->mi2s_playback_sd_mode[id];
else else
mode = drvdata->mi2s_capture_sd_mode[dai->driver->id]; mode = drvdata->mi2s_capture_sd_mode[id];
if (!mode) { if (!mode) {
dev_err(dai->dev, "no line is assigned\n"); 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) { 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) if (channels >= 2)
regval |= LPAIF_I2SCTL_SPKMONO_STEREO; ret = regmap_fields_write(i2sctl->spkmono, id,
LPAIF_I2SCTL_SPKMONO_STEREO);
else else
regval |= LPAIF_I2SCTL_SPKMONO_MONO; ret = regmap_fields_write(i2sctl->spkmono, id,
LPAIF_I2SCTL_SPKMONO_MONO);
} else { } 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) if (channels >= 2)
regval |= LPAIF_I2SCTL_MICMONO_STEREO; ret = regmap_fields_write(i2sctl->micmono, id,
LPAIF_I2SCTL_MICMONO_STEREO);
else 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) { 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; 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); rate * bitwidth * 2);
if (ret) { if (ret) {
dev_err(dai->dev, "error setting mi2s bitclk to %u: %d\n", 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 snd_soc_dai *dai)
{ {
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(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; int ret;
unsigned int val, mask;
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
val = LPAIF_I2SCTL_SPKEN_ENABLE; ret = regmap_fields_write(i2sctl->spken, id,
mask = LPAIF_I2SCTL_SPKEN_MASK; LPAIF_I2SCTL_SPKEN_ENABLE);
} else { } else {
val = LPAIF_I2SCTL_MICEN_ENABLE; ret = regmap_fields_write(i2sctl->micen, id,
mask = LPAIF_I2SCTL_MICEN_MASK; LPAIF_I2SCTL_MICEN_ENABLE);
} }
ret = regmap_update_bits(drvdata->lpaif_map,
LPAIF_I2SCTL_REG(drvdata->variant, dai->driver->id),
mask, val);
if (ret) 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; return ret;
} }
@ -252,25 +307,21 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream,
int cmd, struct snd_soc_dai *dai) int cmd, struct snd_soc_dai *dai)
{ {
struct lpass_data *drvdata = snd_soc_dai_get_drvdata(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; int ret = -EINVAL;
unsigned int val, mask;
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
val = LPAIF_I2SCTL_SPKEN_ENABLE; ret = regmap_fields_write(i2sctl->spken, id,
mask = LPAIF_I2SCTL_SPKEN_MASK; LPAIF_I2SCTL_SPKEN_ENABLE);
} else { } else {
val = LPAIF_I2SCTL_MICEN_ENABLE; ret = regmap_fields_write(i2sctl->micen, id,
mask = LPAIF_I2SCTL_MICEN_MASK; LPAIF_I2SCTL_MICEN_ENABLE);
} }
ret = regmap_update_bits(drvdata->lpaif_map,
LPAIF_I2SCTL_REG(drvdata->variant,
dai->driver->id),
mask, val);
if (ret) if (ret)
dev_err(dai->dev, "error writing to i2sctl reg: %d\n", dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
ret); 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_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
val = LPAIF_I2SCTL_SPKEN_DISABLE; ret = regmap_fields_write(i2sctl->spken, id,
mask = LPAIF_I2SCTL_SPKEN_MASK; LPAIF_I2SCTL_SPKEN_DISABLE);
} else { } else {
val = LPAIF_I2SCTL_MICEN_DISABLE; ret = regmap_fields_write(i2sctl->micen, id,
mask = LPAIF_I2SCTL_MICEN_MASK; LPAIF_I2SCTL_MICEN_DISABLE);
} }
ret = regmap_update_bits(drvdata->lpaif_map,
LPAIF_I2SCTL_REG(drvdata->variant,
dai->driver->id),
mask, val);
if (ret) if (ret)
dev_err(dai->dev, "error writing to i2sctl reg: %d\n", dev_err(dai->dev, "error writing to i2sctl reg: %d\n",
ret); 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, ret = devm_snd_soc_register_component(dev,
&lpass_cpu_comp_driver, &lpass_cpu_comp_driver,
variant->dai_driver, variant->dai_driver,

View File

@ -123,6 +123,30 @@ static struct lpass_variant ipq806x_data = {
.wrdma_reg_stride = 0x1000, .wrdma_reg_stride = 0x1000,
.wrdma_channel_start = 5, .wrdma_channel_start = 5,
.wrdma_channels = 4, .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, .dai_driver = &ipq806x_lpass_cpu_dai_driver,
.num_dai = 1, .num_dai = 1,
.dai_osr_clk_names = (const char *[]) { .dai_osr_clk_names = (const char *[]) {

View File

@ -12,15 +12,12 @@
(v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port)) (v->i2sctrl_reg_base + (addr) + v->i2sctrl_reg_stride * (port))
#define LPAIF_I2SCTL_REG(v, port) LPAIF_I2SCTL_REG_ADDR(v, 0x0, (port)) #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_LOOPBACK_DISABLE 0
#define LPAIF_I2SCTL_SPKEN_SHIFT 14 #define LPAIF_I2SCTL_LOOPBACK_ENABLE 1
#define LPAIF_I2SCTL_SPKEN_DISABLE (0 << LPAIF_I2SCTL_SPKEN_SHIFT)
#define LPAIF_I2SCTL_SPKEN_ENABLE (1 << LPAIF_I2SCTL_SPKEN_SHIFT) #define LPAIF_I2SCTL_SPKEN_DISABLE 0
#define LPAIF_I2SCTL_SPKEN_ENABLE 1
#define LPAIF_I2SCTL_MODE_NONE 0 #define LPAIF_I2SCTL_MODE_NONE 0
#define LPAIF_I2SCTL_MODE_SD0 1 #define LPAIF_I2SCTL_MODE_SD0 1
@ -31,40 +28,37 @@
#define LPAIF_I2SCTL_MODE_QUAD23 6 #define LPAIF_I2SCTL_MODE_QUAD23 6
#define LPAIF_I2SCTL_MODE_6CH 7 #define LPAIF_I2SCTL_MODE_6CH 7
#define LPAIF_I2SCTL_MODE_8CH 8 #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(mode) mode
#define LPAIF_I2SCTL_SPKMODE_SHIFT 10
#define LPAIF_I2SCTL_SPKMODE(mode) ((mode) << LPAIF_I2SCTL_SPKMODE_SHIFT)
#define LPAIF_I2SCTL_SPKMONO_MASK 0x0200 #define LPAIF_I2SCTL_SPKMONO_STEREO 0
#define LPAIF_I2SCTL_SPKMONO_SHIFT 9 #define LPAIF_I2SCTL_SPKMONO_MONO 1
#define LPAIF_I2SCTL_SPKMONO_STEREO (0 << LPAIF_I2SCTL_SPKMONO_SHIFT)
#define LPAIF_I2SCTL_SPKMONO_MONO (1 << LPAIF_I2SCTL_SPKMONO_SHIFT)
#define LPAIF_I2SCTL_MICEN_MASK GENMASK(8, 8) #define LPAIF_I2SCTL_MICEN_DISABLE 0
#define LPAIF_I2SCTL_MICEN_SHIFT 8 #define LPAIF_I2SCTL_MICEN_ENABLE 1
#define LPAIF_I2SCTL_MICEN_DISABLE (0 << LPAIF_I2SCTL_MICEN_SHIFT)
#define LPAIF_I2SCTL_MICEN_ENABLE (1 << LPAIF_I2SCTL_MICEN_SHIFT)
#define LPAIF_I2SCTL_MICMODE_MASK GENMASK(7, 4) #define LPAIF_I2SCTL_MICMODE(mode) mode
#define LPAIF_I2SCTL_MICMODE_SHIFT 4
#define LPAIF_I2SCTL_MICMODE(mode) ((mode) << LPAIF_I2SCTL_MICMODE_SHIFT)
#define LPAIF_I2SCTL_MIMONO_MASK GENMASK(3, 3) #define LPAIF_I2SCTL_MICMONO_STEREO 0
#define LPAIF_I2SCTL_MICMONO_SHIFT 3 #define LPAIF_I2SCTL_MICMONO_MONO 1
#define LPAIF_I2SCTL_MICMONO_STEREO (0 << LPAIF_I2SCTL_MICMONO_SHIFT)
#define LPAIF_I2SCTL_MICMONO_MONO (1 << LPAIF_I2SCTL_MICMONO_SHIFT)
#define LPAIF_I2SCTL_WSSRC_MASK 0x0004 #define LPAIF_I2SCTL_WSSRC_INTERNAL 0
#define LPAIF_I2SCTL_WSSRC_SHIFT 2 #define LPAIF_I2SCTL_WSSRC_EXTERNAL 1
#define LPAIF_I2SCTL_WSSRC_INTERNAL (0 << LPAIF_I2SCTL_WSSRC_SHIFT)
#define LPAIF_I2SCTL_WSSRC_EXTERNAL (1 << LPAIF_I2SCTL_WSSRC_SHIFT)
#define LPAIF_I2SCTL_BITWIDTH_MASK 0x0003 #define LPAIF_I2SCTL_BITWIDTH_16 0
#define LPAIF_I2SCTL_BITWIDTH_SHIFT 0 #define LPAIF_I2SCTL_BITWIDTH_24 1
#define LPAIF_I2SCTL_BITWIDTH_16 (0 << LPAIF_I2SCTL_BITWIDTH_SHIFT) #define LPAIF_I2SCTL_BITWIDTH_32 2
#define LPAIF_I2SCTL_BITWIDTH_24 (1 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
#define LPAIF_I2SCTL_BITWIDTH_32 (2 << LPAIF_I2SCTL_BITWIDTH_SHIFT)
/* LPAIF IRQ */ /* LPAIF IRQ */
#define LPAIF_IRQ_REG_ADDR(v, addr, port) \ #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_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_DMAPERCNT_REG(v, chan, dir) __LPAIF_DMA_REG(v, chan, dir, PERCNT)
#define LPAIF_DMACTL_BURSTEN_MASK 0x800 #define LPAIF_DMACTL_BURSTEN_SINGLE 0
#define LPAIF_DMACTL_BURSTEN_SHIFT 11 #define LPAIF_DMACTL_BURSTEN_INCR4 1
#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_ONE 0
#define LPAIF_DMACTL_WPSCNT_SHIFT 8 #define LPAIF_DMACTL_WPSCNT_TWO 1
#define LPAIF_DMACTL_WPSCNT_ONE (0 << LPAIF_DMACTL_WPSCNT_SHIFT) #define LPAIF_DMACTL_WPSCNT_THREE 2
#define LPAIF_DMACTL_WPSCNT_TWO (1 << LPAIF_DMACTL_WPSCNT_SHIFT) #define LPAIF_DMACTL_WPSCNT_FOUR 3
#define LPAIF_DMACTL_WPSCNT_THREE (2 << LPAIF_DMACTL_WPSCNT_SHIFT) #define LPAIF_DMACTL_WPSCNT_SIX 5
#define LPAIF_DMACTL_WPSCNT_FOUR (3 << LPAIF_DMACTL_WPSCNT_SHIFT) #define LPAIF_DMACTL_WPSCNT_EIGHT 7
#define LPAIF_DMACTL_WPSCNT_SIX (5 << LPAIF_DMACTL_WPSCNT_SHIFT) #define LPAIF_DMACTL_WPSCNT_TEN 9
#define LPAIF_DMACTL_WPSCNT_EIGHT (7 << LPAIF_DMACTL_WPSCNT_SHIFT) #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(id) id
#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_1 0
#define LPAIF_DMACTL_FIFOWM_SHIFT 1 #define LPAIF_DMACTL_FIFOWM_2 1
#define LPAIF_DMACTL_FIFOWM_1 (0 << LPAIF_DMACTL_FIFOWM_SHIFT) #define LPAIF_DMACTL_FIFOWM_3 2
#define LPAIF_DMACTL_FIFOWM_2 (1 << LPAIF_DMACTL_FIFOWM_SHIFT) #define LPAIF_DMACTL_FIFOWM_4 3
#define LPAIF_DMACTL_FIFOWM_3 (2 << LPAIF_DMACTL_FIFOWM_SHIFT) #define LPAIF_DMACTL_FIFOWM_5 4
#define LPAIF_DMACTL_FIFOWM_4 (3 << LPAIF_DMACTL_FIFOWM_SHIFT) #define LPAIF_DMACTL_FIFOWM_6 5
#define LPAIF_DMACTL_FIFOWM_5 (4 << LPAIF_DMACTL_FIFOWM_SHIFT) #define LPAIF_DMACTL_FIFOWM_7 6
#define LPAIF_DMACTL_FIFOWM_6 (5 << LPAIF_DMACTL_FIFOWM_SHIFT) #define LPAIF_DMACTL_FIFOWM_8 7
#define LPAIF_DMACTL_FIFOWM_7 (6 << LPAIF_DMACTL_FIFOWM_SHIFT) #define LPAIF_DMACTL_FIFOWM_9 8
#define LPAIF_DMACTL_FIFOWM_8 (7 << LPAIF_DMACTL_FIFOWM_SHIFT) #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_OFF 0
#define LPAIF_DMACTL_ENABLE_SHIFT 0 #define LPAIF_DMACTL_ENABLE_ON 1
#define LPAIF_DMACTL_ENABLE_OFF (0 << LPAIF_DMACTL_ENABLE_SHIFT)
#define LPAIF_DMACTL_ENABLE_ON (1 << LPAIF_DMACTL_ENABLE_SHIFT) #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__ */ #endif /* __LPASS_LPAIF_REG_H__ */

View File

@ -50,6 +50,53 @@ static const struct snd_pcm_hardware lpass_platform_pcm_hardware = {
.fifo_size = 0, .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, static int lpass_platform_pcmops_open(struct snd_soc_component *component,
struct snd_pcm_substream *substream) 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); snd_pcm_format_t format = params_format(params);
unsigned int channels = params_channels(params); unsigned int channels = params_channels(params);
unsigned int regval; unsigned int regval;
int ch, dir = substream->stream; struct lpaif_dmactl *dmactl;
int id, dir = substream->stream;
int bitwidth; int bitwidth;
int ret, dma_port = pcm_data->i2s_port + v->dmactl_audif_start; 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); bitwidth = snd_pcm_format_width(format);
if (bitwidth < 0) { if (bitwidth < 0) {
@ -147,25 +201,39 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
return bitwidth; return bitwidth;
} }
regval = LPAIF_DMACTL_BURSTEN_INCR4 | ret = regmap_fields_write(dmactl->bursten, id, LPAIF_DMACTL_BURSTEN_INCR4);
LPAIF_DMACTL_AUDINTF(dma_port) | if (ret) {
LPAIF_DMACTL_FIFOWM_8; 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) { switch (bitwidth) {
case 16: case 16:
switch (channels) { switch (channels) {
case 1: case 1:
case 2: case 2:
regval |= LPAIF_DMACTL_WPSCNT_ONE; regval = LPAIF_DMACTL_WPSCNT_ONE;
break; break;
case 4: case 4:
regval |= LPAIF_DMACTL_WPSCNT_TWO; regval = LPAIF_DMACTL_WPSCNT_TWO;
break; break;
case 6: case 6:
regval |= LPAIF_DMACTL_WPSCNT_THREE; regval = LPAIF_DMACTL_WPSCNT_THREE;
break; break;
case 8: case 8:
regval |= LPAIF_DMACTL_WPSCNT_FOUR; regval = LPAIF_DMACTL_WPSCNT_FOUR;
break; break;
default: default:
dev_err(soc_runtime->dev, dev_err(soc_runtime->dev,
@ -178,19 +246,19 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
case 32: case 32:
switch (channels) { switch (channels) {
case 1: case 1:
regval |= LPAIF_DMACTL_WPSCNT_ONE; regval = LPAIF_DMACTL_WPSCNT_ONE;
break; break;
case 2: case 2:
regval |= LPAIF_DMACTL_WPSCNT_TWO; regval = LPAIF_DMACTL_WPSCNT_TWO;
break; break;
case 4: case 4:
regval |= LPAIF_DMACTL_WPSCNT_FOUR; regval = LPAIF_DMACTL_WPSCNT_FOUR;
break; break;
case 6: case 6:
regval |= LPAIF_DMACTL_WPSCNT_SIX; regval = LPAIF_DMACTL_WPSCNT_SIX;
break; break;
case 8: case 8:
regval |= LPAIF_DMACTL_WPSCNT_EIGHT; regval = LPAIF_DMACTL_WPSCNT_EIGHT;
break; break;
default: default:
dev_err(soc_runtime->dev, dev_err(soc_runtime->dev,
@ -205,10 +273,9 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component,
return -EINVAL; return -EINVAL;
} }
ret = regmap_write(drvdata->lpaif_map, ret = regmap_fields_write(dmactl->wpscnt, id, regval);
LPAIF_DMACTL_REG(v, ch, dir), regval);
if (ret) { 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); ret);
return 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 snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_pcm_data *pcm_data = rt->private_data;
struct lpass_variant *v = drvdata->variant; 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; 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, ret = regmap_write(drvdata->lpaif_map,
LPAIF_DMABASE_REG(v, ch, dir), LPAIF_DMABASE_REG(v, ch, dir),
@ -276,9 +351,7 @@ static int lpass_platform_pcmops_prepare(struct snd_soc_component *component,
return ret; return ret;
} }
ret = regmap_update_bits(drvdata->lpaif_map, ret = regmap_fields_write(dmactl->enable, id, LPAIF_DMACTL_ENABLE_ON);
LPAIF_DMACTL_REG(v, ch, dir),
LPAIF_DMACTL_ENABLE_MASK, LPAIF_DMACTL_ENABLE_ON);
if (ret) { if (ret) {
dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n", dev_err(soc_runtime->dev, "error writing to rdmactl reg: %d\n",
ret); ret);
@ -297,9 +370,18 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
struct snd_pcm_runtime *rt = substream->runtime; struct snd_pcm_runtime *rt = substream->runtime;
struct lpass_pcm_data *pcm_data = rt->private_data; struct lpass_pcm_data *pcm_data = rt->private_data;
struct lpass_variant *v = drvdata->variant; 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; 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) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
@ -325,9 +407,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
return ret; return ret;
} }
ret = regmap_update_bits(drvdata->lpaif_map, ret = regmap_fields_write(dmactl->enable, id,
LPAIF_DMACTL_REG(v, ch, dir),
LPAIF_DMACTL_ENABLE_MASK,
LPAIF_DMACTL_ENABLE_ON); LPAIF_DMACTL_ENABLE_ON);
if (ret) { if (ret) {
dev_err(soc_runtime->dev, dev_err(soc_runtime->dev,
@ -338,9 +418,7 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component,
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
ret = regmap_update_bits(drvdata->lpaif_map, ret = regmap_fields_write(dmactl->enable, id,
LPAIF_DMACTL_REG(v, ch, dir),
LPAIF_DMACTL_ENABLE_MASK,
LPAIF_DMACTL_ENABLE_OFF); LPAIF_DMACTL_ENABLE_OFF);
if (ret) { if (ret) {
dev_err(soc_runtime->dev, dev_err(soc_runtime->dev,
@ -580,6 +658,13 @@ int asoc_qcom_lpass_platform_register(struct platform_device *pdev)
return ret; return ret;
} }
ret = lpass_platform_alloc_dmactl_fields(&pdev->dev,
drvdata->lpaif_map);
if (ret) {
dev_err(&pdev->dev,
"error initializing dmactl fields: %d\n", ret);
return ret;
}
return devm_snd_soc_register_component(&pdev->dev, return devm_snd_soc_register_component(&pdev->dev,
&lpass_component_driver, NULL, 0); &lpass_component_driver, NULL, 0);

View File

@ -17,6 +17,28 @@
#define LPASS_MAX_MI2S_PORTS (8) #define LPASS_MAX_MI2S_PORTS (8)
#define LPASS_MAX_DMA_CHANNELS (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 */ /* Both the CPU DAI and platform drivers will access this data */
struct lpass_data { struct lpass_data {
@ -55,6 +77,10 @@ struct lpass_data {
struct clk_bulk_data *clks; struct clk_bulk_data *clks;
int num_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 */ /* Vairant data per each SOC */
@ -72,6 +98,33 @@ struct lpass_variant {
u32 wrdma_reg_stride; u32 wrdma_reg_stride;
u32 wrdma_channels; 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 * on SOCs like APQ8016 the channel control bits start
* at different offset to ipq806x * at different offset to ipq806x