summaryrefslogtreecommitdiff
path: root/sound/soc/meson/axg-fifo.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/meson/axg-fifo.c')
-rw-r--r--sound/soc/meson/axg-fifo.c61
1 files changed, 47 insertions, 14 deletions
diff --git a/sound/soc/meson/axg-fifo.c b/sound/soc/meson/axg-fifo.c
index d6f3eefb8f09..c12b0d5e8ebf 100644
--- a/sound/soc/meson/axg-fifo.c
+++ b/sound/soc/meson/axg-fifo.c
@@ -34,7 +34,7 @@ static struct snd_pcm_hardware axg_fifo_hw = {
.rate_max = 192000,
.channels_min = 1,
.channels_max = AXG_FIFO_CH_MAX,
- .period_bytes_min = AXG_FIFO_MIN_DEPTH,
+ .period_bytes_min = AXG_FIFO_BURST,
.period_bytes_max = UINT_MAX,
.periods_min = 2,
.periods_max = UINT_MAX,
@@ -113,13 +113,10 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
{
struct snd_pcm_runtime *runtime = ss->runtime;
struct axg_fifo *fifo = axg_fifo_data(ss);
+ unsigned int burst_num, period, threshold;
dma_addr_t end_ptr;
- unsigned int burst_num;
- int ret;
- ret = snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(params));
- if (ret < 0)
- return ret;
+ period = params_period_bytes(params);
/* Setup dma memory pointers */
end_ptr = runtime->dma_addr + runtime->dma_bytes - AXG_FIFO_BURST;
@@ -127,9 +124,24 @@ int axg_fifo_pcm_hw_params(struct snd_soc_component *component,
regmap_write(fifo->map, FIFO_FINISH_ADDR, end_ptr);
/* Setup interrupt periodicity */
- burst_num = params_period_bytes(params) / AXG_FIFO_BURST;
+ burst_num = period / AXG_FIFO_BURST;
regmap_write(fifo->map, FIFO_INT_ADDR, burst_num);
+ /*
+ * Start the fifo request on the smallest of the following:
+ * - Half the fifo size
+ * - Half the period size
+ */
+ threshold = min(period / 2, fifo->depth / 2);
+
+ /*
+ * With the threshold in bytes, register value is:
+ * V = (threshold / burst) - 1
+ */
+ threshold /= AXG_FIFO_BURST;
+ regmap_field_write(fifo->field_threshold,
+ threshold ? threshold - 1 : 0);
+
/* Enable block count irq */
regmap_update_bits(fifo->map, FIFO_CTRL0,
CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT),
@@ -167,7 +179,7 @@ int axg_fifo_pcm_hw_free(struct snd_soc_component *component,
regmap_update_bits(fifo->map, FIFO_CTRL0,
CTRL0_INT_EN(FIFO_INT_COUNT_REPEAT), 0);
- return snd_pcm_lib_free_pages(ss);
+ return 0;
}
EXPORT_SYMBOL_GPL(axg_fifo_pcm_hw_free);
@@ -215,17 +227,17 @@ int axg_fifo_pcm_open(struct snd_soc_component *component,
/*
* Make sure the buffer and period size are multiple of the FIFO
- * minimum depth size
+ * burst
*/
ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
- AXG_FIFO_MIN_DEPTH);
+ AXG_FIFO_BURST);
if (ret)
return ret;
ret = snd_pcm_hw_constraint_step(ss->runtime, 0,
SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
- AXG_FIFO_MIN_DEPTH);
+ AXG_FIFO_BURST);
if (ret)
return ret;
@@ -287,9 +299,9 @@ int axg_fifo_pcm_new(struct snd_soc_pcm_runtime *rtd, unsigned int type)
struct snd_card *card = rtd->card->snd_card;
size_t size = axg_fifo_hw.buffer_bytes_max;
- snd_pcm_lib_preallocate_pages(rtd->pcm->streams[type].substream,
- SNDRV_DMA_TYPE_DEV, card->dev,
- size, size);
+ snd_pcm_set_managed_buffer(rtd->pcm->streams[type].substream,
+ SNDRV_DMA_TYPE_DEV, card->dev,
+ size, size);
return 0;
}
EXPORT_SYMBOL_GPL(axg_fifo_pcm_new);
@@ -307,6 +319,7 @@ int axg_fifo_probe(struct platform_device *pdev)
const struct axg_fifo_match_data *data;
struct axg_fifo *fifo;
void __iomem *regs;
+ int ret;
data = of_device_get_match_data(dev);
if (!data) {
@@ -352,6 +365,26 @@ int axg_fifo_probe(struct platform_device *pdev)
return fifo->irq;
}
+ fifo->field_threshold =
+ devm_regmap_field_alloc(dev, fifo->map, data->field_threshold);
+ if (IS_ERR(fifo->field_threshold))
+ return PTR_ERR(fifo->field_threshold);
+
+ ret = of_property_read_u32(dev->of_node, "amlogic,fifo-depth",
+ &fifo->depth);
+ if (ret) {
+ /* Error out for anything but a missing property */
+ if (ret != -EINVAL)
+ return ret;
+ /*
+ * If the property is missing, it might be because of an old
+ * DT. In such case, assume the smallest known fifo depth
+ */
+ fifo->depth = 256;
+ dev_warn(dev, "fifo depth not found, assume %u bytes\n",
+ fifo->depth);
+ }
+
return devm_snd_soc_register_component(dev, data->component_drv,
data->dai_drv, 1);
}