summaryrefslogtreecommitdiffstats
path: root/sound/soc/qcom/lpass-cpu.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/qcom/lpass-cpu.c')
-rw-r--r--sound/soc/qcom/lpass-cpu.c204
1 files changed, 113 insertions, 91 deletions
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c
index e00a4af29c13..1ee6d8b3f550 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,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",
@@ -209,41 +266,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 +292,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 +315,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 +335,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,
};
@@ -545,7 +575,7 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
of_lpass_cpu_parse_dai_data(dev, drvdata);
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-lpaif");
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
drvdata->lpaif = devm_ioremap_resource(dev, res);
if (IS_ERR((void const __force *)drvdata->lpaif)) {
@@ -566,8 +596,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
return PTR_ERR(drvdata->lpaif_map);
}
- if (variant->init)
- variant->init(pdev);
+ if (variant->init) {
+ ret = variant->init(pdev);
+ if (ret) {
+ dev_err(dev, "error initializing variant: %d\n", ret);
+ return ret;
+ }
+ }
for (i = 0; i < variant->num_dai; i++) {
dai_id = variant->dai_driver[i].id;
@@ -594,24 +629,15 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
}
}
- drvdata->ahbix_clk = devm_clk_get(dev, "ahbix-clk");
- if (IS_ERR(drvdata->ahbix_clk)) {
- dev_err(dev, "error getting ahbix-clk: %ld\n",
- PTR_ERR(drvdata->ahbix_clk));
- return PTR_ERR(drvdata->ahbix_clk);
- }
+ /* Allocation for i2sctl regmap fields */
+ drvdata->i2sctl = devm_kzalloc(&pdev->dev, sizeof(struct lpaif_i2sctl),
+ GFP_KERNEL);
- ret = clk_set_rate(drvdata->ahbix_clk, LPASS_AHBIX_CLOCK_FREQUENCY);
+ /* Initialize bitfields for dai I2SCTL register */
+ ret = lpass_cpu_init_i2sctl_bitfields(dev, drvdata->i2sctl,
+ drvdata->lpaif_map);
if (ret) {
- dev_err(dev, "error setting rate on ahbix_clk: %d\n", ret);
- return ret;
- }
- dev_dbg(dev, "set ahbix_clk rate to %lu\n",
- clk_get_rate(drvdata->ahbix_clk));
-
- ret = clk_prepare_enable(drvdata->ahbix_clk);
- if (ret) {
- dev_err(dev, "error enabling ahbix_clk: %d\n", ret);
+ dev_err(dev, "error init i2sctl field: %d\n", ret);
return ret;
}
@@ -621,19 +647,16 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
variant->num_dai);
if (ret) {
dev_err(dev, "error registering cpu driver: %d\n", ret);
- goto err_clk;
+ goto err;
}
ret = asoc_qcom_lpass_platform_register(pdev);
if (ret) {
dev_err(dev, "error registering platform driver: %d\n", ret);
- goto err_clk;
+ goto err;
}
- return 0;
-
-err_clk:
- clk_disable_unprepare(drvdata->ahbix_clk);
+err:
return ret;
}
EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_platform_probe);
@@ -645,7 +668,6 @@ int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev)
if (drvdata->variant->exit)
drvdata->variant->exit(pdev);
- clk_disable_unprepare(drvdata->ahbix_clk);
return 0;
}