From b8e71b991f91323b911c1808d798b588349d85aa Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 11 Jul 2013 10:24:17 +0100 Subject: ALSA: ASoC: convert sa11x0 ssp driver to generic ASoC dmaengine support Signed-off-by: Russell King --- sound/soc/sa11x0/Kconfig | 2 +- sound/soc/sa11x0/ssp.c | 106 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/sound/soc/sa11x0/Kconfig b/sound/soc/sa11x0/Kconfig index f18fe9faa76d..ae7930842e07 100644 --- a/sound/soc/sa11x0/Kconfig +++ b/sound/soc/sa11x0/Kconfig @@ -1,7 +1,7 @@ config SND_SOC_SA11X0_SSP tristate depends on DMA_SA11X0 - select SND_SOC_DMAENGINE + select SND_SOC_GENERIC_DMAENGINE_PCM config SND_SA11X0_ASSABET tristate "SoC Audio support for the Intel Assabet board" diff --git a/sound/soc/sa11x0/ssp.c b/sound/soc/sa11x0/ssp.c index 1bdd4310a39d..2656df529f96 100644 --- a/sound/soc/sa11x0/ssp.c +++ b/sound/soc/sa11x0/ssp.c @@ -22,9 +22,9 @@ #include #include +#include #include #include -#include #include #include "ssp.h" @@ -43,6 +43,12 @@ (SNDRV_PCM_FORMAT_S8 | SNDRV_PCM_FORMAT_U8 | \ SNDRV_PCM_FORMAT_S16_LE | SNDRV_PCM_FORMAT_U16_LE) +#define BUFFER_SIZE_MAX 65536 +#define PERIOD_SIZE_MIN 32 +#define PERIOD_SIZE_MAX 16384 +#define PERIODS_MIN 2 +#define PERIODS_MAX 256 + #define SSCR0 0x60 #define SSCR0_DSS (15 << 0) /* s */ #define SSCR0_FRF_MOT (0 << 4) @@ -65,26 +71,23 @@ struct ssp_priv { unsigned long clk_hz; u32 cr0; u32 cr1; + struct snd_dmaengine_dai_dma_data tx; + struct snd_dmaengine_dai_dma_data rx; }; -static struct soc_dma_config sa11x0_tx_cfg = { - .filter = sa11x0_dma_filter_fn, - .data = "Ser4SSPTr", - .reg = 0x80070000 + SSDR, - .width = DMA_SLAVE_BUSWIDTH_2_BYTES, - .maxburst = 4, - .align = 32, - .fifo_size = 2 * 8, -}; - -static struct soc_dma_config sa11x0_rx_cfg = { - .filter = sa11x0_dma_filter_fn, - .data = "Ser4SSPRc", - .reg = 0x80070000 + SSDR, - .width = DMA_SLAVE_BUSWIDTH_2_BYTES, - .maxburst = 4, - .align = 32, - .fifo_size = 2 * 12, +static const struct snd_pcm_hardware sa11x0_ssp_pcm_hardware = { + .info = SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_RESUME, + .period_bytes_min = PERIOD_SIZE_MIN, + .period_bytes_max = PERIOD_SIZE_MAX, + .periods_min = PERIODS_MIN, + .periods_max = PERIODS_MAX, + .buffer_bytes_max = BUFFER_SIZE_MAX, + /* This is for playback only */ + .fifo_size = 8 * 2, }; /* @@ -115,6 +118,24 @@ static int sa11x0_ssp_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct ssp_priv *ssp = snd_soc_dai_get_drvdata(dai); + int ret; + + ret = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32); + if (ret) + return ret; + + ret = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32); + if (ret) + return ret; + + ret = snd_pcm_hw_rule_add(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, sa11x0_ssp_rate_constraint, ssp, + SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_FORMAT, + SNDRV_PCM_HW_PARAM_CHANNELS, -1); + if (ret) + return ret; if (!dai->active) { writel_relaxed(ssp->cr0, ssp->base + SSCR0); @@ -123,11 +144,6 @@ sa11x0_ssp_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) writel_relaxed(ssp->cr0, ssp->base + SSCR0); } - snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - sa11x0_ssp_rate_constraint, ssp, - SNDRV_PCM_HW_PARAM_RATE, SNDRV_PCM_HW_PARAM_FORMAT, - SNDRV_PCM_HW_PARAM_CHANNELS, -1); - return 0; } @@ -249,8 +265,8 @@ static int sa11x0_ssp_probe(struct snd_soc_dai *dai) * obtain its DMA channel, in turn its struct device, and therefore * a struct device to allocate DMA memory against. */ - dai->playback_dma_data = &sa11x0_tx_cfg; - dai->capture_dma_data = &sa11x0_rx_cfg; + dai->playback_dma_data = &ssp->tx; + dai->capture_dma_data = &ssp->rx; return 0; } @@ -311,10 +327,17 @@ static const struct snd_soc_component_driver sa11x0_ssp_component = { .name = "sa11x0-ssp", }; +static const struct snd_dmaengine_pcm_config sa11x0_ssp_pcm_config = { + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, + .pcm_hardware = &sa11x0_ssp_pcm_hardware, + .prealloc_buffer_size = SZ_64K, +}; + static int sa11x0_ssp_plat_probe(struct platform_device *pdev) { struct ssp_priv *ssp; struct resource *res; + int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -327,6 +350,22 @@ static int sa11x0_ssp_plat_probe(struct platform_device *pdev) /* Assume internal clock, as that's what we program initially */ ssp->clk_hz = 3686400; + /* + * FIXME: The generic ASoC dmaengine backend does not allow us to set + * a different FIFO size for the transmit and receive sides of the + * SSP: the transmit has a 8 x 16bit FIFO, but the receive side has + * a 12 x 16bit FIFO. + */ + ssp->tx.addr = res->start + SSDR; + ssp->tx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + ssp->tx.maxburst = 4; + ssp->tx.filter_data = "Ser4SSPTr"; + + ssp->rx.addr = res->start + SSDR; + ssp->rx.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + ssp->rx.maxburst = 4; + ssp->rx.filter_data = "Ser4SSPRc"; + ssp->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ssp->base)) return PTR_ERR(ssp->base); @@ -335,13 +374,24 @@ static int sa11x0_ssp_plat_probe(struct platform_device *pdev) writel_relaxed(ssp->cr1, ssp->base + SSCR1); platform_set_drvdata(pdev, ssp); - return snd_soc_register_component(&pdev->dev, &sa11x0_ssp_component, - &sa11x0_ssp_driver, 1); + + ret = snd_dmaengine_pcm_register(&pdev->dev, &sa11x0_ssp_pcm_config, + SND_DMAENGINE_PCM_FLAG_COMPAT); + if (ret) + return ret; + + ret = snd_soc_register_component(&pdev->dev, &sa11x0_ssp_component, + &sa11x0_ssp_driver, 1); + if (ret) + snd_dmaengine_pcm_unregister(&pdev->dev); + + return ret; } static int sa11x0_ssp_plat_remove(struct platform_device *pdev) { snd_soc_unregister_component(&pdev->dev); + snd_dmaengine_pcm_unregister(&pdev->dev); return 0; } -- cgit