ASoC: fsl_ssi: Add dual fifo mode support
By enabling dual fifo mode, it would allow SSI enter a better performance to transimit/receive data without occasional hardware underrun/overrun. Signed-off-by: Nicolin Chen <b42378@freescale.com> Acked-by: Timur Tabi <timur@tabi.org> Acked-by: Mark Brown <broonie@linaro.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
This commit is contained in:
parent
b1d27c79c8
commit
0da9e55e71
|
@ -143,6 +143,7 @@ struct fsl_ssi_private {
|
||||||
bool ssi_on_imx;
|
bool ssi_on_imx;
|
||||||
bool imx_ac97;
|
bool imx_ac97;
|
||||||
bool use_dma;
|
bool use_dma;
|
||||||
|
bool use_dual_fifo;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
struct snd_dmaengine_dai_dma_data dma_params_tx;
|
||||||
struct snd_dmaengine_dai_dma_data dma_params_rx;
|
struct snd_dmaengine_dai_dma_data dma_params_rx;
|
||||||
|
@ -413,6 +414,12 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
|
||||||
write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
|
write_ssi(CCSR_SSI_SOR_WAIT(3), &ssi->sor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ssi_private->use_dual_fifo) {
|
||||||
|
write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1);
|
||||||
|
write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1);
|
||||||
|
write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,6 +487,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
|
||||||
ssi_private->second_stream = substream;
|
ssi_private->second_stream = substream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When using dual fifo mode, it is safer to ensure an even period
|
||||||
|
* size. If appearing to an odd number while DMA always starts its
|
||||||
|
* task from fifo0, fifo1 would be neglected at the end of each
|
||||||
|
* period. But SSI would still access fifo1 with an invalid data.
|
||||||
|
*/
|
||||||
|
if (ssi_private->use_dual_fifo)
|
||||||
|
snd_pcm_hw_constraint_step(substream->runtime, 0,
|
||||||
|
SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,7 +963,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||||
ssi_private->fifo_depth = 8;
|
ssi_private->fifo_depth = 8;
|
||||||
|
|
||||||
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
|
if (of_device_is_compatible(pdev->dev.of_node, "fsl,imx21-ssi")) {
|
||||||
u32 dma_events[2];
|
u32 dma_events[2], dmas[4];
|
||||||
ssi_private->ssi_on_imx = true;
|
ssi_private->ssi_on_imx = true;
|
||||||
|
|
||||||
ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
|
ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
|
@ -1001,6 +1017,15 @@ static int fsl_ssi_probe(struct platform_device *pdev)
|
||||||
dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
|
dma_events[0], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
|
||||||
imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
|
imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
|
||||||
dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
|
dma_events[1], shared ? IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI);
|
||||||
|
if (!of_property_read_u32_array(pdev->dev.of_node, "dmas", dmas, 4)
|
||||||
|
&& dmas[2] == IMX_DMATYPE_SSI_DUAL) {
|
||||||
|
ssi_private->use_dual_fifo = true;
|
||||||
|
/* When using dual fifo mode, we need to keep watermark
|
||||||
|
* as even numbers due to dma script limitation.
|
||||||
|
*/
|
||||||
|
ssi_private->dma_params_tx.maxburst &= ~0x1;
|
||||||
|
ssi_private->dma_params_rx.maxburst &= ~0x1;
|
||||||
|
}
|
||||||
} else if (ssi_private->use_dma) {
|
} else if (ssi_private->use_dma) {
|
||||||
/* The 'name' should not have any slashes in it. */
|
/* The 'name' should not have any slashes in it. */
|
||||||
ret = devm_request_irq(&pdev->dev, ssi_private->irq,
|
ret = devm_request_irq(&pdev->dev, ssi_private->irq,
|
||||||
|
|
Loading…
Reference in New Issue