aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2013-04-18 10:24:31 -0400
committerTakashi Iwai <tiwai@suse.de>2013-04-18 10:24:31 -0400
commit8dd2b66d1a961231685a3bfe5937c85d846fbf5d (patch)
tree8117553488bf4ef09b048a4b343cf37cc16bf46d /sound/soc
parent126825e7ea271ae8e3172e10ca1fc22c908b5385 (diff)
parent24568ea4bef5ab8106206eddf5512434421c00ed (diff)
Merge tag 'asoc-v3.10-2' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next
ASoC: More updates for v3.10 The main additional change here is Lars-Peter's DMA work plus the platform conversions which have been tested - getting this in mainline will make life easier for development after the merge window. These factor a large chunk of code out of the drivers for the platforms using dmaengine, greatly simplifying development.
Diffstat (limited to 'sound/soc')
-rw-r--r--sound/soc/Kconfig4
-rw-r--r--sound/soc/Makefile4
-rw-r--r--sound/soc/atmel/atmel-pcm-dma.c6
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.c5
-rw-r--r--sound/soc/codecs/max98088.c2
-rw-r--r--sound/soc/fsl/Kconfig2
-rw-r--r--sound/soc/fsl/fsl_ssi.c19
-rw-r--r--sound/soc/fsl/fsl_ssi.h8
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c76
-rw-r--r--sound/soc/fsl/imx-pcm.c6
-rw-r--r--sound/soc/fsl/imx-pcm.h5
-rw-r--r--sound/soc/fsl/imx-ssi.c22
-rw-r--r--sound/soc/mxs/mxs-pcm.c4
-rw-r--r--sound/soc/omap/omap-pcm.c7
-rw-r--r--sound/soc/pxa/mmp-pcm.c5
-rw-r--r--sound/soc/soc-core.c85
-rw-r--r--sound/soc/soc-dmaengine-pcm.c82
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c284
-rw-r--r--sound/soc/soc-utils.c25
-rw-r--r--sound/soc/spear/spear_pcm.c5
-rw-r--r--sound/soc/tegra/Kconfig2
-rw-r--r--sound/soc/tegra/tegra_pcm.c171
-rw-r--r--sound/soc/ux500/Kconfig2
-rw-r--r--sound/soc/ux500/ux500_pcm.c159
24 files changed, 536 insertions, 454 deletions
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
index 5da8ca7aee05..9e675c76436c 100644
--- a/sound/soc/Kconfig
+++ b/sound/soc/Kconfig
@@ -29,6 +29,10 @@ config SND_SOC_AC97_BUS
29config SND_SOC_DMAENGINE_PCM 29config SND_SOC_DMAENGINE_PCM
30 bool 30 bool
31 31
32config SND_SOC_GENERIC_DMAENGINE_PCM
33 bool
34 select SND_SOC_DMAENGINE_PCM
35
32# All the supported SoCs 36# All the supported SoCs
33source "sound/soc/atmel/Kconfig" 37source "sound/soc/atmel/Kconfig"
34source "sound/soc/au1x/Kconfig" 38source "sound/soc/au1x/Kconfig"
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index 99f32f7c0692..197b6ae54c8d 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -5,6 +5,10 @@ ifneq ($(CONFIG_SND_SOC_DMAENGINE_PCM),)
5snd-soc-core-objs += soc-dmaengine-pcm.o 5snd-soc-core-objs += soc-dmaengine-pcm.o
6endif 6endif
7 7
8ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
9snd-soc-core-objs += soc-generic-dmaengine-pcm.o
10endif
11
8obj-$(CONFIG_SND_SOC) += snd-soc-core.o 12obj-$(CONFIG_SND_SOC) += snd-soc-core.o
9obj-$(CONFIG_SND_SOC) += codecs/ 13obj-$(CONFIG_SND_SOC) += codecs/
10obj-$(CONFIG_SND_SOC) += generic/ 14obj-$(CONFIG_SND_SOC) += generic/
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
index bb07989762d5..1d38fd0bc4e2 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -155,7 +155,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
155 if (ssc->pdev) 155 if (ssc->pdev)
156 sdata = ssc->pdev->dev.platform_data; 156 sdata = ssc->pdev->dev.platform_data;
157 157
158 ret = snd_dmaengine_pcm_open(substream, filter, sdata); 158 ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata);
159 if (ret) { 159 if (ret) {
160 pr_err("atmel-pcm: dmaengine pcm open failed\n"); 160 pr_err("atmel-pcm: dmaengine pcm open failed\n");
161 return -EINVAL; 161 return -EINVAL;
@@ -171,7 +171,7 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
171 171
172 return 0; 172 return 0;
173err: 173err:
174 snd_dmaengine_pcm_close(substream); 174 snd_dmaengine_pcm_close_release_chan(substream);
175 return ret; 175 return ret;
176} 176}
177 177
@@ -197,7 +197,7 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
197 197
198static struct snd_pcm_ops atmel_pcm_ops = { 198static struct snd_pcm_ops atmel_pcm_ops = {
199 .open = atmel_pcm_open, 199 .open = atmel_pcm_open,
200 .close = snd_dmaengine_pcm_close, 200 .close = snd_dmaengine_pcm_close_release_chan,
201 .ioctl = snd_pcm_lib_ioctl, 201 .ioctl = snd_pcm_lib_ioctl,
202 .hw_params = atmel_pcm_hw_params, 202 .hw_params = atmel_pcm_hw_params,
203 .prepare = atmel_pcm_dma_prepare, 203 .prepare = atmel_pcm_dma_prepare,
diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c
index 298946f790eb..488032690378 100644
--- a/sound/soc/cirrus/ep93xx-pcm.c
+++ b/sound/soc/cirrus/ep93xx-pcm.c
@@ -69,7 +69,8 @@ static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
69 69
70 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); 70 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
71 71
72 return snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, 72 return snd_dmaengine_pcm_open_request_chan(substream,
73 ep93xx_pcm_dma_filter,
73 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); 74 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
74} 75}
75 76
@@ -100,7 +101,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
100 101
101static struct snd_pcm_ops ep93xx_pcm_ops = { 102static struct snd_pcm_ops ep93xx_pcm_ops = {
102 .open = ep93xx_pcm_open, 103 .open = ep93xx_pcm_open,
103 .close = snd_dmaengine_pcm_close, 104 .close = snd_dmaengine_pcm_close_release_chan,
104 .ioctl = snd_pcm_lib_ioctl, 105 .ioctl = snd_pcm_lib_ioctl,
105 .hw_params = ep93xx_pcm_hw_params, 106 .hw_params = ep93xx_pcm_hw_params,
106 .hw_free = ep93xx_pcm_hw_free, 107 .hw_free = ep93xx_pcm_hw_free,
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 3a7b7fd14e3e..3eeada57e87d 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -2024,7 +2024,7 @@ static int max98088_probe(struct snd_soc_codec *codec)
2024 ret); 2024 ret);
2025 goto err_access; 2025 goto err_access;
2026 } 2026 }
2027 dev_info(codec->dev, "revision %c\n", ret + 'A'); 2027 dev_info(codec->dev, "revision %c\n", ret - 0x40 + 'A');
2028 2028
2029 snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV); 2029 snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
2030 2030
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig
index 3b98159d9645..3843a18d4e56 100644
--- a/sound/soc/fsl/Kconfig
+++ b/sound/soc/fsl/Kconfig
@@ -118,7 +118,7 @@ config SND_SOC_IMX_PCM_FIQ
118 118
119config SND_SOC_IMX_PCM_DMA 119config SND_SOC_IMX_PCM_DMA
120 bool 120 bool
121 select SND_SOC_DMAENGINE_PCM 121 select SND_SOC_GENERIC_DMAENGINE_PCM
122 select SND_SOC_IMX_PCM 122 select SND_SOC_IMX_PCM
123 123
124config SND_SOC_IMX_AUDMUX 124config SND_SOC_IMX_AUDMUX
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index 42366d776f62..0f0bed6def9e 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -425,12 +425,6 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
425 ssi_private->second_stream = substream; 425 ssi_private->second_stream = substream;
426 } 426 }
427 427
428 if (ssi_private->ssi_on_imx)
429 snd_soc_dai_set_dma_data(dai, substream,
430 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
431 &ssi_private->dma_params_tx :
432 &ssi_private->dma_params_rx);
433
434 return 0; 428 return 0;
435} 429}
436 430
@@ -552,6 +546,18 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
552 } 546 }
553} 547}
554 548
549static int fsl_ssi_dai_probe(struct snd_soc_dai *dai)
550{
551 struct fsl_ssi_private *ssi_private = snd_soc_dai_get_drvdata(dai);
552
553 if (ssi_private->ssi_on_imx) {
554 dai->playback_dma_data = &ssi_private->dma_params_tx;
555 dai->capture_dma_data = &ssi_private->dma_params_rx;
556 }
557
558 return 0;
559}
560
555static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { 561static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
556 .startup = fsl_ssi_startup, 562 .startup = fsl_ssi_startup,
557 .hw_params = fsl_ssi_hw_params, 563 .hw_params = fsl_ssi_hw_params,
@@ -561,6 +567,7 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
561 567
562/* Template for the CPU dai driver structure */ 568/* Template for the CPU dai driver structure */
563static struct snd_soc_dai_driver fsl_ssi_dai_template = { 569static struct snd_soc_dai_driver fsl_ssi_dai_template = {
570 .probe = fsl_ssi_dai_probe,
564 .playback = { 571 .playback = {
565 /* The SSI does not support monaural audio. */ 572 /* The SSI does not support monaural audio. */
566 .channels_min = 2, 573 .channels_min = 2,
diff --git a/sound/soc/fsl/fsl_ssi.h b/sound/soc/fsl/fsl_ssi.h
index 217300029b5b..e6b9a69e2a68 100644
--- a/sound/soc/fsl/fsl_ssi.h
+++ b/sound/soc/fsl/fsl_ssi.h
@@ -196,5 +196,13 @@ struct ccsr_ssi {
196#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT) 196#define CCSR_SSI_SOR_WAIT(x) (((x) & 3) << CCSR_SSI_SOR_WAIT_SHIFT)
197#define CCSR_SSI_SOR_SYNRST 0x00000001 197#define CCSR_SSI_SOR_SYNRST 0x00000001
198 198
199#define CCSR_SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5)
200#define CCSR_SSI_SACNT_WR 0x00000010
201#define CCSR_SSI_SACNT_RD 0x00000008
202#define CCSR_SSI_SACNT_RDWR_MASK 0x00000018
203#define CCSR_SSI_SACNT_TIF 0x00000004
204#define CCSR_SSI_SACNT_FV 0x00000002
205#define CCSR_SSI_SACNT_AC97EN 0x00000001
206
199#endif 207#endif
200 208
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index ee838c8a3b11..c246fb514930 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -11,22 +11,12 @@
11 * Free Software Foundation; either version 2 of the License, or (at your 11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version. 12 * option) any later version.
13 */ 13 */
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/device.h>
17#include <linux/dma-mapping.h>
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/platform_device.h> 14#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <linux/dmaengine.h> 15#include <linux/dmaengine.h>
24#include <linux/types.h> 16#include <linux/types.h>
25 17
26#include <sound/core.h> 18#include <sound/core.h>
27#include <sound/initval.h>
28#include <sound/pcm.h> 19#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/soc.h> 20#include <sound/soc.h>
31#include <sound/dmaengine_pcm.h> 21#include <sound/dmaengine_pcm.h>
32 22
@@ -44,32 +34,7 @@ static bool filter(struct dma_chan *chan, void *param)
44 return true; 34 return true;
45} 35}
46 36
47static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream, 37static const struct snd_pcm_hardware imx_pcm_hardware = {
48 struct snd_pcm_hw_params *params)
49{
50 struct snd_soc_pcm_runtime *rtd = substream->private_data;
51 struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
52 struct dma_slave_config slave_config;
53 int ret;
54
55 ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
56 if (ret)
57 return ret;
58
59 snd_dmaengine_pcm_set_config_from_dai_data(substream,
60 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
61 &slave_config);
62
63 ret = dmaengine_slave_config(chan, &slave_config);
64 if (ret)
65 return ret;
66
67 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
68
69 return 0;
70}
71
72static struct snd_pcm_hardware snd_imx_hardware = {
73 .info = SNDRV_PCM_INFO_INTERLEAVED | 38 .info = SNDRV_PCM_INFO_INTERLEAVED |
74 SNDRV_PCM_INFO_BLOCK_TRANSFER | 39 SNDRV_PCM_INFO_BLOCK_TRANSFER |
75 SNDRV_PCM_INFO_MMAP | 40 SNDRV_PCM_INFO_MMAP |
@@ -88,33 +53,22 @@ static struct snd_pcm_hardware snd_imx_hardware = {
88 .fifo_size = 0, 53 .fifo_size = 0,
89}; 54};
90 55
91static int snd_imx_open(struct snd_pcm_substream *substream) 56static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = {
92{ 57 .pcm_hardware = &imx_pcm_hardware,
93 struct snd_soc_pcm_runtime *rtd = substream->private_data; 58 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
94 59 .compat_filter_fn = filter,
95 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware); 60 .prealloc_buffer_size = IMX_SSI_DMABUF_SIZE,
96
97 return snd_dmaengine_pcm_open(substream, filter,
98 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
99}
100
101static struct snd_pcm_ops imx_pcm_ops = {
102 .open = snd_imx_open,
103 .close = snd_dmaengine_pcm_close,
104 .ioctl = snd_pcm_lib_ioctl,
105 .hw_params = snd_imx_pcm_hw_params,
106 .trigger = snd_dmaengine_pcm_trigger,
107 .pointer = snd_dmaengine_pcm_pointer_no_residue,
108 .mmap = snd_imx_pcm_mmap,
109};
110
111static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
112 .ops = &imx_pcm_ops,
113 .pcm_new = imx_pcm_new,
114 .pcm_free = imx_pcm_free,
115}; 61};
116 62
117int imx_pcm_dma_init(struct platform_device *pdev) 63int imx_pcm_dma_init(struct platform_device *pdev)
118{ 64{
119 return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2); 65 return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
66 SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
67 SND_DMAENGINE_PCM_FLAG_NO_DT |
68 SND_DMAENGINE_PCM_FLAG_COMPAT);
69}
70
71void imx_pcm_dma_exit(struct platform_device *pdev)
72{
73 snd_dmaengine_pcm_unregister(&pdev->dev);
120} 74}
diff --git a/sound/soc/fsl/imx-pcm.c b/sound/soc/fsl/imx-pcm.c
index 0d0625bfcb65..c49896442d8e 100644
--- a/sound/soc/fsl/imx-pcm.c
+++ b/sound/soc/fsl/imx-pcm.c
@@ -114,7 +114,11 @@ static int imx_pcm_probe(struct platform_device *pdev)
114 114
115static int imx_pcm_remove(struct platform_device *pdev) 115static int imx_pcm_remove(struct platform_device *pdev)
116{ 116{
117 snd_soc_unregister_platform(&pdev->dev); 117 if (strcmp(pdev->id_entry->name, "imx-fiq-pcm-audio") == 0)
118 snd_soc_unregister_platform(&pdev->dev);
119 else
120 imx_pcm_dma_exit(pdev);
121
118 return 0; 122 return 0;
119} 123}
120 124
diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h
index be9cc64a208b..b7fa0d75c687 100644
--- a/sound/soc/fsl/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -39,11 +39,16 @@ void imx_pcm_free(struct snd_pcm *pcm);
39 39
40#ifdef CONFIG_SND_SOC_IMX_PCM_DMA 40#ifdef CONFIG_SND_SOC_IMX_PCM_DMA
41int imx_pcm_dma_init(struct platform_device *pdev); 41int imx_pcm_dma_init(struct platform_device *pdev);
42void imx_pcm_dma_exit(struct platform_device *pdev);
42#else 43#else
43static inline int imx_pcm_dma_init(struct platform_device *pdev) 44static inline int imx_pcm_dma_init(struct platform_device *pdev)
44{ 45{
45 return -ENODEV; 46 return -ENODEV;
46} 47}
48
49static inline void imx_pcm_dma_exit(struct platform_device *pdev)
50{
51}
47#endif 52#endif
48 53
49#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ 54#ifdef CONFIG_SND_SOC_IMX_PCM_FIQ
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index 4ce2d608b37a..902fab02b851 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -232,23 +232,6 @@ static int imx_ssi_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
232 return 0; 232 return 0;
233} 233}
234 234
235static int imx_ssi_startup(struct snd_pcm_substream *substream,
236 struct snd_soc_dai *cpu_dai)
237{
238 struct imx_ssi *ssi = snd_soc_dai_get_drvdata(cpu_dai);
239 struct snd_dmaengine_dai_dma_data *dma_data;
240
241 /* Tx/Rx config */
242 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
243 dma_data = &ssi->dma_params_tx;
244 else
245 dma_data = &ssi->dma_params_rx;
246
247 snd_soc_dai_set_dma_data(cpu_dai, substream, dma_data);
248
249 return 0;
250}
251
252/* 235/*
253 * Should only be called when port is inactive (i.e. SSIEN = 0), 236 * Should only be called when port is inactive (i.e. SSIEN = 0),
254 * although can be called multiple times by upper layers. 237 * although can be called multiple times by upper layers.
@@ -353,7 +336,6 @@ static int imx_ssi_trigger(struct snd_pcm_substream *substream, int cmd,
353} 336}
354 337
355static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = { 338static const struct snd_soc_dai_ops imx_ssi_pcm_dai_ops = {
356 .startup = imx_ssi_startup,
357 .hw_params = imx_ssi_hw_params, 339 .hw_params = imx_ssi_hw_params,
358 .set_fmt = imx_ssi_set_dai_fmt, 340 .set_fmt = imx_ssi_set_dai_fmt,
359 .set_clkdiv = imx_ssi_set_dai_clkdiv, 341 .set_clkdiv = imx_ssi_set_dai_clkdiv,
@@ -373,6 +355,10 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
373 SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst); 355 SSI_SFCSR_RFWM0(ssi->dma_params_rx.maxburst);
374 writel(val, ssi->base + SSI_SFCSR); 356 writel(val, ssi->base + SSI_SFCSR);
375 357
358 /* Tx/Rx config */
359 dai->playback_dma_data = &ssi->dma_params_tx;
360 dai->capture_dma_data = &ssi->dma_params_rx;
361
376 return 0; 362 return 0;
377} 363}
378 364
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index ebbef8597554..7bceb16d0fd9 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -87,7 +87,7 @@ static int snd_mxs_open(struct snd_pcm_substream *substream)
87 87
88 snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); 88 snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
89 89
90 return snd_dmaengine_pcm_open(substream, filter, 90 return snd_dmaengine_pcm_open_request_chan(substream, filter,
91 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream)); 91 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
92} 92}
93 93
@@ -104,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
104 104
105static struct snd_pcm_ops mxs_pcm_ops = { 105static struct snd_pcm_ops mxs_pcm_ops = {
106 .open = snd_mxs_open, 106 .open = snd_mxs_open,
107 .close = snd_dmaengine_pcm_close, 107 .close = snd_dmaengine_pcm_close_release_chan,
108 .ioctl = snd_pcm_lib_ioctl, 108 .ioctl = snd_pcm_lib_ioctl,
109 .hw_params = snd_mxs_pcm_hw_params, 109 .hw_params = snd_mxs_pcm_hw_params,
110 .trigger = snd_dmaengine_pcm_trigger, 110 .trigger = snd_dmaengine_pcm_trigger,
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index c8e272f9c2de..c28e042f2208 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -118,8 +118,9 @@ static int omap_pcm_open(struct snd_pcm_substream *substream)
118 118
119 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); 119 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
120 120
121 return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn, 121 return snd_dmaengine_pcm_open_request_chan(substream,
122 dma_data->filter_data); 122 omap_dma_filter_fn,
123 dma_data->filter_data);
123} 124}
124 125
125static int omap_pcm_mmap(struct snd_pcm_substream *substream, 126static int omap_pcm_mmap(struct snd_pcm_substream *substream,
@@ -135,7 +136,7 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
135 136
136static struct snd_pcm_ops omap_pcm_ops = { 137static struct snd_pcm_ops omap_pcm_ops = {
137 .open = omap_pcm_open, 138 .open = omap_pcm_open,
138 .close = snd_dmaengine_pcm_close, 139 .close = snd_dmaengine_pcm_close_release_chan,
139 .ioctl = snd_pcm_lib_ioctl, 140 .ioctl = snd_pcm_lib_ioctl,
140 .hw_params = omap_pcm_hw_params, 141 .hw_params = omap_pcm_hw_params,
141 .hw_free = omap_pcm_hw_free, 142 .hw_free = omap_pcm_hw_free,
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 6c3980252bf6..349930015264 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -131,7 +131,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
131 dma_data.dma_res = r; 131 dma_data.dma_res = r;
132 dma_data.ssp_id = cpu_dai->id; 132 dma_data.ssp_id = cpu_dai->id;
133 133
134 return snd_dmaengine_pcm_open(substream, filter, &dma_data); 134 return snd_dmaengine_pcm_open_request_chan(substream, filter,
135 &dma_data);
135} 136}
136 137
137static int mmp_pcm_mmap(struct snd_pcm_substream *substream, 138static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
@@ -148,7 +149,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
148 149
149struct snd_pcm_ops mmp_pcm_ops = { 150struct snd_pcm_ops mmp_pcm_ops = {
150 .open = mmp_pcm_open, 151 .open = mmp_pcm_open,
151 .close = snd_dmaengine_pcm_close, 152 .close = snd_dmaengine_pcm_close_release_chan,
152 .ioctl = snd_pcm_lib_ioctl, 153 .ioctl = snd_pcm_lib_ioctl,
153 .hw_params = mmp_pcm_hw_params, 154 .hw_params = mmp_pcm_hw_params,
154 .trigger = snd_dmaengine_pcm_trigger, 155 .trigger = snd_dmaengine_pcm_trigger,
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 7bf21a1035ea..d56bbea6e75e 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3900,21 +3900,14 @@ static void snd_soc_unregister_dais(struct device *dev, size_t count)
3900} 3900}
3901 3901
3902/** 3902/**
3903 * snd_soc_register_platform - Register a platform with the ASoC core 3903 * snd_soc_add_platform - Add a platform to the ASoC core
3904 * 3904 * @dev: The parent device for the platform
3905 * @platform: platform to register 3905 * @platform: The platform to add
3906 * @platform_driver: The driver for the platform
3906 */ 3907 */
3907int snd_soc_register_platform(struct device *dev, 3908int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
3908 const struct snd_soc_platform_driver *platform_drv) 3909 const struct snd_soc_platform_driver *platform_drv)
3909{ 3910{
3910 struct snd_soc_platform *platform;
3911
3912 dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
3913
3914 platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
3915 if (platform == NULL)
3916 return -ENOMEM;
3917
3918 /* create platform component name */ 3911 /* create platform component name */
3919 platform->name = fmt_single_name(dev, &platform->id); 3912 platform->name = fmt_single_name(dev, &platform->id);
3920 if (platform->name == NULL) { 3913 if (platform->name == NULL) {
@@ -3937,30 +3930,76 @@ int snd_soc_register_platform(struct device *dev,
3937 3930
3938 return 0; 3931 return 0;
3939} 3932}
3940EXPORT_SYMBOL_GPL(snd_soc_register_platform); 3933EXPORT_SYMBOL_GPL(snd_soc_add_platform);
3941 3934
3942/** 3935/**
3943 * snd_soc_unregister_platform - Unregister a platform from the ASoC core 3936 * snd_soc_register_platform - Register a platform with the ASoC core
3944 * 3937 *
3945 * @platform: platform to unregister 3938 * @platform: platform to register
3946 */ 3939 */
3947void snd_soc_unregister_platform(struct device *dev) 3940int snd_soc_register_platform(struct device *dev,
3941 const struct snd_soc_platform_driver *platform_drv)
3948{ 3942{
3949 struct snd_soc_platform *platform; 3943 struct snd_soc_platform *platform;
3944 int ret;
3950 3945
3951 list_for_each_entry(platform, &platform_list, list) { 3946 dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
3952 if (dev == platform->dev)
3953 goto found;
3954 }
3955 return;
3956 3947
3957found: 3948 platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
3949 if (platform == NULL)
3950 return -ENOMEM;
3951
3952 ret = snd_soc_add_platform(dev, platform, platform_drv);
3953 if (ret)
3954 kfree(platform);
3955
3956 return ret;
3957}
3958EXPORT_SYMBOL_GPL(snd_soc_register_platform);
3959
3960/**
3961 * snd_soc_remove_platform - Remove a platform from the ASoC core
3962 * @platform: the platform to remove
3963 */
3964void snd_soc_remove_platform(struct snd_soc_platform *platform)
3965{
3958 mutex_lock(&client_mutex); 3966 mutex_lock(&client_mutex);
3959 list_del(&platform->list); 3967 list_del(&platform->list);
3960 mutex_unlock(&client_mutex); 3968 mutex_unlock(&client_mutex);
3961 3969
3962 dev_dbg(dev, "ASoC: Unregistered platform '%s'\n", platform->name); 3970 dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n",
3971 platform->name);
3963 kfree(platform->name); 3972 kfree(platform->name);
3973}
3974EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
3975
3976struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
3977{
3978 struct snd_soc_platform *platform;
3979
3980 list_for_each_entry(platform, &platform_list, list) {
3981 if (dev == platform->dev)
3982 return platform;
3983 }
3984
3985 return NULL;
3986}
3987EXPORT_SYMBOL_GPL(snd_soc_lookup_platform);
3988
3989/**
3990 * snd_soc_unregister_platform - Unregister a platform from the ASoC core
3991 *
3992 * @platform: platform to unregister
3993 */
3994void snd_soc_unregister_platform(struct device *dev)
3995{
3996 struct snd_soc_platform *platform;
3997
3998 platform = snd_soc_lookup_platform(dev);
3999 if (!platform)
4000 return;
4001
4002 snd_soc_remove_platform(platform);
3964 kfree(platform); 4003 kfree(platform);
3965} 4004}
3966EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); 4005EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index a9a300acb506..aa924d9b7986 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -254,44 +254,48 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
254} 254}
255EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); 255EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
256 256
257static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd, 257/**
258 dma_filter_fn filter_fn, void *filter_data) 258 * snd_dmaengine_pcm_request_channel - Request channel for the dmaengine PCM
259 * @filter_fn: Filter function used to request the DMA channel
260 * @filter_data: Data passed to the DMA filter function
261 *
262 * Returns NULL or the requested DMA channel.
263 *
264 * This function request a DMA channel for usage with dmaengine PCM.
265 */
266struct dma_chan *snd_dmaengine_pcm_request_channel(dma_filter_fn filter_fn,
267 void *filter_data)
259{ 268{
260 dma_cap_mask_t mask; 269 dma_cap_mask_t mask;
261 270
262 dma_cap_zero(mask); 271 dma_cap_zero(mask);
263 dma_cap_set(DMA_SLAVE, mask); 272 dma_cap_set(DMA_SLAVE, mask);
264 dma_cap_set(DMA_CYCLIC, mask); 273 dma_cap_set(DMA_CYCLIC, mask);
265 prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data);
266
267 if (!prtd->dma_chan)
268 return -ENXIO;
269 274
270 return 0; 275 return dma_request_channel(mask, filter_fn, filter_data);
271} 276}
277EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
272 278
273/** 279/**
274 * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream 280 * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
275 * @substream: PCM substream 281 * @substream: PCM substream
276 * @filter_fn: Filter function used to request the DMA channel 282 * @chan: DMA channel to use for data transfers
277 * @filter_data: Data passed to the DMA filter function
278 * 283 *
279 * Returns 0 on success, a negative error code otherwise. 284 * Returns 0 on success, a negative error code otherwise.
280 * 285 *
281 * This function will request a DMA channel using the passed filter function and 286 * The function should usually be called from the pcm open callback. Note that
282 * data. The function should usually be called from the pcm open callback. 287 * this function will use private_data field of the substream's runtime. So it
283 * 288 * is not availabe to your pcm driver implementation.
284 * Note that this function will use private_data field of the substream's
285 * runtime. So it is not availabe to your pcm driver implementation. If you need
286 * to keep additional data attached to a substream use
287 * snd_dmaengine_pcm_{set,get}_data.
288 */ 289 */
289int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, 290int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
290 dma_filter_fn filter_fn, void *filter_data) 291 struct dma_chan *chan)
291{ 292{
292 struct dmaengine_pcm_runtime_data *prtd; 293 struct dmaengine_pcm_runtime_data *prtd;
293 int ret; 294 int ret;
294 295
296 if (!chan)
297 return -ENXIO;
298
295 ret = snd_pcm_hw_constraint_integer(substream->runtime, 299 ret = snd_pcm_hw_constraint_integer(substream->runtime,
296 SNDRV_PCM_HW_PARAM_PERIODS); 300 SNDRV_PCM_HW_PARAM_PERIODS);
297 if (ret < 0) 301 if (ret < 0)
@@ -301,11 +305,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
301 if (!prtd) 305 if (!prtd)
302 return -ENOMEM; 306 return -ENOMEM;
303 307
304 ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data); 308 prtd->dma_chan = chan;
305 if (ret < 0) {
306 kfree(prtd);
307 return ret;
308 }
309 309
310 substream->runtime->private_data = prtd; 310 substream->runtime->private_data = prtd;
311 311
@@ -314,6 +314,27 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
314EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); 314EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
315 315
316/** 316/**
317 * snd_dmaengine_pcm_open_request_chan - Open a dmaengine based PCM substream and request channel
318 * @substream: PCM substream
319 * @filter_fn: Filter function used to request the DMA channel
320 * @filter_data: Data passed to the DMA filter function
321 *
322 * Returns 0 on success, a negative error code otherwise.
323 *
324 * This function will request a DMA channel using the passed filter function and
325 * data. The function should usually be called from the pcm open callback. Note
326 * that this function will use private_data field of the substream's runtime. So
327 * it is not availabe to your pcm driver implementation.
328 */
329int snd_dmaengine_pcm_open_request_chan(struct snd_pcm_substream *substream,
330 dma_filter_fn filter_fn, void *filter_data)
331{
332 return snd_dmaengine_pcm_open(substream,
333 snd_dmaengine_pcm_request_channel(filter_fn, filter_data));
334}
335EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open_request_chan);
336
337/**
317 * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream 338 * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
318 * @substream: PCM substream 339 * @substream: PCM substream
319 */ 340 */
@@ -321,11 +342,26 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
321{ 342{
322 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); 343 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
323 344
324 dma_release_channel(prtd->dma_chan);
325 kfree(prtd); 345 kfree(prtd);
326 346
327 return 0; 347 return 0;
328} 348}
329EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); 349EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
330 350
351/**
352 * snd_dmaengine_pcm_release_chan_close - Close a dmaengine based PCM substream and release channel
353 * @substream: PCM substream
354 *
355 * Releases the DMA channel associated with the PCM substream.
356 */
357int snd_dmaengine_pcm_close_release_chan(struct snd_pcm_substream *substream)
358{
359 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
360
361 dma_release_channel(prtd->dma_chan);
362
363 return snd_dmaengine_pcm_close(substream);
364}
365EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close_release_chan);
366
331MODULE_LICENSE("GPL"); 367MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c
new file mode 100644
index 000000000000..ae0c37e66ae0
--- /dev/null
+++ b/sound/soc/soc-generic-dmaengine-pcm.c
@@ -0,0 +1,284 @@
1/*
2 * Copyright (C) 2013, Analog Devices Inc.
3 * Author: Lars-Peter Clausen <lars@metafoo.de>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version.
9 *
10 * You should have received a copy of the GNU General Public License along
11 * with this program; if not, write to the Free Software Foundation, Inc.,
12 * 675 Mass Ave, Cambridge, MA 02139, USA.
13 *
14 */
15#include <linux/module.h>
16#include <linux/init.h>
17#include <linux/dmaengine.h>
18#include <linux/slab.h>
19#include <sound/pcm.h>
20#include <sound/pcm_params.h>
21#include <sound/soc.h>
22#include <linux/dma-mapping.h>
23#include <linux/of.h>
24#include <linux/of_dma.h>
25
26#include <sound/dmaengine_pcm.h>
27
28struct dmaengine_pcm {
29 struct dma_chan *chan[SNDRV_PCM_STREAM_CAPTURE + 1];
30 const struct snd_dmaengine_pcm_config *config;
31 struct snd_soc_platform platform;
32 bool compat;
33};
34
35static struct dmaengine_pcm *soc_platform_to_pcm(struct snd_soc_platform *p)
36{
37 return container_of(p, struct dmaengine_pcm, platform);
38}
39
40/**
41 * snd_dmaengine_pcm_prepare_slave_config() - Generic prepare_slave_config callback
42 * @substream: PCM substream
43 * @params: hw_params
44 * @slave_config: DMA slave config to prepare
45 *
46 * This function can be used as a generic prepare_slave_config callback for
47 * platforms which make use of the snd_dmaengine_dai_dma_data struct for their
48 * DAI DMA data. Internally the function will first call
49 * snd_hwparams_to_dma_slave_config to fill in the slave config based on the
50 * hw_params, followed by snd_dmaengine_set_config_from_dai_data to fill in the
51 * remaining fields based on the DAI DMA data.
52 */
53int snd_dmaengine_pcm_prepare_slave_config(struct snd_pcm_substream *substream,
54 struct snd_pcm_hw_params *params, struct dma_slave_config *slave_config)
55{
56 struct snd_soc_pcm_runtime *rtd = substream->private_data;
57 struct snd_dmaengine_dai_dma_data *dma_data;
58 int ret;
59
60 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
61
62 ret = snd_hwparams_to_dma_slave_config(substream, params, slave_config);
63 if (ret)
64 return ret;
65
66 snd_dmaengine_pcm_set_config_from_dai_data(substream, dma_data,
67 slave_config);
68
69 return 0;
70}
71EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_prepare_slave_config);
72
73static int dmaengine_pcm_hw_params(struct snd_pcm_substream *substream,
74 struct snd_pcm_hw_params *params)
75{
76 struct snd_soc_pcm_runtime *rtd = substream->private_data;
77 struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
78 struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
79 struct dma_slave_config slave_config;
80 int ret;
81
82 if (pcm->config->prepare_slave_config) {
83 ret = pcm->config->prepare_slave_config(substream, params,
84 &slave_config);
85 if (ret)
86 return ret;
87
88 ret = dmaengine_slave_config(chan, &slave_config);
89 if (ret)
90 return ret;
91 }
92
93 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params));
94}
95
96static int dmaengine_pcm_open(struct snd_pcm_substream *substream)
97{
98 struct snd_soc_pcm_runtime *rtd = substream->private_data;
99 struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
100 struct dma_chan *chan = pcm->chan[substream->stream];
101 int ret;
102
103 ret = snd_soc_set_runtime_hwparams(substream,
104 pcm->config->pcm_hardware);
105 if (ret)
106 return ret;
107
108 return snd_dmaengine_pcm_open(substream, chan);
109}
110
111static struct device *dmaengine_dma_dev(struct dmaengine_pcm *pcm,
112 struct snd_pcm_substream *substream)
113{
114 if (!pcm->chan[substream->stream])
115 return NULL;
116
117 return pcm->chan[substream->stream]->device->dev;
118}
119
120static void dmaengine_pcm_free(struct snd_pcm *pcm)
121{
122 snd_pcm_lib_preallocate_free_for_all(pcm);
123}
124
125static struct dma_chan *dmaengine_pcm_compat_request_channel(
126 struct snd_soc_pcm_runtime *rtd,
127 struct snd_pcm_substream *substream)
128{
129 struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
130
131 if (pcm->config->compat_request_channel)
132 return pcm->config->compat_request_channel(rtd, substream);
133
134 return snd_dmaengine_pcm_request_channel(pcm->config->compat_filter_fn,
135 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
136}
137
138static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd)
139{
140 struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform);
141 const struct snd_dmaengine_pcm_config *config = pcm->config;
142 struct snd_pcm_substream *substream;
143 unsigned int i;
144 int ret;
145
146 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
147 substream = rtd->pcm->streams[i].substream;
148 if (!substream)
149 continue;
150
151 if (!pcm->chan[i] && pcm->compat) {
152 pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd,
153 substream);
154 }
155
156 if (!pcm->chan[i]) {
157 dev_err(rtd->platform->dev,
158 "Missing dma channel for stream: %d\n", i);
159 ret = -EINVAL;
160 goto err_free;
161 }
162
163 ret = snd_pcm_lib_preallocate_pages(substream,
164 SNDRV_DMA_TYPE_DEV,
165 dmaengine_dma_dev(pcm, substream),
166 config->prealloc_buffer_size,
167 config->pcm_hardware->buffer_bytes_max);
168 if (ret)
169 goto err_free;
170 }
171
172 return 0;
173
174err_free:
175 dmaengine_pcm_free(rtd->pcm);
176 return ret;
177}
178
179static const struct snd_pcm_ops dmaengine_pcm_ops = {
180 .open = dmaengine_pcm_open,
181 .close = snd_dmaengine_pcm_close,
182 .ioctl = snd_pcm_lib_ioctl,
183 .hw_params = dmaengine_pcm_hw_params,
184 .hw_free = snd_pcm_lib_free_pages,
185 .trigger = snd_dmaengine_pcm_trigger,
186 .pointer = snd_dmaengine_pcm_pointer,
187};
188
189static const struct snd_soc_platform_driver dmaengine_pcm_platform = {
190 .ops = &dmaengine_pcm_ops,
191 .pcm_new = dmaengine_pcm_new,
192 .pcm_free = dmaengine_pcm_free,
193 .probe_order = SND_SOC_COMP_ORDER_LATE,
194};
195
196static const struct snd_pcm_ops dmaengine_no_residue_pcm_ops = {
197 .open = dmaengine_pcm_open,
198 .close = snd_dmaengine_pcm_close,
199 .ioctl = snd_pcm_lib_ioctl,
200 .hw_params = dmaengine_pcm_hw_params,
201 .hw_free = snd_pcm_lib_free_pages,
202 .trigger = snd_dmaengine_pcm_trigger,
203 .pointer = snd_dmaengine_pcm_pointer_no_residue,
204};
205
206static const struct snd_soc_platform_driver dmaengine_no_residue_pcm_platform = {
207 .ops = &dmaengine_no_residue_pcm_ops,
208 .pcm_new = dmaengine_pcm_new,
209 .pcm_free = dmaengine_pcm_free,
210 .probe_order = SND_SOC_COMP_ORDER_LATE,
211};
212
213static const char * const dmaengine_pcm_dma_channel_names[] = {
214 [SNDRV_PCM_STREAM_PLAYBACK] = "tx",
215 [SNDRV_PCM_STREAM_CAPTURE] = "rx",
216};
217
218/**
219 * snd_dmaengine_pcm_register - Register a dmaengine based PCM device
220 * @dev: The parent device for the PCM device
221 * @config: Platform specific PCM configuration
222 * @flags: Platform specific quirks
223 */
224int snd_dmaengine_pcm_register(struct device *dev,
225 const struct snd_dmaengine_pcm_config *config, unsigned int flags)
226{
227 struct dmaengine_pcm *pcm;
228 unsigned int i;
229
230 pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
231 if (!pcm)
232 return -ENOMEM;
233
234 pcm->config = config;
235
236 if (flags & SND_DMAENGINE_PCM_FLAG_COMPAT)
237 pcm->compat = true;
238
239 if (!(flags & SND_DMAENGINE_PCM_FLAG_NO_DT) && dev->of_node) {
240 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
241 pcm->chan[i] = of_dma_request_slave_channel(dev->of_node,
242 dmaengine_pcm_dma_channel_names[i]);
243 }
244 }
245
246 if (flags & SND_DMAENGINE_PCM_FLAG_NO_RESIDUE)
247 return snd_soc_add_platform(dev, &pcm->platform,
248 &dmaengine_no_residue_pcm_platform);
249 else
250 return snd_soc_add_platform(dev, &pcm->platform,
251 &dmaengine_pcm_platform);
252}
253EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_register);
254
255/**
256 * snd_dmaengine_pcm_unregister - Removes a dmaengine based PCM device
257 * @dev: Parent device the PCM was register with
258 *
259 * Removes a dmaengine based PCM device previously registered with
260 * snd_dmaengine_pcm_register.
261 */
262void snd_dmaengine_pcm_unregister(struct device *dev)
263{
264 struct snd_soc_platform *platform;
265 struct dmaengine_pcm *pcm;
266 unsigned int i;
267
268 platform = snd_soc_lookup_platform(dev);
269 if (!platform)
270 return;
271
272 pcm = soc_platform_to_pcm(platform);
273
274 for (i = SNDRV_PCM_STREAM_PLAYBACK; i <= SNDRV_PCM_STREAM_CAPTURE; i++) {
275 if (pcm->chan[i])
276 dma_release_channel(pcm->chan[i]);
277 }
278
279 snd_soc_remove_platform(platform);
280 kfree(pcm);
281}
282EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_unregister);
283
284MODULE_LICENSE("GPL");
diff --git a/sound/soc/soc-utils.c b/sound/soc/soc-utils.c
index fe4541df498c..4b3be6c3c91e 100644
--- a/sound/soc/soc-utils.c
+++ b/sound/soc/soc-utils.c
@@ -90,8 +90,33 @@ static struct snd_soc_platform_driver dummy_platform = {
90}; 90};
91 91
92static struct snd_soc_codec_driver dummy_codec; 92static struct snd_soc_codec_driver dummy_codec;
93
94#define STUB_RATES SNDRV_PCM_RATE_8000_192000
95#define STUB_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
96 SNDRV_PCM_FMTBIT_U8 | \
97 SNDRV_PCM_FMTBIT_S16_LE | \
98 SNDRV_PCM_FMTBIT_U16_LE | \
99 SNDRV_PCM_FMTBIT_S24_LE | \
100 SNDRV_PCM_FMTBIT_U24_LE | \
101 SNDRV_PCM_FMTBIT_S32_LE | \
102 SNDRV_PCM_FMTBIT_U32_LE | \
103 SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE)
93static struct snd_soc_dai_driver dummy_dai = { 104static struct snd_soc_dai_driver dummy_dai = {
94 .name = "snd-soc-dummy-dai", 105 .name = "snd-soc-dummy-dai",
106 .playback = {
107 .stream_name = "Playback",
108 .channels_min = 1,
109 .channels_max = 384,
110 .rates = STUB_RATES,
111 .formats = STUB_FORMATS,
112 },
113 .capture = {
114 .stream_name = "Capture",
115 .channels_min = 1,
116 .channels_max = 384,
117 .rates = STUB_RATES,
118 .formats = STUB_FORMATS,
119 },
95}; 120};
96 121
97static int snd_soc_dummy_probe(struct platform_device *pdev) 122static int snd_soc_dummy_probe(struct platform_device *pdev)
diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
index bfbcc1fcfe6f..2fbd4899d8ef 100644
--- a/sound/soc/spear/spear_pcm.c
+++ b/sound/soc/spear/spear_pcm.c
@@ -64,7 +64,8 @@ static int spear_pcm_open(struct snd_pcm_substream *substream)
64 if (ret) 64 if (ret)
65 return ret; 65 return ret;
66 66
67 return snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data) 67 return snd_dmaengine_pcm_open_request_chan(substream, dma_data->filter,
68 dma_data);
68} 69}
69 70
70static int spear_pcm_mmap(struct snd_pcm_substream *substream, 71static int spear_pcm_mmap(struct snd_pcm_substream *substream,
@@ -79,7 +80,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream,
79 80
80static struct snd_pcm_ops spear_pcm_ops = { 81static struct snd_pcm_ops spear_pcm_ops = {
81 .open = spear_pcm_open, 82 .open = spear_pcm_open,
82 .close = snd_dmaengine_pcm_close, 83 .close = snd_dmaengine_pcm_close_release_chan,
83 .ioctl = snd_pcm_lib_ioctl, 84 .ioctl = snd_pcm_lib_ioctl,
84 .hw_params = spear_pcm_hw_params, 85 .hw_params = spear_pcm_hw_params,
85 .hw_free = spear_pcm_hw_free, 86 .hw_free = spear_pcm_hw_free,
diff --git a/sound/soc/tegra/Kconfig b/sound/soc/tegra/Kconfig
index dbc27ce1d4de..b1c9d573da05 100644
--- a/sound/soc/tegra/Kconfig
+++ b/sound/soc/tegra/Kconfig
@@ -2,7 +2,7 @@ config SND_SOC_TEGRA
2 tristate "SoC Audio for the Tegra System-on-Chip" 2 tristate "SoC Audio for the Tegra System-on-Chip"
3 depends on ARCH_TEGRA && TEGRA20_APB_DMA 3 depends on ARCH_TEGRA && TEGRA20_APB_DMA
4 select REGMAP_MMIO 4 select REGMAP_MMIO
5 select SND_SOC_DMAENGINE_PCM if TEGRA20_APB_DMA 5 select SND_SOC_GENERIC_DMAENGINE_PCM if TEGRA20_APB_DMA
6 help 6 help
7 Say Y or M here if you want support for SoC audio on Tegra. 7 Say Y or M here if you want support for SoC audio on Tegra.
8 8
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 6d1c70c3d753..f056f632557c 100644
--- a/sound/soc/tegra/tegra_pcm.c
+++ b/sound/soc/tegra/tegra_pcm.c
@@ -29,9 +29,7 @@
29 * 29 *
30 */ 30 */
31 31
32#include <linux/dma-mapping.h>
33#include <linux/module.h> 32#include <linux/module.h>
34#include <linux/slab.h>
35#include <sound/core.h> 33#include <sound/core.h>
36#include <sound/pcm.h> 34#include <sound/pcm.h>
37#include <sound/pcm_params.h> 35#include <sound/pcm_params.h>
@@ -55,175 +53,24 @@ static const struct snd_pcm_hardware tegra_pcm_hardware = {
55 .fifo_size = 4, 53 .fifo_size = 4,
56}; 54};
57 55
58static int tegra_pcm_open(struct snd_pcm_substream *substream) 56static const struct snd_dmaengine_pcm_config tegra_dmaengine_pcm_config = {
59{ 57 .pcm_hardware = &tegra_pcm_hardware,
60 struct snd_soc_pcm_runtime *rtd = substream->private_data; 58 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
61 struct device *dev = rtd->platform->dev; 59 .compat_filter_fn = NULL,
62 int ret; 60 .prealloc_buffer_size = PAGE_SIZE * 8,
63
64 /* Set HW params now that initialization is complete */
65 snd_soc_set_runtime_hwparams(substream, &tegra_pcm_hardware);
66
67 ret = snd_dmaengine_pcm_open(substream, NULL, NULL);
68 if (ret) {
69 dev_err(dev, "dmaengine pcm open failed with err %d\n", ret);
70 return ret;
71 }
72
73 return 0;
74}
75
76static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
77 struct snd_pcm_hw_params *params)
78{
79 struct snd_soc_pcm_runtime *rtd = substream->private_data;
80 struct device *dev = rtd->platform->dev;
81 struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
82 struct dma_slave_config slave_config;
83 int ret;
84
85 ret = snd_hwparams_to_dma_slave_config(substream, params,
86 &slave_config);
87 if (ret) {
88 dev_err(dev, "hw params config failed with err %d\n", ret);
89 return ret;
90 }
91
92 snd_dmaengine_pcm_set_config_from_dai_data(substream,
93 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
94 &slave_config);
95
96 ret = dmaengine_slave_config(chan, &slave_config);
97 if (ret < 0) {
98 dev_err(dev, "dma slave config failed with err %d\n", ret);
99 return ret;
100 }
101
102 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
103 return 0;
104}
105
106static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
107{
108 snd_pcm_set_runtime_buffer(substream, NULL);
109 return 0;
110}
111
112static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
113 struct vm_area_struct *vma)
114{
115 struct snd_pcm_runtime *runtime = substream->runtime;
116
117 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
118 runtime->dma_area,
119 runtime->dma_addr,
120 runtime->dma_bytes);
121}
122
123static struct snd_pcm_ops tegra_pcm_ops = {
124 .open = tegra_pcm_open,
125 .close = snd_dmaengine_pcm_close,
126 .ioctl = snd_pcm_lib_ioctl,
127 .hw_params = tegra_pcm_hw_params,
128 .hw_free = tegra_pcm_hw_free,
129 .trigger = snd_dmaengine_pcm_trigger,
130 .pointer = snd_dmaengine_pcm_pointer,
131 .mmap = tegra_pcm_mmap,
132};
133
134static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
135{
136 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
137 struct snd_dma_buffer *buf = &substream->dma_buffer;
138 size_t size = tegra_pcm_hardware.buffer_bytes_max;
139
140 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
141 &buf->addr, GFP_KERNEL);
142 if (!buf->area)
143 return -ENOMEM;
144
145 buf->dev.type = SNDRV_DMA_TYPE_DEV;
146 buf->dev.dev = pcm->card->dev;
147 buf->private_data = NULL;
148 buf->bytes = size;
149
150 return 0;
151}
152
153static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
154{
155 struct snd_pcm_substream *substream;
156 struct snd_dma_buffer *buf;
157
158 substream = pcm->streams[stream].substream;
159 if (!substream)
160 return;
161
162 buf = &substream->dma_buffer;
163 if (!buf->area)
164 return;
165
166 dma_free_writecombine(pcm->card->dev, buf->bytes,
167 buf->area, buf->addr);
168 buf->area = NULL;
169}
170
171static u64 tegra_dma_mask = DMA_BIT_MASK(32);
172
173static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
174{
175 struct snd_card *card = rtd->card->snd_card;
176 struct snd_pcm *pcm = rtd->pcm;
177 int ret = 0;
178
179 if (!card->dev->dma_mask)
180 card->dev->dma_mask = &tegra_dma_mask;
181 if (!card->dev->coherent_dma_mask)
182 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
183
184 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
185 ret = tegra_pcm_preallocate_dma_buffer(pcm,
186 SNDRV_PCM_STREAM_PLAYBACK);
187 if (ret)
188 goto err;
189 }
190
191 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
192 ret = tegra_pcm_preallocate_dma_buffer(pcm,
193 SNDRV_PCM_STREAM_CAPTURE);
194 if (ret)
195 goto err_free_play;
196 }
197
198 return 0;
199
200err_free_play:
201 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
202err:
203 return ret;
204}
205
206static void tegra_pcm_free(struct snd_pcm *pcm)
207{
208 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
209 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
210}
211
212static struct snd_soc_platform_driver tegra_pcm_platform = {
213 .ops = &tegra_pcm_ops,
214 .pcm_new = tegra_pcm_new,
215 .pcm_free = tegra_pcm_free,
216}; 61};
217 62
218int tegra_pcm_platform_register(struct device *dev) 63int tegra_pcm_platform_register(struct device *dev)
219{ 64{
220 return snd_soc_register_platform(dev, &tegra_pcm_platform); 65 return snd_dmaengine_pcm_register(dev, &tegra_dmaengine_pcm_config,
66 SND_DMAENGINE_PCM_FLAG_NO_DT |
67 SND_DMAENGINE_PCM_FLAG_COMPAT);
221} 68}
222EXPORT_SYMBOL_GPL(tegra_pcm_platform_register); 69EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
223 70
224void tegra_pcm_platform_unregister(struct device *dev) 71void tegra_pcm_platform_unregister(struct device *dev)
225{ 72{
226 snd_soc_unregister_platform(dev); 73 return snd_dmaengine_pcm_unregister(dev);
227} 74}
228EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister); 75EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
229 76
diff --git a/sound/soc/ux500/Kconfig b/sound/soc/ux500/Kconfig
index 069330d82be5..c73c5907eb11 100644
--- a/sound/soc/ux500/Kconfig
+++ b/sound/soc/ux500/Kconfig
@@ -16,7 +16,7 @@ config SND_SOC_UX500_PLAT_MSP_I2S
16config SND_SOC_UX500_PLAT_DMA 16config SND_SOC_UX500_PLAT_DMA
17 tristate "Platform - DB8500 (DMA)" 17 tristate "Platform - DB8500 (DMA)"
18 depends on SND_SOC_UX500 18 depends on SND_SOC_UX500
19 select SND_SOC_DMAENGINE_PCM 19 select SND_SOC_GENERIC_DMAENGINE_PCM
20 help 20 help
21 Say Y if you want to enable the Ux500 platform-driver. 21 Say Y if you want to enable the Ux500 platform-driver.
22 22
diff --git a/sound/soc/ux500/ux500_pcm.c b/sound/soc/ux500/ux500_pcm.c
index 09b5364e5095..b6e5ae277299 100644
--- a/sound/soc/ux500/ux500_pcm.c
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -40,7 +40,7 @@
40#define UX500_PLATFORM_PERIODS_MAX 48 40#define UX500_PLATFORM_PERIODS_MAX 48
41#define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE) 41#define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE)
42 42
43static struct snd_pcm_hardware ux500_pcm_hw = { 43static const struct snd_pcm_hardware ux500_pcm_hw = {
44 .info = SNDRV_PCM_INFO_INTERLEAVED | 44 .info = SNDRV_PCM_INFO_INTERLEAVED |
45 SNDRV_PCM_INFO_MMAP | 45 SNDRV_PCM_INFO_MMAP |
46 SNDRV_PCM_INFO_RESUME | 46 SNDRV_PCM_INFO_RESUME |
@@ -61,43 +61,23 @@ static struct snd_pcm_hardware ux500_pcm_hw = {
61 .periods_max = UX500_PLATFORM_PERIODS_MAX, 61 .periods_max = UX500_PLATFORM_PERIODS_MAX,
62}; 62};
63 63
64static void ux500_pcm_dma_hw_free(struct device *dev, 64static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
65 struct snd_pcm_substream *substream) 65 struct snd_pcm_substream *substream)
66{ 66{
67 struct snd_pcm_runtime *runtime = substream->runtime;
68 struct snd_dma_buffer *buf = runtime->dma_buffer_p;
69
70 if (runtime->dma_area == NULL)
71 return;
72
73 if (buf != &substream->dma_buffer) {
74 dma_free_coherent(buf->dev.dev, buf->bytes, buf->area,
75 buf->addr);
76 kfree(runtime->dma_buffer_p);
77 }
78
79 snd_pcm_set_runtime_buffer(substream, NULL);
80}
81
82static int ux500_pcm_open(struct snd_pcm_substream *substream)
83{
84 struct snd_soc_pcm_runtime *rtd = substream->private_data;
85 struct snd_soc_dai *dai = rtd->cpu_dai; 67 struct snd_soc_dai *dai = rtd->cpu_dai;
86 struct device *dev = dai->dev; 68 struct device *dev = dai->dev;
87 int ret;
88 struct ux500_msp_dma_params *dma_params;
89 u16 per_data_width, mem_data_width; 69 u16 per_data_width, mem_data_width;
90 struct stedma40_chan_cfg *dma_cfg; 70 struct stedma40_chan_cfg *dma_cfg;
71 struct ux500_msp_dma_params *dma_params;
91 72
92 dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id, 73 dev_dbg(dev, "%s: MSP %d (%s): Enter.\n", __func__, dai->id,
93 snd_pcm_stream_str(substream)); 74 snd_pcm_stream_str(substream));
94 75
95 dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__); 76 dma_params = snd_soc_dai_get_dma_data(dai, substream);
96 snd_soc_set_runtime_hwparams(substream, &ux500_pcm_hw); 77 dma_cfg = dma_params->dma_cfg;
97 78
98 mem_data_width = STEDMA40_HALFWORD_WIDTH; 79 mem_data_width = STEDMA40_HALFWORD_WIDTH;
99 80
100 dma_params = snd_soc_dai_get_dma_data(dai, substream);
101 switch (dma_params->data_size) { 81 switch (dma_params->data_size) {
102 case 32: 82 case 32:
103 per_data_width = STEDMA40_WORD_WIDTH; 83 per_data_width = STEDMA40_WORD_WIDTH;
@@ -110,13 +90,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
110 break; 90 break;
111 default: 91 default:
112 per_data_width = STEDMA40_WORD_WIDTH; 92 per_data_width = STEDMA40_WORD_WIDTH;
113 dev_warn(rtd->platform->dev,
114 "%s: Unknown data-size (%d)! Assuming 32 bits.\n",
115 __func__, dma_params->data_size);
116 } 93 }
117 94
118 dma_cfg = dma_params->dma_cfg;
119
120 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 95 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
121 dma_cfg->src_info.data_width = mem_data_width; 96 dma_cfg->src_info.data_width = mem_data_width;
122 dma_cfg->dst_info.data_width = per_data_width; 97 dma_cfg->dst_info.data_width = per_data_width;
@@ -125,123 +100,24 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
125 dma_cfg->dst_info.data_width = mem_data_width; 100 dma_cfg->dst_info.data_width = mem_data_width;
126 } 101 }
127 102
128 103 return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg);
129 ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg);
130 if (ret) {
131 dev_dbg(dai->dev,
132 "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n",
133 __func__, ret);
134 return ret;
135 }
136
137 return 0;
138} 104}
139 105
140static int ux500_pcm_hw_params(struct snd_pcm_substream *substream, 106static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
141 struct snd_pcm_hw_params *hw_params) 107 .pcm_hardware = &ux500_pcm_hw,
142{ 108 .compat_request_channel = ux500_pcm_request_chan,
143 struct snd_pcm_runtime *runtime = substream->runtime; 109 .prealloc_buffer_size = 128 * 1024,
144 struct snd_dma_buffer *buf = runtime->dma_buffer_p;
145 struct snd_soc_pcm_runtime *rtd = substream->private_data;
146 int ret = 0;
147 int size;
148
149 dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
150
151 size = params_buffer_bytes(hw_params);
152
153 if (buf) {
154 if (buf->bytes >= size)
155 goto out;
156 ux500_pcm_dma_hw_free(NULL, substream);
157 }
158
159 if (substream->dma_buffer.area != NULL &&
160 substream->dma_buffer.bytes >= size) {
161 buf = &substream->dma_buffer;
162 } else {
163 buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
164 if (!buf)
165 goto nomem;
166
167 buf->dev.type = SNDRV_DMA_TYPE_DEV;
168 buf->dev.dev = NULL;
169 buf->area = dma_alloc_coherent(NULL, size, &buf->addr,
170 GFP_KERNEL);
171 buf->bytes = size;
172 buf->private_data = NULL;
173
174 if (!buf->area)
175 goto free;
176 }
177 snd_pcm_set_runtime_buffer(substream, buf);
178 ret = 1;
179 out:
180 runtime->dma_bytes = size;
181 return ret;
182
183 free:
184 kfree(buf);
185 nomem:
186 return -ENOMEM;
187}
188
189static int ux500_pcm_hw_free(struct snd_pcm_substream *substream)
190{
191 struct snd_soc_pcm_runtime *rtd = substream->private_data;
192
193 dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
194
195 ux500_pcm_dma_hw_free(NULL, substream);
196
197 return 0;
198}
199
200static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
201 struct vm_area_struct *vma)
202{
203 struct snd_pcm_runtime *runtime = substream->runtime;
204 struct snd_soc_pcm_runtime *rtd = substream->private_data;
205
206 dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__);
207
208 return dma_mmap_coherent(NULL, vma, runtime->dma_area,
209 runtime->dma_addr, runtime->dma_bytes);
210}
211
212static struct snd_pcm_ops ux500_pcm_ops = {
213 .open = ux500_pcm_open,
214 .close = snd_dmaengine_pcm_close,
215 .ioctl = snd_pcm_lib_ioctl,
216 .hw_params = ux500_pcm_hw_params,
217 .hw_free = ux500_pcm_hw_free,
218 .trigger = snd_dmaengine_pcm_trigger,
219 .pointer = snd_dmaengine_pcm_pointer_no_residue,
220 .mmap = ux500_pcm_mmap
221};
222
223int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd)
224{
225 struct snd_pcm *pcm = rtd->pcm;
226
227 dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__,
228 pcm->id);
229
230 pcm->info_flags = 0;
231
232 return 0;
233}
234
235static struct snd_soc_platform_driver ux500_pcm_soc_drv = {
236 .ops = &ux500_pcm_ops,
237 .pcm_new = ux500_pcm_new,
238}; 110};
239 111
240int ux500_pcm_register_platform(struct platform_device *pdev) 112int ux500_pcm_register_platform(struct platform_device *pdev)
241{ 113{
242 int ret; 114 int ret;
243 115
244 ret = snd_soc_register_platform(&pdev->dev, &ux500_pcm_soc_drv); 116 ret = snd_dmaengine_pcm_register(&pdev->dev,
117 &ux500_dmaengine_pcm_config,
118 SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
119 SND_DMAENGINE_PCM_FLAG_COMPAT |
120 SND_DMAENGINE_PCM_FLAG_NO_DT);
245 if (ret < 0) { 121 if (ret < 0) {
246 dev_err(&pdev->dev, 122 dev_err(&pdev->dev,
247 "%s: ERROR: Failed to register platform '%s' (%d)!\n", 123 "%s: ERROR: Failed to register platform '%s' (%d)!\n",
@@ -255,8 +131,7 @@ EXPORT_SYMBOL_GPL(ux500_pcm_register_platform);
255 131
256int ux500_pcm_unregister_platform(struct platform_device *pdev) 132int ux500_pcm_unregister_platform(struct platform_device *pdev)
257{ 133{
258 snd_soc_unregister_platform(&pdev->dev); 134 snd_dmaengine_pcm_unregister(&pdev->dev);
259
260 return 0; 135 return 0;
261} 136}
262EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); 137EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);