summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2013-07-11 10:24:17 +0100
committerRussell King <rmk+kernel@armlinux.org.uk>2020-10-12 21:52:50 +0100
commitb8e71b991f91323b911c1808d798b588349d85aa (patch)
tree5dcc33d2adf033d7a9ef1a77f73ddd823ecd2c56
parented633ccbc7266d10595c952019075eea094cd544 (diff)
ALSA: ASoC: convert sa11x0 ssp driver to generic ASoC dmaengine support
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--sound/soc/sa11x0/Kconfig2
-rw-r--r--sound/soc/sa11x0/ssp.c106
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 <linux/slab.h>
#include <sound/core.h>
+#include <sound/dmaengine_pcm.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
-#include <sound/soc-dmaengine.h>
#include <sound/soc.h>
#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;
}