aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2013-04-18 10:05:30 -0400
committerMark Brown <broonie@opensource.wolfsonmicro.com>2013-04-18 10:05:30 -0400
commitd45a26bd9790fcde58cf4b11a775ff56c6b44e0b (patch)
tree71b75e94b7a586123331eed46e91d25dd88ff52a /sound/soc
parent8ef53f689afea7f2da360cb27d7af040c1216bfa (diff)
parent22f38f792ec53e2a93be13ecb609bbe911ed8ff9 (diff)
Merge remote-tracking branch 'asoc/topic/dma' into asoc-next
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.c29
-rw-r--r--sound/soc/cirrus/edb93xx.c1
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c9
-rw-r--r--sound/soc/cirrus/ep93xx-i2s.c16
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.c38
-rw-r--r--sound/soc/cirrus/ep93xx-pcm.h20
-rw-r--r--sound/soc/cirrus/simone.c2
-rw-r--r--sound/soc/cirrus/snappercl15.c1
-rw-r--r--sound/soc/fsl/Kconfig2
-rw-r--r--sound/soc/fsl/fsl_ssi.c55
-rw-r--r--sound/soc/fsl/imx-pcm-dma.c120
-rw-r--r--sound/soc/fsl/imx-pcm-fiq.c4
-rw-r--r--sound/soc/fsl/imx-pcm.c6
-rw-r--r--sound/soc/fsl/imx-pcm.h24
-rw-r--r--sound/soc/fsl/imx-ssi.c49
-rw-r--r--sound/soc/fsl/imx-ssi.h7
-rw-r--r--sound/soc/mxs/mxs-pcm.c43
-rw-r--r--sound/soc/mxs/mxs-pcm.h4
-rw-r--r--sound/soc/mxs/mxs-saif.c6
-rw-r--r--sound/soc/omap/am3517evm.c1
-rw-r--r--sound/soc/omap/ams-delta.c1
-rw-r--r--sound/soc/omap/mcbsp.c14
-rw-r--r--sound/soc/omap/mcbsp.h7
-rw-r--r--sound/soc/omap/n810.c1
-rw-r--r--sound/soc/omap/omap-abe-twl6040.c1
-rw-r--r--sound/soc/omap/omap-dmic.c38
-rw-r--r--sound/soc/omap/omap-hdmi.c24
-rw-r--r--sound/soc/omap/omap-mcbsp.c18
-rw-r--r--sound/soc/omap/omap-mcpdm.c109
-rw-r--r--sound/soc/omap/omap-pcm.c86
-rw-r--r--sound/soc/omap/omap-pcm.h40
-rw-r--r--sound/soc/omap/omap-twl4030.c1
-rw-r--r--sound/soc/omap/omap3pandora.c9
-rw-r--r--sound/soc/omap/osk5912.c1
-rw-r--r--sound/soc/omap/rx51.c1
-rw-r--r--sound/soc/pxa/mmp-pcm.c34
-rw-r--r--sound/soc/soc-core.c85
-rw-r--r--sound/soc/soc-dmaengine-pcm.c150
-rw-r--r--sound/soc/soc-generic-dmaengine-pcm.c284
-rw-r--r--sound/soc/spear/spear_pcm.c19
-rw-r--r--sound/soc/tegra/Kconfig2
-rw-r--r--sound/soc/tegra/tegra20_ac97.c13
-rw-r--r--sound/soc/tegra/tegra20_ac97.h4
-rw-r--r--sound/soc/tegra/tegra20_i2s.c13
-rw-r--r--sound/soc/tegra/tegra20_i2s.h4
-rw-r--r--sound/soc/tegra/tegra20_spdif.c7
-rw-r--r--sound/soc/tegra/tegra20_spdif.h4
-rw-r--r--sound/soc/tegra/tegra30_ahub.c8
-rw-r--r--sound/soc/tegra/tegra30_ahub.h8
-rw-r--r--sound/soc/tegra/tegra30_i2s.c13
-rw-r--r--sound/soc/tegra/tegra30_i2s.h4
-rw-r--r--sound/soc/tegra/tegra_pcm.c187
-rw-r--r--sound/soc/tegra/tegra_pcm.h7
-rw-r--r--sound/soc/ux500/Kconfig2
-rw-r--r--sound/soc/ux500/ux500_pcm.c229
-rw-r--r--sound/soc/ux500/ux500_pcm.h14
58 files changed, 808 insertions, 1079 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 30184a4a147a..1d38fd0bc4e2 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -67,9 +67,10 @@ static const struct snd_pcm_hardware atmel_pcm_dma_hardware = {
67static void atmel_pcm_dma_irq(u32 ssc_sr, 67static void atmel_pcm_dma_irq(u32 ssc_sr,
68 struct snd_pcm_substream *substream) 68 struct snd_pcm_substream *substream)
69{ 69{
70 struct snd_soc_pcm_runtime *rtd = substream->private_data;
70 struct atmel_pcm_dma_params *prtd; 71 struct atmel_pcm_dma_params *prtd;
71 72
72 prtd = snd_dmaengine_pcm_get_data(substream); 73 prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
73 74
74 if (ssc_sr & prtd->mask->ssc_error) { 75 if (ssc_sr & prtd->mask->ssc_error) {
75 if (snd_pcm_running(substream)) 76 if (snd_pcm_running(substream))
@@ -104,15 +105,13 @@ static bool filter(struct dma_chan *chan, void *slave)
104} 105}
105 106
106static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream, 107static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
107 struct snd_pcm_hw_params *params) 108 struct snd_pcm_hw_params *params, struct atmel_pcm_dma_params *prtd)
108{ 109{
109 struct atmel_pcm_dma_params *prtd;
110 struct ssc_device *ssc; 110 struct ssc_device *ssc;
111 struct dma_chan *dma_chan; 111 struct dma_chan *dma_chan;
112 struct dma_slave_config slave_config; 112 struct dma_slave_config slave_config;
113 int ret; 113 int ret;
114 114
115 prtd = snd_dmaengine_pcm_get_data(substream);
116 ssc = prtd->ssc; 115 ssc = prtd->ssc;
117 116
118 ret = snd_hwparams_to_dma_slave_config(substream, params, 117 ret = snd_hwparams_to_dma_slave_config(substream, params,
@@ -130,8 +129,6 @@ static int atmel_pcm_configure_dma(struct snd_pcm_substream *substream,
130 slave_config.src_maxburst = 1; 129 slave_config.src_maxburst = 1;
131 } 130 }
132 131
133 slave_config.device_fc = false;
134
135 dma_chan = snd_dmaengine_pcm_get_chan(substream); 132 dma_chan = snd_dmaengine_pcm_get_chan(substream);
136 if (dmaengine_slave_config(dma_chan, &slave_config)) { 133 if (dmaengine_slave_config(dma_chan, &slave_config)) {
137 pr_err("atmel-pcm: failed to configure dma channel\n"); 134 pr_err("atmel-pcm: failed to configure dma channel\n");
@@ -158,15 +155,13 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
158 if (ssc->pdev) 155 if (ssc->pdev)
159 sdata = ssc->pdev->dev.platform_data; 156 sdata = ssc->pdev->dev.platform_data;
160 157
161 ret = snd_dmaengine_pcm_open(substream, filter, sdata); 158 ret = snd_dmaengine_pcm_open_request_chan(substream, filter, sdata);
162 if (ret) { 159 if (ret) {
163 pr_err("atmel-pcm: dmaengine pcm open failed\n"); 160 pr_err("atmel-pcm: dmaengine pcm open failed\n");
164 return -EINVAL; 161 return -EINVAL;
165 } 162 }
166 163
167 snd_dmaengine_pcm_set_data(substream, prtd); 164 ret = atmel_pcm_configure_dma(substream, params, prtd);
168
169 ret = atmel_pcm_configure_dma(substream, params);
170 if (ret) { 165 if (ret) {
171 pr_err("atmel-pcm: failed to configure dmai\n"); 166 pr_err("atmel-pcm: failed to configure dmai\n");
172 goto err; 167 goto err;
@@ -176,15 +171,16 @@ static int atmel_pcm_hw_params(struct snd_pcm_substream *substream,
176 171
177 return 0; 172 return 0;
178err: 173err:
179 snd_dmaengine_pcm_close(substream); 174 snd_dmaengine_pcm_close_release_chan(substream);
180 return ret; 175 return ret;
181} 176}
182 177
183static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream) 178static int atmel_pcm_dma_prepare(struct snd_pcm_substream *substream)
184{ 179{
180 struct snd_soc_pcm_runtime *rtd = substream->private_data;
185 struct atmel_pcm_dma_params *prtd; 181 struct atmel_pcm_dma_params *prtd;
186 182
187 prtd = snd_dmaengine_pcm_get_data(substream); 183 prtd = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
188 184
189 ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error); 185 ssc_writex(prtd->ssc->regs, SSC_IER, prtd->mask->ssc_error);
190 ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable); 186 ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_enable);
@@ -199,16 +195,9 @@ static int atmel_pcm_open(struct snd_pcm_substream *substream)
199 return 0; 195 return 0;
200} 196}
201 197
202static int atmel_pcm_close(struct snd_pcm_substream *substream)
203{
204 snd_dmaengine_pcm_close(substream);
205
206 return 0;
207}
208
209static struct snd_pcm_ops atmel_pcm_ops = { 198static struct snd_pcm_ops atmel_pcm_ops = {
210 .open = atmel_pcm_open, 199 .open = atmel_pcm_open,
211 .close = atmel_pcm_close, 200 .close = snd_dmaengine_pcm_close_release_chan,
212 .ioctl = snd_pcm_lib_ioctl, 201 .ioctl = snd_pcm_lib_ioctl,
213 .hw_params = atmel_pcm_hw_params, 202 .hw_params = atmel_pcm_hw_params,
214 .prepare = atmel_pcm_dma_prepare, 203 .prepare = atmel_pcm_dma_prepare,
diff --git a/sound/soc/cirrus/edb93xx.c b/sound/soc/cirrus/edb93xx.c
index 5db68cf7b281..c43fb214558a 100644
--- a/sound/soc/cirrus/edb93xx.c
+++ b/sound/soc/cirrus/edb93xx.c
@@ -27,7 +27,6 @@
27#include <sound/soc.h> 27#include <sound/soc.h>
28#include <asm/mach-types.h> 28#include <asm/mach-types.h>
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include "ep93xx-pcm.h"
31 30
32static int edb93xx_hw_params(struct snd_pcm_substream *substream, 31static int edb93xx_hw_params(struct snd_pcm_substream *substream,
33 struct snd_pcm_hw_params *params) 32 struct snd_pcm_hw_params *params)
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index 1738d28fb04f..8d3088647e44 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -23,7 +23,6 @@
23#include <sound/soc.h> 23#include <sound/soc.h>
24 24
25#include <linux/platform_data/dma-ep93xx.h> 25#include <linux/platform_data/dma-ep93xx.h>
26#include "ep93xx-pcm.h"
27 26
28/* 27/*
29 * Per channel (1-4) registers. 28 * Per channel (1-4) registers.
@@ -101,14 +100,16 @@ struct ep93xx_ac97_info {
101/* currently ALSA only supports a single AC97 device */ 100/* currently ALSA only supports a single AC97 device */
102static struct ep93xx_ac97_info *ep93xx_ac97_info; 101static struct ep93xx_ac97_info *ep93xx_ac97_info;
103 102
104static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_out = { 103static struct ep93xx_dma_data ep93xx_ac97_pcm_out = {
105 .name = "ac97-pcm-out", 104 .name = "ac97-pcm-out",
106 .dma_port = EP93XX_DMA_AAC1, 105 .dma_port = EP93XX_DMA_AAC1,
106 .direction = DMA_MEM_TO_DEV,
107}; 107};
108 108
109static struct ep93xx_pcm_dma_params ep93xx_ac97_pcm_in = { 109static struct ep93xx_dma_data ep93xx_ac97_pcm_in = {
110 .name = "ac97-pcm-in", 110 .name = "ac97-pcm-in",
111 .dma_port = EP93XX_DMA_AAC1, 111 .dma_port = EP93XX_DMA_AAC1,
112 .direction = DMA_DEV_TO_MEM,
112}; 113};
113 114
114static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info, 115static inline unsigned ep93xx_ac97_read_reg(struct ep93xx_ac97_info *info,
@@ -316,7 +317,7 @@ static int ep93xx_ac97_trigger(struct snd_pcm_substream *substream,
316static int ep93xx_ac97_startup(struct snd_pcm_substream *substream, 317static int ep93xx_ac97_startup(struct snd_pcm_substream *substream,
317 struct snd_soc_dai *dai) 318 struct snd_soc_dai *dai)
318{ 319{
319 struct ep93xx_pcm_dma_params *dma_data; 320 struct ep93xx_dma_data *dma_data;
320 321
321 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 322 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
322 dma_data = &ep93xx_ac97_pcm_out; 323 dma_data = &ep93xx_ac97_pcm_out;
diff --git a/sound/soc/cirrus/ep93xx-i2s.c b/sound/soc/cirrus/ep93xx-i2s.c
index 323ed69b7975..83075b3c180c 100644
--- a/sound/soc/cirrus/ep93xx-i2s.c
+++ b/sound/soc/cirrus/ep93xx-i2s.c
@@ -30,8 +30,6 @@
30#include <mach/ep93xx-regs.h> 30#include <mach/ep93xx-regs.h>
31#include <linux/platform_data/dma-ep93xx.h> 31#include <linux/platform_data/dma-ep93xx.h>
32 32
33#include "ep93xx-pcm.h"
34
35#define EP93XX_I2S_TXCLKCFG 0x00 33#define EP93XX_I2S_TXCLKCFG 0x00
36#define EP93XX_I2S_RXCLKCFG 0x04 34#define EP93XX_I2S_RXCLKCFG 0x04
37#define EP93XX_I2S_GLCTRL 0x0C 35#define EP93XX_I2S_GLCTRL 0x0C
@@ -62,18 +60,20 @@ struct ep93xx_i2s_info {
62 struct clk *mclk; 60 struct clk *mclk;
63 struct clk *sclk; 61 struct clk *sclk;
64 struct clk *lrclk; 62 struct clk *lrclk;
65 struct ep93xx_pcm_dma_params *dma_params; 63 struct ep93xx_dma_data *dma_data;
66 void __iomem *regs; 64 void __iomem *regs;
67}; 65};
68 66
69struct ep93xx_pcm_dma_params ep93xx_i2s_dma_params[] = { 67struct ep93xx_dma_data ep93xx_i2s_dma_data[] = {
70 [SNDRV_PCM_STREAM_PLAYBACK] = { 68 [SNDRV_PCM_STREAM_PLAYBACK] = {
71 .name = "i2s-pcm-out", 69 .name = "i2s-pcm-out",
72 .dma_port = EP93XX_DMA_I2S1, 70 .port = EP93XX_DMA_I2S1,
71 .direction = DMA_MEM_TO_DEV,
73 }, 72 },
74 [SNDRV_PCM_STREAM_CAPTURE] = { 73 [SNDRV_PCM_STREAM_CAPTURE] = {
75 .name = "i2s-pcm-in", 74 .name = "i2s-pcm-in",
76 .dma_port = EP93XX_DMA_I2S1, 75 .port = EP93XX_DMA_I2S1,
76 .direction = DMA_DEV_TO_MEM,
77 }, 77 },
78}; 78};
79 79
@@ -147,7 +147,7 @@ static int ep93xx_i2s_startup(struct snd_pcm_substream *substream,
147 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 147 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
148 148
149 snd_soc_dai_set_dma_data(cpu_dai, substream, 149 snd_soc_dai_set_dma_data(cpu_dai, substream,
150 &info->dma_params[substream->stream]); 150 &info->dma_data[substream->stream]);
151 return 0; 151 return 0;
152} 152}
153 153
@@ -403,7 +403,7 @@ static int ep93xx_i2s_probe(struct platform_device *pdev)
403 } 403 }
404 404
405 dev_set_drvdata(&pdev->dev, info); 405 dev_set_drvdata(&pdev->dev, info);
406 info->dma_params = ep93xx_i2s_dma_params; 406 info->dma_data = ep93xx_i2s_dma_data;
407 407
408 err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai); 408 err = snd_soc_register_dai(&pdev->dev, &ep93xx_i2s_dai);
409 if (err) 409 if (err)
diff --git a/sound/soc/cirrus/ep93xx-pcm.c b/sound/soc/cirrus/ep93xx-pcm.c
index 72eb7a49e16a..488032690378 100644
--- a/sound/soc/cirrus/ep93xx-pcm.c
+++ b/sound/soc/cirrus/ep93xx-pcm.c
@@ -29,8 +29,6 @@
29#include <mach/hardware.h> 29#include <mach/hardware.h>
30#include <mach/ep93xx-regs.h> 30#include <mach/ep93xx-regs.h>
31 31
32#include "ep93xx-pcm.h"
33
34static const struct snd_pcm_hardware ep93xx_pcm_hardware = { 32static const struct snd_pcm_hardware ep93xx_pcm_hardware = {
35 .info = (SNDRV_PCM_INFO_MMAP | 33 .info = (SNDRV_PCM_INFO_MMAP |
36 SNDRV_PCM_INFO_MMAP_VALID | 34 SNDRV_PCM_INFO_MMAP_VALID |
@@ -68,40 +66,12 @@ static bool ep93xx_pcm_dma_filter(struct dma_chan *chan, void *filter_param)
68static int ep93xx_pcm_open(struct snd_pcm_substream *substream) 66static int ep93xx_pcm_open(struct snd_pcm_substream *substream)
69{ 67{
70 struct snd_soc_pcm_runtime *rtd = substream->private_data; 68 struct snd_soc_pcm_runtime *rtd = substream->private_data;
71 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
72 struct ep93xx_pcm_dma_params *dma_params;
73 struct ep93xx_dma_data *dma_data;
74 int ret;
75 69
76 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware); 70 snd_soc_set_runtime_hwparams(substream, &ep93xx_pcm_hardware);
77 71
78 dma_data = kmalloc(sizeof(*dma_data), GFP_KERNEL); 72 return snd_dmaengine_pcm_open_request_chan(substream,
79 if (!dma_data) 73 ep93xx_pcm_dma_filter,
80 return -ENOMEM; 74 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
81
82 dma_params = snd_soc_dai_get_dma_data(cpu_dai, substream);
83 dma_data->port = dma_params->dma_port;
84 dma_data->name = dma_params->name;
85 dma_data->direction = snd_pcm_substream_to_dma_direction(substream);
86
87 ret = snd_dmaengine_pcm_open(substream, ep93xx_pcm_dma_filter, dma_data);
88 if (ret) {
89 kfree(dma_data);
90 return ret;
91 }
92
93 snd_dmaengine_pcm_set_data(substream, dma_data);
94
95 return 0;
96}
97
98static int ep93xx_pcm_close(struct snd_pcm_substream *substream)
99{
100 struct dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
101
102 snd_dmaengine_pcm_close(substream);
103 kfree(dma_data);
104 return 0;
105} 75}
106 76
107static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream, 77static int ep93xx_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -131,7 +101,7 @@ static int ep93xx_pcm_mmap(struct snd_pcm_substream *substream,
131 101
132static struct snd_pcm_ops ep93xx_pcm_ops = { 102static struct snd_pcm_ops ep93xx_pcm_ops = {
133 .open = ep93xx_pcm_open, 103 .open = ep93xx_pcm_open,
134 .close = ep93xx_pcm_close, 104 .close = snd_dmaengine_pcm_close_release_chan,
135 .ioctl = snd_pcm_lib_ioctl, 105 .ioctl = snd_pcm_lib_ioctl,
136 .hw_params = ep93xx_pcm_hw_params, 106 .hw_params = ep93xx_pcm_hw_params,
137 .hw_free = ep93xx_pcm_hw_free, 107 .hw_free = ep93xx_pcm_hw_free,
diff --git a/sound/soc/cirrus/ep93xx-pcm.h b/sound/soc/cirrus/ep93xx-pcm.h
deleted file mode 100644
index 111e1121ecb8..000000000000
--- a/sound/soc/cirrus/ep93xx-pcm.h
+++ /dev/null
@@ -1,20 +0,0 @@
1/*
2 * sound/soc/ep93xx/ep93xx-pcm.h - EP93xx ALSA PCM interface
3 *
4 * Copyright (C) 2006 Lennert Buytenhek <buytenh@wantstofly.org>
5 * Copyright (C) 2006 Applied Data Systems
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#ifndef _EP93XX_SND_SOC_PCM_H
13#define _EP93XX_SND_SOC_PCM_H
14
15struct ep93xx_pcm_dma_params {
16 char *name;
17 int dma_port;
18};
19
20#endif /* _EP93XX_SND_SOC_PCM_H */
diff --git a/sound/soc/cirrus/simone.c b/sound/soc/cirrus/simone.c
index a397bb0d8179..4d094d00c34a 100644
--- a/sound/soc/cirrus/simone.c
+++ b/sound/soc/cirrus/simone.c
@@ -21,8 +21,6 @@
21#include <asm/mach-types.h> 21#include <asm/mach-types.h>
22#include <mach/hardware.h> 22#include <mach/hardware.h>
23 23
24#include "ep93xx-pcm.h"
25
26static struct snd_soc_dai_link simone_dai = { 24static struct snd_soc_dai_link simone_dai = {
27 .name = "AC97", 25 .name = "AC97",
28 .stream_name = "AC97 HiFi", 26 .stream_name = "AC97 HiFi",
diff --git a/sound/soc/cirrus/snappercl15.c b/sound/soc/cirrus/snappercl15.c
index 9d77fe28dfcc..69041074f2c1 100644
--- a/sound/soc/cirrus/snappercl15.c
+++ b/sound/soc/cirrus/snappercl15.c
@@ -21,7 +21,6 @@
21#include <mach/hardware.h> 21#include <mach/hardware.h>
22 22
23#include "../codecs/tlv320aic23.h" 23#include "../codecs/tlv320aic23.h"
24#include "ep93xx-pcm.h"
25 24
26#define CODEC_CLOCK 5644800 25#define CODEC_CLOCK 5644800
27 26
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 7decbd9b2340..ab27ffab83f3 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -27,6 +27,7 @@
27#include <sound/pcm_params.h> 27#include <sound/pcm_params.h>
28#include <sound/initval.h> 28#include <sound/initval.h>
29#include <sound/soc.h> 29#include <sound/soc.h>
30#include <sound/dmaengine_pcm.h>
30 31
31#include "fsl_ssi.h" 32#include "fsl_ssi.h"
32#include "imx-pcm.h" 33#include "imx-pcm.h"
@@ -122,8 +123,10 @@ struct fsl_ssi_private {
122 bool ssi_on_imx; 123 bool ssi_on_imx;
123 struct clk *clk; 124 struct clk *clk;
124 struct platform_device *imx_pcm_pdev; 125 struct platform_device *imx_pcm_pdev;
125 struct imx_pcm_dma_params dma_params_tx; 126 struct snd_dmaengine_dai_dma_data dma_params_tx;
126 struct imx_pcm_dma_params dma_params_rx; 127 struct snd_dmaengine_dai_dma_data dma_params_rx;
128 struct imx_dma_data filter_data_tx;
129 struct imx_dma_data filter_data_rx;
127 130
128 struct { 131 struct {
129 unsigned int rfrc; 132 unsigned int rfrc;
@@ -422,12 +425,6 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
422 ssi_private->second_stream = substream; 425 ssi_private->second_stream = substream;
423 } 426 }
424 427
425 if (ssi_private->ssi_on_imx)
426 snd_soc_dai_set_dma_data(dai, substream,
427 (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
428 &ssi_private->dma_params_tx :
429 &ssi_private->dma_params_rx);
430
431 return 0; 428 return 0;
432} 429}
433 430
@@ -549,6 +546,18 @@ static void fsl_ssi_shutdown(struct snd_pcm_substream *substream,
549 } 546 }
550} 547}
551 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
552static const struct snd_soc_dai_ops fsl_ssi_dai_ops = { 561static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
553 .startup = fsl_ssi_startup, 562 .startup = fsl_ssi_startup,
554 .hw_params = fsl_ssi_hw_params, 563 .hw_params = fsl_ssi_hw_params,
@@ -558,6 +567,7 @@ static const struct snd_soc_dai_ops fsl_ssi_dai_ops = {
558 567
559/* Template for the CPU dai driver structure */ 568/* Template for the CPU dai driver structure */
560static 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,
561 .playback = { 571 .playback = {
562 /* The SSI does not support monaural audio. */ 572 /* The SSI does not support monaural audio. */
563 .channels_min = 2, 573 .channels_min = 2,
@@ -649,6 +659,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
649 const uint32_t *iprop; 659 const uint32_t *iprop;
650 struct resource res; 660 struct resource res;
651 char name[64]; 661 char name[64];
662 bool shared;
652 663
653 /* SSIs that are not connected on the board should have a 664 /* SSIs that are not connected on the board should have a
654 * status = "disabled" 665 * status = "disabled"
@@ -737,14 +748,18 @@ static int fsl_ssi_probe(struct platform_device *pdev)
737 * We have burstsize be "fifo_depth - 2" to match the SSI 748 * We have burstsize be "fifo_depth - 2" to match the SSI
738 * watermark setting in fsl_ssi_startup(). 749 * watermark setting in fsl_ssi_startup().
739 */ 750 */
740 ssi_private->dma_params_tx.burstsize = 751 ssi_private->dma_params_tx.maxburst =
741 ssi_private->fifo_depth - 2; 752 ssi_private->fifo_depth - 2;
742 ssi_private->dma_params_rx.burstsize = 753 ssi_private->dma_params_rx.maxburst =
743 ssi_private->fifo_depth - 2; 754 ssi_private->fifo_depth - 2;
744 ssi_private->dma_params_tx.dma_addr = 755 ssi_private->dma_params_tx.addr =
745 ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0); 756 ssi_private->ssi_phys + offsetof(struct ccsr_ssi, stx0);
746 ssi_private->dma_params_rx.dma_addr = 757 ssi_private->dma_params_rx.addr =
747 ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0); 758 ssi_private->ssi_phys + offsetof(struct ccsr_ssi, srx0);
759 ssi_private->dma_params_tx.filter_data =
760 &ssi_private->filter_data_tx;
761 ssi_private->dma_params_rx.filter_data =
762 &ssi_private->filter_data_rx;
748 /* 763 /*
749 * TODO: This is a temporary solution and should be changed 764 * TODO: This is a temporary solution and should be changed
750 * to use generic DMA binding later when the helplers get in. 765 * to use generic DMA binding later when the helplers get in.
@@ -755,14 +770,14 @@ static int fsl_ssi_probe(struct platform_device *pdev)
755 dev_err(&pdev->dev, "could not get dma events\n"); 770 dev_err(&pdev->dev, "could not get dma events\n");
756 goto error_clk; 771 goto error_clk;
757 } 772 }
758 ssi_private->dma_params_tx.dma = dma_events[0]; 773
759 ssi_private->dma_params_rx.dma = dma_events[1]; 774 shared = of_device_is_compatible(of_get_parent(np),
760 775 "fsl,spba-bus");
761 ssi_private->dma_params_tx.shared_peripheral = 776
762 of_device_is_compatible(of_get_parent(np), 777 imx_pcm_dma_params_init_data(&ssi_private->filter_data_tx,
763 "fsl,spba-bus"); 778 dma_events[0], shared);
764 ssi_private->dma_params_rx.shared_peripheral = 779 imx_pcm_dma_params_init_data(&ssi_private->filter_data_rx,
765 ssi_private->dma_params_tx.shared_peripheral; 780 dma_events[1], shared);
766 } 781 }
767 782
768 /* Initialize the the device_attribute structure */ 783 /* Initialize the the device_attribute structure */
diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c
index 500f8ce55d78..c246fb514930 100644
--- a/sound/soc/fsl/imx-pcm-dma.c
+++ b/sound/soc/fsl/imx-pcm-dma.c
@@ -11,74 +11,30 @@
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
33#include <linux/platform_data/dma-imx.h>
34
35#include "imx-pcm.h" 23#include "imx-pcm.h"
36 24
37static bool filter(struct dma_chan *chan, void *param) 25static bool filter(struct dma_chan *chan, void *param)
38{ 26{
27 struct snd_dmaengine_dai_dma_data *dma_data = param;
28
39 if (!imx_dma_is_general_purpose(chan)) 29 if (!imx_dma_is_general_purpose(chan))
40 return false; 30 return false;
41 31
42 chan->private = param; 32 chan->private = dma_data->filter_data;
43 33
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 imx_pcm_dma_params *dma_params;
53 struct dma_slave_config slave_config;
54 int ret;
55
56 dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
57
58 ret = snd_hwparams_to_dma_slave_config(substream, params, &slave_config);
59 if (ret)
60 return ret;
61
62 slave_config.device_fc = false;
63
64 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
65 slave_config.dst_addr = dma_params->dma_addr;
66 slave_config.dst_maxburst = dma_params->burstsize;
67 } else {
68 slave_config.src_addr = dma_params->dma_addr;
69 slave_config.src_maxburst = dma_params->burstsize;
70 }
71
72 ret = dmaengine_slave_config(chan, &slave_config);
73 if (ret)
74 return ret;
75
76 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
77
78 return 0;
79}
80
81static struct snd_pcm_hardware snd_imx_hardware = {
82 .info = SNDRV_PCM_INFO_INTERLEAVED | 38 .info = SNDRV_PCM_INFO_INTERLEAVED |
83 SNDRV_PCM_INFO_BLOCK_TRANSFER | 39 SNDRV_PCM_INFO_BLOCK_TRANSFER |
84 SNDRV_PCM_INFO_MMAP | 40 SNDRV_PCM_INFO_MMAP |
@@ -97,64 +53,22 @@ static struct snd_pcm_hardware snd_imx_hardware = {
97 .fifo_size = 0, 53 .fifo_size = 0,
98}; 54};
99 55
100static int snd_imx_open(struct snd_pcm_substream *substream) 56static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = {
101{ 57 .pcm_hardware = &imx_pcm_hardware,
102 struct snd_soc_pcm_runtime *rtd = substream->private_data; 58 .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config,
103 struct imx_pcm_dma_params *dma_params; 59 .compat_filter_fn = filter,
104 struct imx_dma_data *dma_data; 60 .prealloc_buffer_size = IMX_SSI_DMABUF_SIZE,
105 int ret; 61};
106
107 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
108
109 dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
110
111 dma_data = kzalloc(sizeof(*dma_data), GFP_KERNEL);
112 if (!dma_data)
113 return -ENOMEM;
114
115 dma_data->peripheral_type = dma_params->shared_peripheral ?
116 IMX_DMATYPE_SSI_SP : IMX_DMATYPE_SSI;
117 dma_data->priority = DMA_PRIO_HIGH;
118 dma_data->dma_request = dma_params->dma;
119
120 ret = snd_dmaengine_pcm_open(substream, filter, dma_data);
121 if (ret) {
122 kfree(dma_data);
123 return ret;
124 }
125
126 snd_dmaengine_pcm_set_data(substream, dma_data);
127
128 return 0;
129}
130 62
131static int snd_imx_close(struct snd_pcm_substream *substream) 63int imx_pcm_dma_init(struct platform_device *pdev)
132{ 64{
133 struct imx_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream); 65 return snd_dmaengine_pcm_register(&pdev->dev, &imx_dmaengine_pcm_config,
134 66 SND_DMAENGINE_PCM_FLAG_NO_RESIDUE |
135 snd_dmaengine_pcm_close(substream); 67 SND_DMAENGINE_PCM_FLAG_NO_DT |
136 kfree(dma_data); 68 SND_DMAENGINE_PCM_FLAG_COMPAT);
137
138 return 0;
139} 69}
140 70
141static struct snd_pcm_ops imx_pcm_ops = { 71void imx_pcm_dma_exit(struct platform_device *pdev)
142 .open = snd_imx_open,
143 .close = snd_imx_close,
144 .ioctl = snd_pcm_lib_ioctl,
145 .hw_params = snd_imx_pcm_hw_params,
146 .trigger = snd_dmaengine_pcm_trigger,
147 .pointer = snd_dmaengine_pcm_pointer_no_residue,
148 .mmap = snd_imx_pcm_mmap,
149};
150
151static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
152 .ops = &imx_pcm_ops,
153 .pcm_new = imx_pcm_new,
154 .pcm_free = imx_pcm_free,
155};
156
157int imx_pcm_dma_init(struct platform_device *pdev)
158{ 72{
159 return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2); 73 snd_dmaengine_pcm_unregister(&pdev->dev);
160} 74}
diff --git a/sound/soc/fsl/imx-pcm-fiq.c b/sound/soc/fsl/imx-pcm-fiq.c
index 920f945cb2f4..025d0d9494f4 100644
--- a/sound/soc/fsl/imx-pcm-fiq.c
+++ b/sound/soc/fsl/imx-pcm-fiq.c
@@ -299,8 +299,8 @@ int imx_pcm_fiq_init(struct platform_device *pdev)
299 299
300 imx_ssi_fiq_base = (unsigned long)ssi->base; 300 imx_ssi_fiq_base = (unsigned long)ssi->base;
301 301
302 ssi->dma_params_tx.burstsize = 4; 302 ssi->dma_params_tx.maxburst = 4;
303 ssi->dma_params_rx.burstsize = 6; 303 ssi->dma_params_rx.maxburst = 6;
304 304
305 ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq); 305 ret = snd_soc_register_platform(&pdev->dev, &imx_soc_platform_fiq);
306 if (ret) 306 if (ret)
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 5ae13a13a353..b7fa0d75c687 100644
--- a/sound/soc/fsl/imx-pcm.h
+++ b/sound/soc/fsl/imx-pcm.h
@@ -13,17 +13,24 @@
13#ifndef _IMX_PCM_H 13#ifndef _IMX_PCM_H
14#define _IMX_PCM_H 14#define _IMX_PCM_H
15 15
16#include <linux/platform_data/dma-imx.h>
17
16/* 18/*
17 * Do not change this as the FIQ handler depends on this size 19 * Do not change this as the FIQ handler depends on this size
18 */ 20 */
19#define IMX_SSI_DMABUF_SIZE (64 * 1024) 21#define IMX_SSI_DMABUF_SIZE (64 * 1024)
20 22
21struct imx_pcm_dma_params { 23static inline void
22 int dma; 24imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data,
23 unsigned long dma_addr; 25 int dma, bool shared)
24 int burstsize; 26{
25 bool shared_peripheral; /* The peripheral is on SPBA bus */ 27 dma_data->dma_request = dma;
26}; 28 dma_data->priority = DMA_PRIO_HIGH;
29 if (shared)
30 dma_data->peripheral_type = IMX_DMATYPE_SSI_SP;
31 else
32 dma_data->peripheral_type = IMX_DMATYPE_SSI;
33}
27 34
28int snd_imx_pcm_mmap(struct snd_pcm_substream *substream, 35int snd_imx_pcm_mmap(struct snd_pcm_substream *substream,
29 struct vm_area_struct *vma); 36 struct vm_area_struct *vma);
@@ -32,11 +39,16 @@ void imx_pcm_free(struct snd_pcm *pcm);
32 39
33#ifdef CONFIG_SND_SOC_IMX_PCM_DMA 40#ifdef CONFIG_SND_SOC_IMX_PCM_DMA
34int 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);
35#else 43#else
36static inline int imx_pcm_dma_init(struct platform_device *pdev) 44static inline int imx_pcm_dma_init(struct platform_device *pdev)
37{ 45{
38 return -ENODEV; 46 return -ENODEV;
39} 47}
48
49static inline void imx_pcm_dma_exit(struct platform_device *pdev)
50{
51}
40#endif 52#endif
41 53
42#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 810c7eeb7b03..9128b7b26ecf 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 imx_pcm_dma_params *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,
@@ -369,10 +351,14 @@ static int imx_ssi_dai_probe(struct snd_soc_dai *dai)
369 351
370 snd_soc_dai_set_drvdata(dai, ssi); 352 snd_soc_dai_set_drvdata(dai, ssi);
371 353
372 val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.burstsize) | 354 val = SSI_SFCSR_TFWM0(ssi->dma_params_tx.maxburst) |
373 SSI_SFCSR_RFWM0(ssi->dma_params_rx.burstsize); 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
@@ -575,19 +561,26 @@ static int imx_ssi_probe(struct platform_device *pdev)
575 561
576 writel(0x0, ssi->base + SSI_SIER); 562 writel(0x0, ssi->base + SSI_SIER);
577 563
578 ssi->dma_params_rx.dma_addr = res->start + SSI_SRX0; 564 ssi->dma_params_rx.addr = res->start + SSI_SRX0;
579 ssi->dma_params_tx.dma_addr = res->start + SSI_STX0; 565 ssi->dma_params_tx.addr = res->start + SSI_STX0;
566
567 ssi->dma_params_tx.maxburst = 6;
568 ssi->dma_params_rx.maxburst = 4;
580 569
581 ssi->dma_params_tx.burstsize = 6; 570 ssi->dma_params_tx.filter_data = &ssi->filter_data_tx;
582 ssi->dma_params_rx.burstsize = 4; 571 ssi->dma_params_rx.filter_data = &ssi->filter_data_rx;
583 572
584 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0"); 573 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx0");
585 if (res) 574 if (res) {
586 ssi->dma_params_tx.dma = res->start; 575 imx_pcm_dma_params_init_data(&ssi->filter_data_tx, res->start,
576 false);
577 }
587 578
588 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0"); 579 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "rx0");
589 if (res) 580 if (res) {
590 ssi->dma_params_rx.dma = res->start; 581 imx_pcm_dma_params_init_data(&ssi->filter_data_rx, res->start,
582 false);
583 }
591 584
592 platform_set_drvdata(pdev, ssi); 585 platform_set_drvdata(pdev, ssi);
593 586
diff --git a/sound/soc/fsl/imx-ssi.h b/sound/soc/fsl/imx-ssi.h
index dc114bdedce5..bb6b3dbb13fd 100644
--- a/sound/soc/fsl/imx-ssi.h
+++ b/sound/soc/fsl/imx-ssi.h
@@ -187,6 +187,7 @@
187 187
188#include <linux/dmaengine.h> 188#include <linux/dmaengine.h>
189#include <linux/platform_data/dma-imx.h> 189#include <linux/platform_data/dma-imx.h>
190#include <sound/dmaengine_pcm.h>
190#include "imx-pcm.h" 191#include "imx-pcm.h"
191 192
192struct imx_ssi { 193struct imx_ssi {
@@ -204,8 +205,10 @@ struct imx_ssi {
204 void (*ac97_reset) (struct snd_ac97 *ac97); 205 void (*ac97_reset) (struct snd_ac97 *ac97);
205 void (*ac97_warm_reset)(struct snd_ac97 *ac97); 206 void (*ac97_warm_reset)(struct snd_ac97 *ac97);
206 207
207 struct imx_pcm_dma_params dma_params_rx; 208 struct snd_dmaengine_dai_dma_data dma_params_rx;
208 struct imx_pcm_dma_params dma_params_tx; 209 struct snd_dmaengine_dai_dma_data dma_params_tx;
210 struct imx_dma_data filter_data_tx;
211 struct imx_dma_data filter_data_rx;
209 212
210 int enabled; 213 int enabled;
211 214
diff --git a/sound/soc/mxs/mxs-pcm.c b/sound/soc/mxs/mxs-pcm.c
index 564b5b60319d..7bceb16d0fd9 100644
--- a/sound/soc/mxs/mxs-pcm.c
+++ b/sound/soc/mxs/mxs-pcm.c
@@ -28,7 +28,6 @@
28#include <linux/platform_device.h> 28#include <linux/platform_device.h>
29#include <linux/slab.h> 29#include <linux/slab.h>
30#include <linux/dmaengine.h> 30#include <linux/dmaengine.h>
31#include <linux/fsl/mxs-dma.h>
32 31
33#include <sound/core.h> 32#include <sound/core.h>
34#include <sound/initval.h> 33#include <sound/initval.h>
@@ -39,11 +38,6 @@
39 38
40#include "mxs-pcm.h" 39#include "mxs-pcm.h"
41 40
42struct mxs_pcm_dma_data {
43 struct mxs_dma_data dma_data;
44 struct mxs_pcm_dma_params *dma_params;
45};
46
47static struct snd_pcm_hardware snd_mxs_hardware = { 41static struct snd_pcm_hardware snd_mxs_hardware = {
48 .info = SNDRV_PCM_INFO_MMAP | 42 .info = SNDRV_PCM_INFO_MMAP |
49 SNDRV_PCM_INFO_MMAP_VALID | 43 SNDRV_PCM_INFO_MMAP_VALID |
@@ -66,8 +60,7 @@ static struct snd_pcm_hardware snd_mxs_hardware = {
66 60
67static bool filter(struct dma_chan *chan, void *param) 61static bool filter(struct dma_chan *chan, void *param)
68{ 62{
69 struct mxs_pcm_dma_data *pcm_dma_data = param; 63 struct mxs_pcm_dma_params *dma_params = param;
70 struct mxs_pcm_dma_params *dma_params = pcm_dma_data->dma_params;
71 64
72 if (!mxs_dma_is_apbx(chan)) 65 if (!mxs_dma_is_apbx(chan))
73 return false; 66 return false;
@@ -75,7 +68,7 @@ static bool filter(struct dma_chan *chan, void *param)
75 if (chan->chan_id != dma_params->chan_num) 68 if (chan->chan_id != dma_params->chan_num)
76 return false; 69 return false;
77 70
78 chan->private = &pcm_dma_data->dma_data; 71 chan->private = &dma_params->dma_data;
79 72
80 return true; 73 return true;
81} 74}
@@ -91,37 +84,11 @@ static int snd_mxs_pcm_hw_params(struct snd_pcm_substream *substream,
91static int snd_mxs_open(struct snd_pcm_substream *substream) 84static int snd_mxs_open(struct snd_pcm_substream *substream)
92{ 85{
93 struct snd_soc_pcm_runtime *rtd = substream->private_data; 86 struct snd_soc_pcm_runtime *rtd = substream->private_data;
94 struct mxs_pcm_dma_data *pcm_dma_data;
95 int ret;
96
97 pcm_dma_data = kzalloc(sizeof(*pcm_dma_data), GFP_KERNEL);
98 if (pcm_dma_data == NULL)
99 return -ENOMEM;
100
101 pcm_dma_data->dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
102 pcm_dma_data->dma_data.chan_irq = pcm_dma_data->dma_params->chan_irq;
103
104 ret = snd_dmaengine_pcm_open(substream, filter, pcm_dma_data);
105 if (ret) {
106 kfree(pcm_dma_data);
107 return ret;
108 }
109 87
110 snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware); 88 snd_soc_set_runtime_hwparams(substream, &snd_mxs_hardware);
111 89
112 snd_dmaengine_pcm_set_data(substream, pcm_dma_data); 90 return snd_dmaengine_pcm_open_request_chan(substream, filter,
113 91 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream));
114 return 0;
115}
116
117static int snd_mxs_close(struct snd_pcm_substream *substream)
118{
119 struct mxs_pcm_dma_data *pcm_dma_data = snd_dmaengine_pcm_get_data(substream);
120
121 snd_dmaengine_pcm_close(substream);
122 kfree(pcm_dma_data);
123
124 return 0;
125} 92}
126 93
127static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream, 94static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
@@ -137,7 +104,7 @@ static int snd_mxs_pcm_mmap(struct snd_pcm_substream *substream,
137 104
138static struct snd_pcm_ops mxs_pcm_ops = { 105static struct snd_pcm_ops mxs_pcm_ops = {
139 .open = snd_mxs_open, 106 .open = snd_mxs_open,
140 .close = snd_mxs_close, 107 .close = snd_dmaengine_pcm_close_release_chan,
141 .ioctl = snd_pcm_lib_ioctl, 108 .ioctl = snd_pcm_lib_ioctl,
142 .hw_params = snd_mxs_pcm_hw_params, 109 .hw_params = snd_mxs_pcm_hw_params,
143 .trigger = snd_dmaengine_pcm_trigger, 110 .trigger = snd_dmaengine_pcm_trigger,
diff --git a/sound/soc/mxs/mxs-pcm.h b/sound/soc/mxs/mxs-pcm.h
index 35ba2ca42384..3aa918f9ed3e 100644
--- a/sound/soc/mxs/mxs-pcm.h
+++ b/sound/soc/mxs/mxs-pcm.h
@@ -19,8 +19,10 @@
19#ifndef _MXS_PCM_H 19#ifndef _MXS_PCM_H
20#define _MXS_PCM_H 20#define _MXS_PCM_H
21 21
22#include <linux/fsl/mxs-dma.h>
23
22struct mxs_pcm_dma_params { 24struct mxs_pcm_dma_params {
23 int chan_irq; 25 struct mxs_dma_data dma_data;
24 int chan_num; 26 int chan_num;
25}; 27};
26 28
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 3a2aa1d19b93..f13bd8730b0f 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -753,9 +753,9 @@ static int mxs_saif_probe(struct platform_device *pdev)
753 return ret; 753 return ret;
754 } 754 }
755 755
756 saif->dma_param.chan_irq = platform_get_irq(pdev, 1); 756 saif->dma_param.dma_data.chan_irq = platform_get_irq(pdev, 1);
757 if (saif->dma_param.chan_irq < 0) { 757 if (saif->dma_param.dma_data.chan_irq < 0) {
758 ret = saif->dma_param.chan_irq; 758 ret = saif->dma_param.dma_data.chan_irq;
759 dev_err(&pdev->dev, "failed to get dma irq resource: %d\n", 759 dev_err(&pdev->dev, "failed to get dma irq resource: %d\n",
760 ret); 760 ret);
761 return ret; 761 return ret;
diff --git a/sound/soc/omap/am3517evm.c b/sound/soc/omap/am3517evm.c
index c1900b2a6f28..994dcf345975 100644
--- a/sound/soc/omap/am3517evm.c
+++ b/sound/soc/omap/am3517evm.c
@@ -28,7 +28,6 @@
28#include <linux/platform_data/asoc-ti-mcbsp.h> 28#include <linux/platform_data/asoc-ti-mcbsp.h>
29 29
30#include "omap-mcbsp.h" 30#include "omap-mcbsp.h"
31#include "omap-pcm.h"
32 31
33#include "../codecs/tlv320aic23.h" 32#include "../codecs/tlv320aic23.h"
34 33
diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c
index 2600447fa74f..629446482a91 100644
--- a/sound/soc/omap/ams-delta.c
+++ b/sound/soc/omap/ams-delta.c
@@ -36,7 +36,6 @@
36#include <linux/platform_data/asoc-ti-mcbsp.h> 36#include <linux/platform_data/asoc-ti-mcbsp.h>
37 37
38#include "omap-mcbsp.h" 38#include "omap-mcbsp.h"
39#include "omap-pcm.h"
40#include "../codecs/cx20442.h" 39#include "../codecs/cx20442.h"
41 40
42 41
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 285c8368cb47..eb68c7db1cf3 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -1018,9 +1018,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
1018 return -ENODEV; 1018 return -ENODEV;
1019 } 1019 }
1020 /* RX DMA request number, and port address configuration */ 1020 /* RX DMA request number, and port address configuration */
1021 mcbsp->dma_data[1].name = "Audio Capture"; 1021 mcbsp->dma_req[1] = res->start;
1022 mcbsp->dma_data[1].dma_req = res->start; 1022 mcbsp->dma_data[1].filter_data = &mcbsp->dma_req[1];
1023 mcbsp->dma_data[1].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 1); 1023 mcbsp->dma_data[1].addr = omap_mcbsp_dma_reg_params(mcbsp, 1);
1024 mcbsp->dma_data[1].maxburst = 4;
1024 1025
1025 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx"); 1026 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "tx");
1026 if (!res) { 1027 if (!res) {
@@ -1028,9 +1029,10 @@ int omap_mcbsp_init(struct platform_device *pdev)
1028 return -ENODEV; 1029 return -ENODEV;
1029 } 1030 }
1030 /* TX DMA request number, and port address configuration */ 1031 /* TX DMA request number, and port address configuration */
1031 mcbsp->dma_data[0].name = "Audio Playback"; 1032 mcbsp->dma_req[0] = res->start;
1032 mcbsp->dma_data[0].dma_req = res->start; 1033 mcbsp->dma_data[0].filter_data = &mcbsp->dma_req[0];
1033 mcbsp->dma_data[0].port_addr = omap_mcbsp_dma_reg_params(mcbsp, 0); 1034 mcbsp->dma_data[0].addr = omap_mcbsp_dma_reg_params(mcbsp, 0);
1035 mcbsp->dma_data[0].maxburst = 4;
1034 1036
1035 mcbsp->fclk = clk_get(&pdev->dev, "fck"); 1037 mcbsp->fclk = clk_get(&pdev->dev, "fck");
1036 if (IS_ERR(mcbsp->fclk)) { 1038 if (IS_ERR(mcbsp->fclk)) {
diff --git a/sound/soc/omap/mcbsp.h b/sound/soc/omap/mcbsp.h
index f93e0b0af303..96d1b086bcf8 100644
--- a/sound/soc/omap/mcbsp.h
+++ b/sound/soc/omap/mcbsp.h
@@ -24,14 +24,14 @@
24#ifndef __ASOC_MCBSP_H 24#ifndef __ASOC_MCBSP_H
25#define __ASOC_MCBSP_H 25#define __ASOC_MCBSP_H
26 26
27#include "omap-pcm.h"
28
29#ifdef CONFIG_ARCH_OMAP1 27#ifdef CONFIG_ARCH_OMAP1
30#define mcbsp_omap1() 1 28#define mcbsp_omap1() 1
31#else 29#else
32#define mcbsp_omap1() 0 30#define mcbsp_omap1() 0
33#endif 31#endif
34 32
33#include <sound/dmaengine_pcm.h>
34
35/* McBSP register numbers. Register address offset = num * reg_step */ 35/* McBSP register numbers. Register address offset = num * reg_step */
36enum { 36enum {
37 /* Common registers */ 37 /* Common registers */
@@ -312,7 +312,8 @@ struct omap_mcbsp {
312 struct omap_mcbsp_platform_data *pdata; 312 struct omap_mcbsp_platform_data *pdata;
313 struct omap_mcbsp_st_data *st_data; 313 struct omap_mcbsp_st_data *st_data;
314 struct omap_mcbsp_reg_cfg cfg_regs; 314 struct omap_mcbsp_reg_cfg cfg_regs;
315 struct omap_pcm_dma_data dma_data[2]; 315 struct snd_dmaengine_dai_dma_data dma_data[2];
316 unsigned int dma_req[2];
316 int dma_op_mode; 317 int dma_op_mode;
317 u16 max_tx_thres; 318 u16 max_tx_thres;
318 u16 max_rx_thres; 319 u16 max_rx_thres;
diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c
index ee7cd53aa3ee..5e8d640d314f 100644
--- a/sound/soc/omap/n810.c
+++ b/sound/soc/omap/n810.c
@@ -34,7 +34,6 @@
34#include <linux/platform_data/asoc-ti-mcbsp.h> 34#include <linux/platform_data/asoc-ti-mcbsp.h>
35 35
36#include "omap-mcbsp.h" 36#include "omap-mcbsp.h"
37#include "omap-pcm.h"
38 37
39#define N810_HEADSET_AMP_GPIO 10 38#define N810_HEADSET_AMP_GPIO 10
40#define N810_SPEAKER_AMP_GPIO 101 39#define N810_SPEAKER_AMP_GPIO 101
diff --git a/sound/soc/omap/omap-abe-twl6040.c b/sound/soc/omap/omap-abe-twl6040.c
index e7d93fa412a9..70cd5c7b2e14 100644
--- a/sound/soc/omap/omap-abe-twl6040.c
+++ b/sound/soc/omap/omap-abe-twl6040.c
@@ -34,7 +34,6 @@
34 34
35#include "omap-dmic.h" 35#include "omap-dmic.h"
36#include "omap-mcpdm.h" 36#include "omap-mcpdm.h"
37#include "omap-pcm.h"
38#include "../codecs/twl6040.h" 37#include "../codecs/twl6040.h"
39 38
40struct abe_twl6040 { 39struct abe_twl6040 {
diff --git a/sound/soc/omap/omap-dmic.c b/sound/soc/omap/omap-dmic.c
index ba49ccd9eed9..a2597fab33a3 100644
--- a/sound/soc/omap/omap-dmic.c
+++ b/sound/soc/omap/omap-dmic.c
@@ -39,8 +39,8 @@
39#include <sound/pcm_params.h> 39#include <sound/pcm_params.h>
40#include <sound/initval.h> 40#include <sound/initval.h>
41#include <sound/soc.h> 41#include <sound/soc.h>
42#include <sound/dmaengine_pcm.h>
42 43
43#include "omap-pcm.h"
44#include "omap-dmic.h" 44#include "omap-dmic.h"
45 45
46struct omap_dmic { 46struct omap_dmic {
@@ -55,13 +55,9 @@ struct omap_dmic {
55 u32 ch_enabled; 55 u32 ch_enabled;
56 bool active; 56 bool active;
57 struct mutex mutex; 57 struct mutex mutex;
58};
59 58
60/* 59 struct snd_dmaengine_dai_dma_data dma_data;
61 * Stream DMA parameters 60 unsigned int dma_req;
62 */
63static struct omap_pcm_dma_data omap_dmic_dai_dma_params = {
64 .name = "DMIC capture",
65}; 61};
66 62
67static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val) 63static inline void omap_dmic_write(struct omap_dmic *dmic, u16 reg, u32 val)
@@ -118,7 +114,7 @@ static int omap_dmic_dai_startup(struct snd_pcm_substream *substream,
118 114
119 mutex_unlock(&dmic->mutex); 115 mutex_unlock(&dmic->mutex);
120 116
121 snd_soc_dai_set_dma_data(dai, substream, &omap_dmic_dai_dma_params); 117 snd_soc_dai_set_dma_data(dai, substream, &dmic->dma_data);
122 return ret; 118 return ret;
123} 119}
124 120
@@ -203,7 +199,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
203 struct snd_soc_dai *dai) 199 struct snd_soc_dai *dai)
204{ 200{
205 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai); 201 struct omap_dmic *dmic = snd_soc_dai_get_drvdata(dai);
206 struct omap_pcm_dma_data *dma_data; 202 struct snd_dmaengine_dai_dma_data *dma_data;
207 int channels; 203 int channels;
208 204
209 dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params)); 205 dmic->clk_div = omap_dmic_select_divider(dmic, params_rate(params));
@@ -230,7 +226,7 @@ static int omap_dmic_dai_hw_params(struct snd_pcm_substream *substream,
230 226
231 /* packet size is threshold * channels */ 227 /* packet size is threshold * channels */
232 dma_data = snd_soc_dai_get_dma_data(dai, substream); 228 dma_data = snd_soc_dai_get_dma_data(dai, substream);
233 dma_data->packet_size = dmic->threshold * channels; 229 dma_data->maxburst = dmic->threshold * channels;
234 230
235 return 0; 231 return 0;
236} 232}
@@ -476,7 +472,7 @@ static int asoc_dmic_probe(struct platform_device *pdev)
476 ret = -ENODEV; 472 ret = -ENODEV;
477 goto err_put_clk; 473 goto err_put_clk;
478 } 474 }
479 omap_dmic_dai_dma_params.port_addr = res->start + OMAP_DMIC_DATA_REG; 475 dmic->dma_data.addr = res->start + OMAP_DMIC_DATA_REG;
480 476
481 res = platform_get_resource(pdev, IORESOURCE_DMA, 0); 477 res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
482 if (!res) { 478 if (!res) {
@@ -484,7 +480,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
484 ret = -ENODEV; 480 ret = -ENODEV;
485 goto err_put_clk; 481 goto err_put_clk;
486 } 482 }
487 omap_dmic_dai_dma_params.dma_req = res->start; 483
484 dmic->dma_req = res->start;
485 dmic->dma_data.filter_data = &dmic->dma_req;
488 486
489 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 487 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
490 if (!res) { 488 if (!res) {
@@ -493,19 +491,9 @@ static int asoc_dmic_probe(struct platform_device *pdev)
493 goto err_put_clk; 491 goto err_put_clk;
494 } 492 }
495 493
496 if (!devm_request_mem_region(&pdev->dev, res->start, 494 dmic->io_base = devm_ioremap_resource(&pdev->dev, res);
497 resource_size(res), pdev->name)) { 495 if (IS_ERR(dmic->io_base))
498 dev_err(dmic->dev, "memory region already claimed\n"); 496 return PTR_ERR(dmic->io_base);
499 ret = -ENODEV;
500 goto err_put_clk;
501 }
502
503 dmic->io_base = devm_ioremap(&pdev->dev, res->start,
504 resource_size(res));
505 if (!dmic->io_base) {
506 ret = -ENOMEM;
507 goto err_put_clk;
508 }
509 497
510 ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai); 498 ret = snd_soc_register_dai(&pdev->dev, &omap_dmic_dai);
511 if (ret) 499 if (ret)
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
index 32fa840c493e..b4bfab9f33e8 100644
--- a/sound/soc/omap/omap-hdmi.c
+++ b/sound/soc/omap/omap-hdmi.c
@@ -32,15 +32,16 @@
32#include <sound/soc.h> 32#include <sound/soc.h>
33#include <sound/asound.h> 33#include <sound/asound.h>
34#include <sound/asoundef.h> 34#include <sound/asoundef.h>
35#include <sound/dmaengine_pcm.h>
35#include <video/omapdss.h> 36#include <video/omapdss.h>
36 37
37#include "omap-pcm.h"
38#include "omap-hdmi.h" 38#include "omap-hdmi.h"
39 39
40#define DRV_NAME "omap-hdmi-audio-dai" 40#define DRV_NAME "omap-hdmi-audio-dai"
41 41
42struct hdmi_priv { 42struct hdmi_priv {
43 struct omap_pcm_dma_data dma_params; 43 struct snd_dmaengine_dai_dma_data dma_data;
44 unsigned int dma_req;
44 struct omap_dss_audio dss_audio; 45 struct omap_dss_audio dss_audio;
45 struct snd_aes_iec958 iec; 46 struct snd_aes_iec958 iec;
46 struct snd_cea_861_aud_if cea; 47 struct snd_cea_861_aud_if cea;
@@ -68,7 +69,7 @@ static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
68 return -ENODEV; 69 return -ENODEV;
69 } 70 }
70 71
71 snd_soc_dai_set_dma_data(dai, substream, &priv->dma_params); 72 snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
72 73
73 return 0; 74 return 0;
74} 75}
@@ -88,25 +89,20 @@ static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
88 struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai); 89 struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
89 struct snd_aes_iec958 *iec = &priv->iec; 90 struct snd_aes_iec958 *iec = &priv->iec;
90 struct snd_cea_861_aud_if *cea = &priv->cea; 91 struct snd_cea_861_aud_if *cea = &priv->cea;
91 struct omap_pcm_dma_data *dma_data;
92 int err = 0; 92 int err = 0;
93 93
94 dma_data = snd_soc_dai_get_dma_data(dai, substream);
95
96 switch (params_format(params)) { 94 switch (params_format(params)) {
97 case SNDRV_PCM_FORMAT_S16_LE: 95 case SNDRV_PCM_FORMAT_S16_LE:
98 dma_data->packet_size = 16; 96 priv->dma_data.maxburst = 16;
99 break; 97 break;
100 case SNDRV_PCM_FORMAT_S24_LE: 98 case SNDRV_PCM_FORMAT_S24_LE:
101 dma_data->packet_size = 32; 99 priv->dma_data.maxburst = 32;
102 break; 100 break;
103 default: 101 default:
104 dev_err(dai->dev, "format not supported!\n"); 102 dev_err(dai->dev, "format not supported!\n");
105 return -EINVAL; 103 return -EINVAL;
106 } 104 }
107 105
108 dma_data->data_type = 32;
109
110 /* 106 /*
111 * fill the IEC-60958 channel status word 107 * fill the IEC-60958 channel status word
112 */ 108 */
@@ -283,8 +279,7 @@ static int omap_hdmi_probe(struct platform_device *pdev)
283 return -ENODEV; 279 return -ENODEV;
284 } 280 }
285 281
286 hdmi_data->dma_params.port_addr = hdmi_rsrc->start 282 hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
287 + OMAP_HDMI_AUDIO_DMA_PORT;
288 283
289 hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0); 284 hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
290 if (!hdmi_rsrc) { 285 if (!hdmi_rsrc) {
@@ -292,8 +287,9 @@ static int omap_hdmi_probe(struct platform_device *pdev)
292 return -ENODEV; 287 return -ENODEV;
293 } 288 }
294 289
295 hdmi_data->dma_params.dma_req = hdmi_rsrc->start; 290 hdmi_data->dma_req = hdmi_rsrc->start;
296 hdmi_data->dma_params.name = "HDMI playback"; 291 hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
292 hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
297 293
298 /* 294 /*
299 * TODO: We assume that there is only one DSS HDMI device. Future 295 * TODO: We assume that there is only one DSS HDMI device. Future
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index 8d2defd6fdbe..1e7b3e89e04f 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -33,11 +33,11 @@
33#include <sound/pcm_params.h> 33#include <sound/pcm_params.h>
34#include <sound/initval.h> 34#include <sound/initval.h>
35#include <sound/soc.h> 35#include <sound/soc.h>
36#include <sound/dmaengine_pcm.h>
36 37
37#include <linux/platform_data/asoc-ti-mcbsp.h> 38#include <linux/platform_data/asoc-ti-mcbsp.h>
38#include "mcbsp.h" 39#include "mcbsp.h"
39#include "omap-mcbsp.h" 40#include "omap-mcbsp.h"
40#include "omap-pcm.h"
41 41
42#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) 42#define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000)
43 43
@@ -62,24 +62,22 @@ enum {
62 * Stream DMA parameters. DMA request line and port address are set runtime 62 * Stream DMA parameters. DMA request line and port address are set runtime
63 * since they are different between OMAP1 and later OMAPs 63 * since they are different between OMAP1 and later OMAPs
64 */ 64 */
65static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream) 65static void omap_mcbsp_set_threshold(struct snd_pcm_substream *substream,
66 unsigned int packet_size)
66{ 67{
67 struct snd_soc_pcm_runtime *rtd = substream->private_data; 68 struct snd_soc_pcm_runtime *rtd = substream->private_data;
68 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 69 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
69 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 70 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
70 struct omap_pcm_dma_data *dma_data;
71 int words; 71 int words;
72 72
73 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
74
75 /* 73 /*
76 * Configure McBSP threshold based on either: 74 * Configure McBSP threshold based on either:
77 * packet_size, when the sDMA is in packet mode, or based on the 75 * packet_size, when the sDMA is in packet mode, or based on the
78 * period size in THRESHOLD mode, otherwise use McBSP threshold = 1 76 * period size in THRESHOLD mode, otherwise use McBSP threshold = 1
79 * for mono streams. 77 * for mono streams.
80 */ 78 */
81 if (dma_data->packet_size) 79 if (packet_size)
82 words = dma_data->packet_size; 80 words = packet_size;
83 else 81 else
84 words = 1; 82 words = 1;
85 83
@@ -226,7 +224,7 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
226{ 224{
227 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai); 225 struct omap_mcbsp *mcbsp = snd_soc_dai_get_drvdata(cpu_dai);
228 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs; 226 struct omap_mcbsp_reg_cfg *regs = &mcbsp->cfg_regs;
229 struct omap_pcm_dma_data *dma_data; 227 struct snd_dmaengine_dai_dma_data *dma_data;
230 int wlen, channels, wpf; 228 int wlen, channels, wpf;
231 int pkt_size = 0; 229 int pkt_size = 0;
232 unsigned int format, div, framesize, master; 230 unsigned int format, div, framesize, master;
@@ -245,7 +243,6 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
245 return -EINVAL; 243 return -EINVAL;
246 } 244 }
247 if (mcbsp->pdata->buffer_size) { 245 if (mcbsp->pdata->buffer_size) {
248 dma_data->set_threshold = omap_mcbsp_set_threshold;
249 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) { 246 if (mcbsp->dma_op_mode == MCBSP_DMA_MODE_THRESHOLD) {
250 int period_words, max_thrsh; 247 int period_words, max_thrsh;
251 int divider = 0; 248 int divider = 0;
@@ -276,9 +273,10 @@ static int omap_mcbsp_dai_hw_params(struct snd_pcm_substream *substream,
276 /* Use packet mode for non mono streams */ 273 /* Use packet mode for non mono streams */
277 pkt_size = channels; 274 pkt_size = channels;
278 } 275 }
276 omap_mcbsp_set_threshold(substream, pkt_size);
279 } 277 }
280 278
281 dma_data->packet_size = pkt_size; 279 dma_data->maxburst = pkt_size;
282 280
283 if (mcbsp->configured) { 281 if (mcbsp->configured) {
284 /* McBSP already configured by another stream */ 282 /* McBSP already configured by another stream */
diff --git a/sound/soc/omap/omap-mcpdm.c b/sound/soc/omap/omap-mcpdm.c
index 5ca11bdac21e..49f102a1dbae 100644
--- a/sound/soc/omap/omap-mcpdm.c
+++ b/sound/soc/omap/omap-mcpdm.c
@@ -39,11 +39,14 @@
39#include <sound/pcm.h> 39#include <sound/pcm.h>
40#include <sound/pcm_params.h> 40#include <sound/pcm_params.h>
41#include <sound/soc.h> 41#include <sound/soc.h>
42#include <sound/dmaengine_pcm.h>
42 43
43#include "omap-mcpdm.h" 44#include "omap-mcpdm.h"
44#include "omap-pcm.h"
45 45
46#define OMAP44XX_MCPDM_L3_BASE 0x49032000 46struct mcpdm_link_config {
47 u32 link_mask; /* channel mask for the direction */
48 u32 threshold; /* FIFO threshold */
49};
47 50
48struct omap_mcpdm { 51struct omap_mcpdm {
49 struct device *dev; 52 struct device *dev;
@@ -53,29 +56,22 @@ struct omap_mcpdm {
53 56
54 struct mutex mutex; 57 struct mutex mutex;
55 58
56 /* channel data */ 59 /* Playback/Capture configuration */
57 u32 dn_channels; 60 struct mcpdm_link_config config[2];
58 u32 up_channels;
59
60 /* McPDM FIFO thresholds */
61 u32 dn_threshold;
62 u32 up_threshold;
63 61
64 /* McPDM dn offsets for rx1, and 2 channels */ 62 /* McPDM dn offsets for rx1, and 2 channels */
65 u32 dn_rx_offset; 63 u32 dn_rx_offset;
64
65 /* McPDM needs to be restarted due to runtime reconfiguration */
66 bool restart;
67
68 struct snd_dmaengine_dai_dma_data dma_data[2];
69 unsigned int dma_req[2];
66}; 70};
67 71
68/* 72/*
69 * Stream DMA parameters 73 * Stream DMA parameters
70 */ 74 */
71static struct omap_pcm_dma_data omap_mcpdm_dai_dma_params[] = {
72 {
73 .name = "Audio playback",
74 },
75 {
76 .name = "Audio capture",
77 },
78};
79 75
80static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val) 76static inline void omap_mcpdm_write(struct omap_mcpdm *mcpdm, u16 reg, u32 val)
81{ 77{
@@ -130,11 +126,12 @@ static void omap_mcpdm_reg_dump(struct omap_mcpdm *mcpdm) {}
130static void omap_mcpdm_start(struct omap_mcpdm *mcpdm) 126static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
131{ 127{
132 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 128 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
129 u32 link_mask = mcpdm->config[0].link_mask | mcpdm->config[1].link_mask;
133 130
134 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 131 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
135 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 132 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
136 133
137 ctrl |= mcpdm->dn_channels | mcpdm->up_channels; 134 ctrl |= link_mask;
138 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 135 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
139 136
140 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 137 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -148,11 +145,12 @@ static void omap_mcpdm_start(struct omap_mcpdm *mcpdm)
148static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm) 145static void omap_mcpdm_stop(struct omap_mcpdm *mcpdm)
149{ 146{
150 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL); 147 u32 ctrl = omap_mcpdm_read(mcpdm, MCPDM_REG_CTRL);
148 u32 link_mask = MCPDM_PDM_DN_MASK | MCPDM_PDM_UP_MASK;
151 149
152 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 150 ctrl |= (MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
153 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 151 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
154 152
155 ctrl &= ~(mcpdm->dn_channels | mcpdm->up_channels); 153 ctrl &= ~(link_mask);
156 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl); 154 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, ctrl);
157 155
158 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST); 156 ctrl &= ~(MCPDM_SW_DN_RST | MCPDM_SW_UP_RST);
@@ -188,8 +186,10 @@ static void omap_mcpdm_open_streams(struct omap_mcpdm *mcpdm)
188 omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset); 186 omap_mcpdm_write(mcpdm, MCPDM_REG_DN_OFFSET, dn_offset);
189 } 187 }
190 188
191 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN, mcpdm->dn_threshold); 189 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_DN,
192 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP, mcpdm->up_threshold); 190 mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold);
191 omap_mcpdm_write(mcpdm, MCPDM_REG_FIFO_CTRL_UP,
192 mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold);
193 193
194 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET, 194 omap_mcpdm_write(mcpdm, MCPDM_REG_DMAENABLE_SET,
195 MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE); 195 MCPDM_DMA_DN_ENABLE | MCPDM_DMA_UP_ENABLE);
@@ -267,7 +267,7 @@ static int omap_mcpdm_dai_startup(struct snd_pcm_substream *substream,
267 mutex_unlock(&mcpdm->mutex); 267 mutex_unlock(&mcpdm->mutex);
268 268
269 snd_soc_dai_set_dma_data(dai, substream, 269 snd_soc_dai_set_dma_data(dai, substream,
270 &omap_mcpdm_dai_dma_params[substream->stream]); 270 &mcpdm->dma_data[substream->stream]);
271 271
272 return 0; 272 return 0;
273} 273}
@@ -283,6 +283,8 @@ static void omap_mcpdm_dai_shutdown(struct snd_pcm_substream *substream,
283 if (omap_mcpdm_active(mcpdm)) { 283 if (omap_mcpdm_active(mcpdm)) {
284 omap_mcpdm_stop(mcpdm); 284 omap_mcpdm_stop(mcpdm);
285 omap_mcpdm_close_streams(mcpdm); 285 omap_mcpdm_close_streams(mcpdm);
286 mcpdm->config[0].link_mask = 0;
287 mcpdm->config[1].link_mask = 0;
286 } 288 }
287 } 289 }
288 290
@@ -295,7 +297,8 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
295{ 297{
296 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 298 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
297 int stream = substream->stream; 299 int stream = substream->stream;
298 struct omap_pcm_dma_data *dma_data; 300 struct snd_dmaengine_dai_dma_data *dma_data;
301 u32 threshold;
299 int channels; 302 int channels;
300 int link_mask = 0; 303 int link_mask = 0;
301 304
@@ -325,16 +328,32 @@ static int omap_mcpdm_dai_hw_params(struct snd_pcm_substream *substream,
325 328
326 dma_data = snd_soc_dai_get_dma_data(dai, substream); 329 dma_data = snd_soc_dai_get_dma_data(dai, substream);
327 330
331 threshold = mcpdm->config[stream].threshold;
328 /* Configure McPDM channels, and DMA packet size */ 332 /* Configure McPDM channels, and DMA packet size */
329 if (stream == SNDRV_PCM_STREAM_PLAYBACK) { 333 if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
330 mcpdm->dn_channels = link_mask << 3; 334 link_mask <<= 3;
331 dma_data->packet_size = 335
332 (MCPDM_DN_THRES_MAX - mcpdm->dn_threshold) * channels; 336 /* If capture is not running assume a stereo stream to come */
337 if (!mcpdm->config[!stream].link_mask)
338 mcpdm->config[!stream].link_mask = 0x3;
339
340 dma_data->maxburst =
341 (MCPDM_DN_THRES_MAX - threshold) * channels;
333 } else { 342 } else {
334 mcpdm->up_channels = link_mask << 0; 343 /* If playback is not running assume a stereo stream to come */
335 dma_data->packet_size = mcpdm->up_threshold * channels; 344 if (!mcpdm->config[!stream].link_mask)
345 mcpdm->config[!stream].link_mask = (0x3 << 3);
346
347 dma_data->maxburst = threshold * channels;
336 } 348 }
337 349
350 /* Check if we need to restart McPDM with this stream */
351 if (mcpdm->config[stream].link_mask &&
352 mcpdm->config[stream].link_mask != link_mask)
353 mcpdm->restart = true;
354
355 mcpdm->config[stream].link_mask = link_mask;
356
338 return 0; 357 return 0;
339} 358}
340 359
@@ -346,6 +365,11 @@ static int omap_mcpdm_prepare(struct snd_pcm_substream *substream,
346 if (!omap_mcpdm_active(mcpdm)) { 365 if (!omap_mcpdm_active(mcpdm)) {
347 omap_mcpdm_start(mcpdm); 366 omap_mcpdm_start(mcpdm);
348 omap_mcpdm_reg_dump(mcpdm); 367 omap_mcpdm_reg_dump(mcpdm);
368 } else if (mcpdm->restart) {
369 omap_mcpdm_stop(mcpdm);
370 omap_mcpdm_start(mcpdm);
371 mcpdm->restart = false;
372 omap_mcpdm_reg_dump(mcpdm);
349 } 373 }
350 374
351 return 0; 375 return 0;
@@ -369,7 +393,7 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
369 pm_runtime_get_sync(mcpdm->dev); 393 pm_runtime_get_sync(mcpdm->dev);
370 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00); 394 omap_mcpdm_write(mcpdm, MCPDM_REG_CTRL, 0x00);
371 395
372 ret = request_irq(mcpdm->irq, omap_mcpdm_irq_handler, 396 ret = devm_request_irq(mcpdm->dev, mcpdm->irq, omap_mcpdm_irq_handler,
373 0, "McPDM", (void *)mcpdm); 397 0, "McPDM", (void *)mcpdm);
374 398
375 pm_runtime_put_sync(mcpdm->dev); 399 pm_runtime_put_sync(mcpdm->dev);
@@ -380,8 +404,9 @@ static int omap_mcpdm_probe(struct snd_soc_dai *dai)
380 } 404 }
381 405
382 /* Configure McPDM threshold values */ 406 /* Configure McPDM threshold values */
383 mcpdm->dn_threshold = 2; 407 mcpdm->config[SNDRV_PCM_STREAM_PLAYBACK].threshold = 2;
384 mcpdm->up_threshold = MCPDM_UP_THRES_MAX - 3; 408 mcpdm->config[SNDRV_PCM_STREAM_CAPTURE].threshold =
409 MCPDM_UP_THRES_MAX - 3;
385 return ret; 410 return ret;
386} 411}
387 412
@@ -389,7 +414,6 @@ static int omap_mcpdm_remove(struct snd_soc_dai *dai)
389{ 414{
390 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai); 415 struct omap_mcpdm *mcpdm = snd_soc_dai_get_drvdata(dai);
391 416
392 free_irq(mcpdm->irq, (void *)mcpdm);
393 pm_runtime_disable(mcpdm->dev); 417 pm_runtime_disable(mcpdm->dev);
394 418
395 return 0; 419 return 0;
@@ -446,33 +470,30 @@ static int asoc_mcpdm_probe(struct platform_device *pdev)
446 if (res == NULL) 470 if (res == NULL)
447 return -ENOMEM; 471 return -ENOMEM;
448 472
449 omap_mcpdm_dai_dma_params[0].port_addr = res->start + MCPDM_REG_DN_DATA; 473 mcpdm->dma_data[0].addr = res->start + MCPDM_REG_DN_DATA;
450 omap_mcpdm_dai_dma_params[1].port_addr = res->start + MCPDM_REG_UP_DATA; 474 mcpdm->dma_data[1].addr = res->start + MCPDM_REG_UP_DATA;
451 475
452 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link"); 476 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "dn_link");
453 if (!res) 477 if (!res)
454 return -ENODEV; 478 return -ENODEV;
455 479
456 omap_mcpdm_dai_dma_params[0].dma_req = res->start; 480 mcpdm->dma_req[0] = res->start;
481 mcpdm->dma_data[0].filter_data = &mcpdm->dma_req[0];
457 482
458 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link"); 483 res = platform_get_resource_byname(pdev, IORESOURCE_DMA, "up_link");
459 if (!res) 484 if (!res)
460 return -ENODEV; 485 return -ENODEV;
461 486
462 omap_mcpdm_dai_dma_params[1].dma_req = res->start; 487 mcpdm->dma_req[1] = res->start;
488 mcpdm->dma_data[1].filter_data = &mcpdm->dma_req[1];
463 489
464 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); 490 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu");
465 if (res == NULL) 491 if (res == NULL)
466 return -ENOMEM; 492 return -ENOMEM;
467 493
468 if (!devm_request_mem_region(&pdev->dev, res->start, 494 mcpdm->io_base = devm_ioremap_resource(&pdev->dev, res);
469 resource_size(res), "McPDM")) 495 if (IS_ERR(mcpdm->io_base))
470 return -EBUSY; 496 return PTR_ERR(mcpdm->io_base);
471
472 mcpdm->io_base = devm_ioremap(&pdev->dev, res->start,
473 resource_size(res));
474 if (!mcpdm->io_base)
475 return -ENOMEM;
476 497
477 mcpdm->irq = platform_get_irq(pdev, 0); 498 mcpdm->irq = platform_get_irq(pdev, 0);
478 if (mcpdm->irq < 0) 499 if (mcpdm->irq < 0)
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index c722c2ef9665..c28e042f2208 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -32,8 +32,6 @@
32#include <sound/dmaengine_pcm.h> 32#include <sound/dmaengine_pcm.h>
33#include <sound/soc.h> 33#include <sound/soc.h>
34 34
35#include "omap-pcm.h"
36
37#ifdef CONFIG_ARCH_OMAP1 35#ifdef CONFIG_ARCH_OMAP1
38#define pcm_omap1510() cpu_is_omap1510() 36#define pcm_omap1510() cpu_is_omap1510()
39#else 37#else
@@ -56,25 +54,6 @@ static const struct snd_pcm_hardware omap_pcm_hardware = {
56 .buffer_bytes_max = 128 * 1024, 54 .buffer_bytes_max = 128 * 1024,
57}; 55};
58 56
59static int omap_pcm_get_dma_buswidth(int num_bits)
60{
61 int buswidth;
62
63 switch (num_bits) {
64 case 16:
65 buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
66 break;
67 case 32:
68 buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
69 break;
70 default:
71 buswidth = -EINVAL;
72 break;
73 }
74 return buswidth;
75}
76
77
78/* this may get called several times by oss emulation */ 57/* this may get called several times by oss emulation */
79static int omap_pcm_hw_params(struct snd_pcm_substream *substream, 58static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
80 struct snd_pcm_hw_params *params) 59 struct snd_pcm_hw_params *params)
@@ -105,20 +84,9 @@ static int omap_pcm_hw_params(struct snd_pcm_substream *substream,
105 if (err) 84 if (err)
106 return err; 85 return err;
107 86
108 /* Override the *_dma addr_width if requested by the DAI driver */ 87 snd_dmaengine_pcm_set_config_from_dai_data(substream,
109 if (dma_data->data_type) { 88 snd_soc_dai_get_dma_data(rtd->cpu_dai, substream),
110 int buswidth = omap_pcm_get_dma_buswidth(dma_data->data_type); 89 &config);
111
112 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
113 config.dst_addr_width = buswidth;
114 else
115 config.src_addr_width = buswidth;
116 }
117
118 config.src_addr = dma_data->port_addr;
119 config.dst_addr = dma_data->port_addr;
120 config.src_maxburst = dma_data->packet_size;
121 config.dst_maxburst = dma_data->packet_size;
122 90
123 return dmaengine_slave_config(chan, &config); 91 return dmaengine_slave_config(chan, &config);
124} 92}
@@ -129,37 +97,6 @@ static int omap_pcm_hw_free(struct snd_pcm_substream *substream)
129 return 0; 97 return 0;
130} 98}
131 99
132static int omap_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
133{
134 struct snd_soc_pcm_runtime *rtd = substream->private_data;
135 struct omap_pcm_dma_data *dma_data;
136 int ret = 0;
137
138 dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
139
140 switch (cmd) {
141 case SNDRV_PCM_TRIGGER_START:
142 case SNDRV_PCM_TRIGGER_RESUME:
143 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
144 /* Configure McBSP internal buffer usage */
145 if (dma_data->set_threshold)
146 dma_data->set_threshold(substream);
147 break;
148
149 case SNDRV_PCM_TRIGGER_STOP:
150 case SNDRV_PCM_TRIGGER_SUSPEND:
151 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
152 break;
153 default:
154 ret = -EINVAL;
155 }
156
157 if (ret == 0)
158 ret = snd_dmaengine_pcm_trigger(substream, cmd);
159
160 return ret;
161}
162
163static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream) 100static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
164{ 101{
165 snd_pcm_uframes_t offset; 102 snd_pcm_uframes_t offset;
@@ -175,20 +112,15 @@ static snd_pcm_uframes_t omap_pcm_pointer(struct snd_pcm_substream *substream)
175static int omap_pcm_open(struct snd_pcm_substream *substream) 112static int omap_pcm_open(struct snd_pcm_substream *substream)
176{ 113{
177 struct snd_soc_pcm_runtime *rtd = substream->private_data; 114 struct snd_soc_pcm_runtime *rtd = substream->private_data;
178 struct omap_pcm_dma_data *dma_data; 115 struct snd_dmaengine_dai_dma_data *dma_data;
179 116
180 snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware); 117 snd_soc_set_runtime_hwparams(substream, &omap_pcm_hardware);
181 118
182 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);
183 120
184 return snd_dmaengine_pcm_open(substream, omap_dma_filter_fn, 121 return snd_dmaengine_pcm_open_request_chan(substream,
185 &dma_data->dma_req); 122 omap_dma_filter_fn,
186} 123 dma_data->filter_data);
187
188static int omap_pcm_close(struct snd_pcm_substream *substream)
189{
190 snd_dmaengine_pcm_close(substream);
191 return 0;
192} 124}
193 125
194static int omap_pcm_mmap(struct snd_pcm_substream *substream, 126static int omap_pcm_mmap(struct snd_pcm_substream *substream,
@@ -204,11 +136,11 @@ static int omap_pcm_mmap(struct snd_pcm_substream *substream,
204 136
205static struct snd_pcm_ops omap_pcm_ops = { 137static struct snd_pcm_ops omap_pcm_ops = {
206 .open = omap_pcm_open, 138 .open = omap_pcm_open,
207 .close = omap_pcm_close, 139 .close = snd_dmaengine_pcm_close_release_chan,
208 .ioctl = snd_pcm_lib_ioctl, 140 .ioctl = snd_pcm_lib_ioctl,
209 .hw_params = omap_pcm_hw_params, 141 .hw_params = omap_pcm_hw_params,
210 .hw_free = omap_pcm_hw_free, 142 .hw_free = omap_pcm_hw_free,
211 .trigger = omap_pcm_trigger, 143 .trigger = snd_dmaengine_pcm_trigger,
212 .pointer = omap_pcm_pointer, 144 .pointer = omap_pcm_pointer,
213 .mmap = omap_pcm_mmap, 145 .mmap = omap_pcm_mmap,
214}; 146};
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
deleted file mode 100644
index cabe74c4068b..000000000000
--- a/sound/soc/omap/omap-pcm.h
+++ /dev/null
@@ -1,40 +0,0 @@
1/*
2 * omap-pcm.h
3 *
4 * Copyright (C) 2008 Nokia Corporation
5 *
6 * Contact: Jarkko Nikula <jarkko.nikula@bitmer.com>
7 * Peter Ujfalusi <peter.ujfalusi@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License
11 * version 2 as published by the Free Software Foundation.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 * 02110-1301 USA
22 *
23 */
24
25#ifndef __OMAP_PCM_H__
26#define __OMAP_PCM_H__
27
28struct snd_pcm_substream;
29
30struct omap_pcm_dma_data {
31 char *name; /* stream identifier */
32 int dma_req; /* DMA request line */
33 unsigned long port_addr; /* transmit/receive register */
34 void (*set_threshold)(struct snd_pcm_substream *substream);
35 int data_type; /* 8, 16, 32 (bits) or 0 to let omap-pcm
36 * to decide the sDMA data type */
37 int packet_size; /* packet size only in PACKET mode */
38};
39
40#endif
diff --git a/sound/soc/omap/omap-twl4030.c b/sound/soc/omap/omap-twl4030.c
index fd98509d0f49..2a9324f794d8 100644
--- a/sound/soc/omap/omap-twl4030.c
+++ b/sound/soc/omap/omap-twl4030.c
@@ -43,7 +43,6 @@
43#include <sound/jack.h> 43#include <sound/jack.h>
44 44
45#include "omap-mcbsp.h" 45#include "omap-mcbsp.h"
46#include "omap-pcm.h"
47 46
48struct omap_twl4030 { 47struct omap_twl4030 {
49 int jack_detect; /* board can detect jack events */ 48 int jack_detect; /* board can detect jack events */
diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c
index 805512f2555a..cf604a2faa18 100644
--- a/sound/soc/omap/omap3pandora.c
+++ b/sound/soc/omap/omap3pandora.c
@@ -34,7 +34,6 @@
34#include <linux/platform_data/asoc-ti-mcbsp.h> 34#include <linux/platform_data/asoc-ti-mcbsp.h>
35 35
36#include "omap-mcbsp.h" 36#include "omap-mcbsp.h"
37#include "omap-pcm.h"
38 37
39#define OMAP3_PANDORA_DAC_POWER_GPIO 118 38#define OMAP3_PANDORA_DAC_POWER_GPIO 118
40#define OMAP3_PANDORA_AMP_POWER_GPIO 14 39#define OMAP3_PANDORA_AMP_POWER_GPIO 14
@@ -80,12 +79,18 @@ static int omap3pandora_hw_params(struct snd_pcm_substream *substream,
80static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w, 79static int omap3pandora_dac_event(struct snd_soc_dapm_widget *w,
81 struct snd_kcontrol *k, int event) 80 struct snd_kcontrol *k, int event)
82{ 81{
82 int ret;
83
83 /* 84 /*
84 * The PCM1773 DAC datasheet requires 1ms delay between switching 85 * The PCM1773 DAC datasheet requires 1ms delay between switching
85 * VCC power on/off and /PD pin high/low 86 * VCC power on/off and /PD pin high/low
86 */ 87 */
87 if (SND_SOC_DAPM_EVENT_ON(event)) { 88 if (SND_SOC_DAPM_EVENT_ON(event)) {
88 regulator_enable(omap3pandora_dac_reg); 89 ret = regulator_enable(omap3pandora_dac_reg);
90 if (ret) {
91 dev_err(w->dapm->dev, "Failed to power DAC: %d\n", ret);
92 return ret;
93 }
89 mdelay(1); 94 mdelay(1);
90 gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1); 95 gpio_set_value(OMAP3_PANDORA_DAC_POWER_GPIO, 1);
91 } else { 96 } else {
diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c
index 06ef8d67ed1c..d03e57da7708 100644
--- a/sound/soc/omap/osk5912.c
+++ b/sound/soc/omap/osk5912.c
@@ -33,7 +33,6 @@
33#include <linux/platform_data/asoc-ti-mcbsp.h> 33#include <linux/platform_data/asoc-ti-mcbsp.h>
34 34
35#include "omap-mcbsp.h" 35#include "omap-mcbsp.h"
36#include "omap-pcm.h"
37#include "../codecs/tlv320aic23.h" 36#include "../codecs/tlv320aic23.h"
38 37
39#define CODEC_CLOCK 12000000 38#define CODEC_CLOCK 12000000
diff --git a/sound/soc/omap/rx51.c b/sound/soc/omap/rx51.c
index 3cd525748975..249cd230ad8f 100644
--- a/sound/soc/omap/rx51.c
+++ b/sound/soc/omap/rx51.c
@@ -37,7 +37,6 @@
37#include <asm/mach-types.h> 37#include <asm/mach-types.h>
38 38
39#include "omap-mcbsp.h" 39#include "omap-mcbsp.h"
40#include "omap-pcm.h"
41 40
42#define RX51_TVOUT_SEL_GPIO 40 41#define RX51_TVOUT_SEL_GPIO 40
43#define RX51_JACK_DETECT_GPIO 177 42#define RX51_JACK_DETECT_GPIO 177
diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c
index 190eb0bccf5f..349930015264 100644
--- a/sound/soc/pxa/mmp-pcm.c
+++ b/sound/soc/pxa/mmp-pcm.c
@@ -118,9 +118,8 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
118 struct snd_soc_pcm_runtime *rtd = substream->private_data; 118 struct snd_soc_pcm_runtime *rtd = substream->private_data;
119 struct platform_device *pdev = to_platform_device(rtd->platform->dev); 119 struct platform_device *pdev = to_platform_device(rtd->platform->dev);
120 struct snd_soc_dai *cpu_dai = rtd->cpu_dai; 120 struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
121 struct mmp_dma_data *dma_data; 121 struct mmp_dma_data dma_data;
122 struct resource *r; 122 struct resource *r;
123 int ret;
124 123
125 r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream); 124 r = platform_get_resource(pdev, IORESOURCE_DMA, substream->stream);
126 if (!r) 125 if (!r)
@@ -128,33 +127,12 @@ static int mmp_pcm_open(struct snd_pcm_substream *substream)
128 127
129 snd_soc_set_runtime_hwparams(substream, 128 snd_soc_set_runtime_hwparams(substream,
130 &mmp_pcm_hardware[substream->stream]); 129 &mmp_pcm_hardware[substream->stream]);
131 dma_data = devm_kzalloc(&pdev->dev,
132 sizeof(struct mmp_dma_data), GFP_KERNEL);
133 if (dma_data == NULL)
134 return -ENOMEM;
135 130
136 dma_data->dma_res = r; 131 dma_data.dma_res = r;
137 dma_data->ssp_id = cpu_dai->id; 132 dma_data.ssp_id = cpu_dai->id;
138 133
139 ret = snd_dmaengine_pcm_open(substream, filter, dma_data); 134 return snd_dmaengine_pcm_open_request_chan(substream, filter,
140 if (ret) { 135 &dma_data);
141 devm_kfree(&pdev->dev, dma_data);
142 return ret;
143 }
144
145 snd_dmaengine_pcm_set_data(substream, dma_data);
146 return 0;
147}
148
149static int mmp_pcm_close(struct snd_pcm_substream *substream)
150{
151 struct mmp_dma_data *dma_data = snd_dmaengine_pcm_get_data(substream);
152 struct snd_soc_pcm_runtime *rtd = substream->private_data;
153 struct platform_device *pdev = to_platform_device(rtd->platform->dev);
154
155 snd_dmaengine_pcm_close(substream);
156 devm_kfree(&pdev->dev, dma_data);
157 return 0;
158} 136}
159 137
160static int mmp_pcm_mmap(struct snd_pcm_substream *substream, 138static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
@@ -171,7 +149,7 @@ static int mmp_pcm_mmap(struct snd_pcm_substream *substream,
171 149
172struct snd_pcm_ops mmp_pcm_ops = { 150struct snd_pcm_ops mmp_pcm_ops = {
173 .open = mmp_pcm_open, 151 .open = mmp_pcm_open,
174 .close = mmp_pcm_close, 152 .close = snd_dmaengine_pcm_close_release_chan,
175 .ioctl = snd_pcm_lib_ioctl, 153 .ioctl = snd_pcm_lib_ioctl,
176 .hw_params = mmp_pcm_hw_params, 154 .hw_params = mmp_pcm_hw_params,
177 .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 c70f9e072043..78468c64dd86 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3903,21 +3903,14 @@ void snd_soc_unregister_dais(struct device *dev, size_t count)
3903EXPORT_SYMBOL_GPL(snd_soc_unregister_dais); 3903EXPORT_SYMBOL_GPL(snd_soc_unregister_dais);
3904 3904
3905/** 3905/**
3906 * snd_soc_register_platform - Register a platform with the ASoC core 3906 * snd_soc_add_platform - Add a platform to the ASoC core
3907 * 3907 * @dev: The parent device for the platform
3908 * @platform: platform to register 3908 * @platform: The platform to add
3909 * @platform_driver: The driver for the platform
3909 */ 3910 */
3910int snd_soc_register_platform(struct device *dev, 3911int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform,
3911 const struct snd_soc_platform_driver *platform_drv) 3912 const struct snd_soc_platform_driver *platform_drv)
3912{ 3913{
3913 struct snd_soc_platform *platform;
3914
3915 dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
3916
3917 platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
3918 if (platform == NULL)
3919 return -ENOMEM;
3920
3921 /* create platform component name */ 3914 /* create platform component name */
3922 platform->name = fmt_single_name(dev, &platform->id); 3915 platform->name = fmt_single_name(dev, &platform->id);
3923 if (platform->name == NULL) { 3916 if (platform->name == NULL) {
@@ -3940,30 +3933,76 @@ int snd_soc_register_platform(struct device *dev,
3940 3933
3941 return 0; 3934 return 0;
3942} 3935}
3943EXPORT_SYMBOL_GPL(snd_soc_register_platform); 3936EXPORT_SYMBOL_GPL(snd_soc_add_platform);
3944 3937
3945/** 3938/**
3946 * snd_soc_unregister_platform - Unregister a platform from the ASoC core 3939 * snd_soc_register_platform - Register a platform with the ASoC core
3947 * 3940 *
3948 * @platform: platform to unregister 3941 * @platform: platform to register
3949 */ 3942 */
3950void snd_soc_unregister_platform(struct device *dev) 3943int snd_soc_register_platform(struct device *dev,
3944 const struct snd_soc_platform_driver *platform_drv)
3951{ 3945{
3952 struct snd_soc_platform *platform; 3946 struct snd_soc_platform *platform;
3947 int ret;
3953 3948
3954 list_for_each_entry(platform, &platform_list, list) { 3949 dev_dbg(dev, "ASoC: platform register %s\n", dev_name(dev));
3955 if (dev == platform->dev)
3956 goto found;
3957 }
3958 return;
3959 3950
3960found: 3951 platform = kzalloc(sizeof(struct snd_soc_platform), GFP_KERNEL);
3952 if (platform == NULL)
3953 return -ENOMEM;
3954
3955 ret = snd_soc_add_platform(dev, platform, platform_drv);
3956 if (ret)
3957 kfree(platform);
3958
3959 return ret;
3960}
3961EXPORT_SYMBOL_GPL(snd_soc_register_platform);
3962
3963/**
3964 * snd_soc_remove_platform - Remove a platform from the ASoC core
3965 * @platform: the platform to remove
3966 */
3967void snd_soc_remove_platform(struct snd_soc_platform *platform)
3968{
3961 mutex_lock(&client_mutex); 3969 mutex_lock(&client_mutex);
3962 list_del(&platform->list); 3970 list_del(&platform->list);
3963 mutex_unlock(&client_mutex); 3971 mutex_unlock(&client_mutex);
3964 3972
3965 dev_dbg(dev, "ASoC: Unregistered platform '%s'\n", platform->name); 3973 dev_dbg(platform->dev, "ASoC: Unregistered platform '%s'\n",
3974 platform->name);
3966 kfree(platform->name); 3975 kfree(platform->name);
3976}
3977EXPORT_SYMBOL_GPL(snd_soc_remove_platform);
3978
3979struct snd_soc_platform *snd_soc_lookup_platform(struct device *dev)
3980{
3981 struct snd_soc_platform *platform;
3982
3983 list_for_each_entry(platform, &platform_list, list) {
3984 if (dev == platform->dev)
3985 return platform;
3986 }
3987
3988 return NULL;
3989}
3990EXPORT_SYMBOL_GPL(snd_soc_lookup_platform);
3991
3992/**
3993 * snd_soc_unregister_platform - Unregister a platform from the ASoC core
3994 *
3995 * @platform: platform to unregister
3996 */
3997void snd_soc_unregister_platform(struct device *dev)
3998{
3999 struct snd_soc_platform *platform;
4000
4001 platform = snd_soc_lookup_platform(dev);
4002 if (!platform)
4003 return;
4004
4005 snd_soc_remove_platform(platform);
3967 kfree(platform); 4006 kfree(platform);
3968} 4007}
3969EXPORT_SYMBOL_GPL(snd_soc_unregister_platform); 4008EXPORT_SYMBOL_GPL(snd_soc_unregister_platform);
diff --git a/sound/soc/soc-dmaengine-pcm.c b/sound/soc/soc-dmaengine-pcm.c
index 111b7d921e89..aa924d9b7986 100644
--- a/sound/soc/soc-dmaengine-pcm.c
+++ b/sound/soc/soc-dmaengine-pcm.c
@@ -33,8 +33,6 @@ struct dmaengine_pcm_runtime_data {
33 dma_cookie_t cookie; 33 dma_cookie_t cookie;
34 34
35 unsigned int pos; 35 unsigned int pos;
36
37 void *data;
38}; 36};
39 37
40static inline struct dmaengine_pcm_runtime_data *substream_to_prtd( 38static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
@@ -43,33 +41,6 @@ static inline struct dmaengine_pcm_runtime_data *substream_to_prtd(
43 return substream->runtime->private_data; 41 return substream->runtime->private_data;
44} 42}
45 43
46/**
47 * snd_dmaengine_pcm_set_data - Set dmaengine substream private data
48 * @substream: PCM substream
49 * @data: Data to set
50 */
51void snd_dmaengine_pcm_set_data(struct snd_pcm_substream *substream, void *data)
52{
53 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
54
55 prtd->data = data;
56}
57EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_data);
58
59/**
60 * snd_dmaengine_pcm_get_data - Get dmaeinge substream private data
61 * @substream: PCM substream
62 *
63 * Returns the data previously set with snd_dmaengine_pcm_set_data
64 */
65void *snd_dmaengine_pcm_get_data(struct snd_pcm_substream *substream)
66{
67 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
68
69 return prtd->data;
70}
71EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_get_data);
72
73struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream) 44struct dma_chan *snd_dmaengine_pcm_get_chan(struct snd_pcm_substream *substream)
74{ 45{
75 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); 46 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
@@ -118,10 +89,49 @@ int snd_hwparams_to_dma_slave_config(const struct snd_pcm_substream *substream,
118 slave_config->src_addr_width = buswidth; 89 slave_config->src_addr_width = buswidth;
119 } 90 }
120 91
92 slave_config->device_fc = false;
93
121 return 0; 94 return 0;
122} 95}
123EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config); 96EXPORT_SYMBOL_GPL(snd_hwparams_to_dma_slave_config);
124 97
98/**
99 * snd_dmaengine_pcm_set_config_from_dai_data() - Initializes a dma slave config
100 * using DAI DMA data.
101 * @substream: PCM substream
102 * @dma_data: DAI DMA data
103 * @slave_config: DMA slave configuration
104 *
105 * Initializes the {dst,src}_addr, {dst,src}_maxburst, {dst,src}_addr_width and
106 * slave_id fields of the DMA slave config from the same fields of the DAI DMA
107 * data struct. The src and dst fields will be initialized depending on the
108 * direction of the substream. If the substream is a playback stream the dst
109 * fields will be initialized, if it is a capture stream the src fields will be
110 * initialized. The {dst,src}_addr_width field will only be initialized if the
111 * addr_width field of the DAI DMA data struct is not equal to
112 * DMA_SLAVE_BUSWIDTH_UNDEFINED.
113 */
114void snd_dmaengine_pcm_set_config_from_dai_data(
115 const struct snd_pcm_substream *substream,
116 const struct snd_dmaengine_dai_dma_data *dma_data,
117 struct dma_slave_config *slave_config)
118{
119 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
120 slave_config->dst_addr = dma_data->addr;
121 slave_config->dst_maxburst = dma_data->maxburst;
122 if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
123 slave_config->dst_addr_width = dma_data->addr_width;
124 } else {
125 slave_config->src_addr = dma_data->addr;
126 slave_config->src_maxburst = dma_data->maxburst;
127 if (dma_data->addr_width != DMA_SLAVE_BUSWIDTH_UNDEFINED)
128 slave_config->src_addr_width = dma_data->addr_width;
129 }
130
131 slave_config->slave_id = dma_data->slave_id;
132}
133EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_set_config_from_dai_data);
134
125static void dmaengine_pcm_dma_complete(void *arg) 135static void dmaengine_pcm_dma_complete(void *arg)
126{ 136{
127 struct snd_pcm_substream *substream = arg; 137 struct snd_pcm_substream *substream = arg;
@@ -244,44 +254,48 @@ snd_pcm_uframes_t snd_dmaengine_pcm_pointer(struct snd_pcm_substream *substream)
244} 254}
245EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer); 255EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_pointer);
246 256
247static int dmaengine_pcm_request_channel(struct dmaengine_pcm_runtime_data *prtd, 257/**
248 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)
249{ 268{
250 dma_cap_mask_t mask; 269 dma_cap_mask_t mask;
251 270
252 dma_cap_zero(mask); 271 dma_cap_zero(mask);
253 dma_cap_set(DMA_SLAVE, mask); 272 dma_cap_set(DMA_SLAVE, mask);
254 dma_cap_set(DMA_CYCLIC, mask); 273 dma_cap_set(DMA_CYCLIC, mask);
255 prtd->dma_chan = dma_request_channel(mask, filter_fn, filter_data);
256 274
257 if (!prtd->dma_chan) 275 return dma_request_channel(mask, filter_fn, filter_data);
258 return -ENXIO;
259
260 return 0;
261} 276}
277EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_request_channel);
262 278
263/** 279/**
264 * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream 280 * snd_dmaengine_pcm_open - Open a dmaengine based PCM substream
265 * @substream: PCM substream 281 * @substream: PCM substream
266 * @filter_fn: Filter function used to request the DMA channel 282 * @chan: DMA channel to use for data transfers
267 * @filter_data: Data passed to the DMA filter function
268 * 283 *
269 * Returns 0 on success, a negative error code otherwise. 284 * Returns 0 on success, a negative error code otherwise.
270 * 285 *
271 * 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
272 * 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
273 * 288 * is not availabe to your pcm driver implementation.
274 * Note that this function will use private_data field of the substream's
275 * runtime. So it is not availabe to your pcm driver implementation. If you need
276 * to keep additional data attached to a substream use
277 * snd_dmaengine_pcm_{set,get}_data.
278 */ 289 */
279int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream, 290int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
280 dma_filter_fn filter_fn, void *filter_data) 291 struct dma_chan *chan)
281{ 292{
282 struct dmaengine_pcm_runtime_data *prtd; 293 struct dmaengine_pcm_runtime_data *prtd;
283 int ret; 294 int ret;
284 295
296 if (!chan)
297 return -ENXIO;
298
285 ret = snd_pcm_hw_constraint_integer(substream->runtime, 299 ret = snd_pcm_hw_constraint_integer(substream->runtime,
286 SNDRV_PCM_HW_PARAM_PERIODS); 300 SNDRV_PCM_HW_PARAM_PERIODS);
287 if (ret < 0) 301 if (ret < 0)
@@ -291,11 +305,7 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
291 if (!prtd) 305 if (!prtd)
292 return -ENOMEM; 306 return -ENOMEM;
293 307
294 ret = dmaengine_pcm_request_channel(prtd, filter_fn, filter_data); 308 prtd->dma_chan = chan;
295 if (ret < 0) {
296 kfree(prtd);
297 return ret;
298 }
299 309
300 substream->runtime->private_data = prtd; 310 substream->runtime->private_data = prtd;
301 311
@@ -304,6 +314,27 @@ int snd_dmaengine_pcm_open(struct snd_pcm_substream *substream,
304EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open); 314EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_open);
305 315
306/** 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/**
307 * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream 338 * snd_dmaengine_pcm_close - Close a dmaengine based PCM substream
308 * @substream: PCM substream 339 * @substream: PCM substream
309 */ 340 */
@@ -311,11 +342,26 @@ int snd_dmaengine_pcm_close(struct snd_pcm_substream *substream)
311{ 342{
312 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream); 343 struct dmaengine_pcm_runtime_data *prtd = substream_to_prtd(substream);
313 344
314 dma_release_channel(prtd->dma_chan);
315 kfree(prtd); 345 kfree(prtd);
316 346
317 return 0; 347 return 0;
318} 348}
319EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close); 349EXPORT_SYMBOL_GPL(snd_dmaengine_pcm_close);
320 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
321MODULE_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/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c
index 5e7aebe1e664..d653763f83b7 100644
--- a/sound/soc/spear/spear_pcm.c
+++ b/sound/soc/spear/spear_pcm.c
@@ -64,21 +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 ret = snd_dmaengine_pcm_open(substream, dma_data->filter, dma_data); 67 return snd_dmaengine_pcm_open_request_chan(substream, dma_data->filter,
68 if (ret) 68 dma_data);
69 return ret;
70
71 snd_dmaengine_pcm_set_data(substream, dma_data);
72
73 return 0;
74}
75
76static int spear_pcm_close(struct snd_pcm_substream *substream)
77{
78
79 snd_dmaengine_pcm_close(substream);
80
81 return 0;
82} 69}
83 70
84static int spear_pcm_mmap(struct snd_pcm_substream *substream, 71static int spear_pcm_mmap(struct snd_pcm_substream *substream,
@@ -93,7 +80,7 @@ static int spear_pcm_mmap(struct snd_pcm_substream *substream,
93 80
94static struct snd_pcm_ops spear_pcm_ops = { 81static struct snd_pcm_ops spear_pcm_ops = {
95 .open = spear_pcm_open, 82 .open = spear_pcm_open,
96 .close = spear_pcm_close, 83 .close = snd_dmaengine_pcm_close_release_chan,
97 .ioctl = snd_pcm_lib_ioctl, 84 .ioctl = snd_pcm_lib_ioctl,
98 .hw_params = spear_pcm_hw_params, 85 .hw_params = spear_pcm_hw_params,
99 .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/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index 336dcdd3e8a4..2d7b8c2719ce 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -35,6 +35,7 @@
35#include <sound/pcm.h> 35#include <sound/pcm.h>
36#include <sound/pcm_params.h> 36#include <sound/pcm_params.h>
37#include <sound/soc.h> 37#include <sound/soc.h>
38#include <sound/dmaengine_pcm.h>
38 39
39#include "tegra_asoc_utils.h" 40#include "tegra_asoc_utils.h"
40#include "tegra20_ac97.h" 41#include "tegra20_ac97.h"
@@ -389,14 +390,14 @@ static int tegra20_ac97_platform_probe(struct platform_device *pdev)
389 } 390 }
390 391
391 ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1; 392 ac97->capture_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_RX1;
392 ac97->capture_dma_data.wrap = 4; 393 ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
393 ac97->capture_dma_data.width = 32; 394 ac97->capture_dma_data.maxburst = 4;
394 ac97->capture_dma_data.req_sel = of_dma[1]; 395 ac97->capture_dma_data.slave_id = of_dma[1];
395 396
396 ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1; 397 ac97->playback_dma_data.addr = mem->start + TEGRA20_AC97_FIFO_TX1;
397 ac97->playback_dma_data.wrap = 4; 398 ac97->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
398 ac97->playback_dma_data.width = 32; 399 ac97->capture_dma_data.maxburst = 4;
399 ac97->playback_dma_data.req_sel = of_dma[1]; 400 ac97->capture_dma_data.slave_id = of_dma[0];
400 401
401 ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1); 402 ret = snd_soc_register_dais(&pdev->dev, &tegra20_ac97_dai, 1);
402 if (ret) { 403 if (ret) {
diff --git a/sound/soc/tegra/tegra20_ac97.h b/sound/soc/tegra/tegra20_ac97.h
index dddc6828004e..4acb3aaba29b 100644
--- a/sound/soc/tegra/tegra20_ac97.h
+++ b/sound/soc/tegra/tegra20_ac97.h
@@ -85,8 +85,8 @@
85 85
86struct tegra20_ac97 { 86struct tegra20_ac97 {
87 struct clk *clk_ac97; 87 struct clk *clk_ac97;
88 struct tegra_pcm_dma_params capture_dma_data; 88 struct snd_dmaengine_dai_dma_data capture_dma_data;
89 struct tegra_pcm_dma_params playback_dma_data; 89 struct snd_dmaengine_dai_dma_data playback_dma_data;
90 struct regmap *regmap; 90 struct regmap *regmap;
91 int reset_gpio; 91 int reset_gpio;
92 int sync_gpio; 92 int sync_gpio;
diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c
index caa772de5a18..e6651e0eaeed 100644
--- a/sound/soc/tegra/tegra20_i2s.c
+++ b/sound/soc/tegra/tegra20_i2s.c
@@ -41,6 +41,7 @@
41#include <sound/pcm.h> 41#include <sound/pcm.h>
42#include <sound/pcm_params.h> 42#include <sound/pcm_params.h>
43#include <sound/soc.h> 43#include <sound/soc.h>
44#include <sound/dmaengine_pcm.h>
44 45
45#include "tegra20_i2s.h" 46#include "tegra20_i2s.h"
46 47
@@ -403,14 +404,14 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev)
403 } 404 }
404 405
405 i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2; 406 i2s->capture_dma_data.addr = mem->start + TEGRA20_I2S_FIFO2;
406 i2s->capture_dma_data.wrap = 4; 407 i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
407 i2s->capture_dma_data.width = 32; 408 i2s->capture_dma_data.maxburst = 4;
408 i2s->capture_dma_data.req_sel = dma_ch; 409 i2s->capture_dma_data.slave_id = dma_ch;
409 410
410 i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1; 411 i2s->playback_dma_data.addr = mem->start + TEGRA20_I2S_FIFO1;
411 i2s->playback_dma_data.wrap = 4; 412 i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
412 i2s->playback_dma_data.width = 32; 413 i2s->playback_dma_data.maxburst = 4;
413 i2s->playback_dma_data.req_sel = dma_ch; 414 i2s->playback_dma_data.slave_id = dma_ch;
414 415
415 pm_runtime_enable(&pdev->dev); 416 pm_runtime_enable(&pdev->dev);
416 if (!pm_runtime_enabled(&pdev->dev)) { 417 if (!pm_runtime_enabled(&pdev->dev)) {
diff --git a/sound/soc/tegra/tegra20_i2s.h b/sound/soc/tegra/tegra20_i2s.h
index 729958713cd4..fa6c29cc12b9 100644
--- a/sound/soc/tegra/tegra20_i2s.h
+++ b/sound/soc/tegra/tegra20_i2s.h
@@ -155,8 +155,8 @@
155struct tegra20_i2s { 155struct tegra20_i2s {
156 struct snd_soc_dai_driver dai; 156 struct snd_soc_dai_driver dai;
157 struct clk *clk_i2s; 157 struct clk *clk_i2s;
158 struct tegra_pcm_dma_params capture_dma_data; 158 struct snd_dmaengine_dai_dma_data capture_dma_data;
159 struct tegra_pcm_dma_params playback_dma_data; 159 struct snd_dmaengine_dai_dma_data playback_dma_data;
160 struct regmap *regmap; 160 struct regmap *regmap;
161}; 161};
162 162
diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c
index 04771d14d343..b7b4743cc94d 100644
--- a/sound/soc/tegra/tegra20_spdif.c
+++ b/sound/soc/tegra/tegra20_spdif.c
@@ -32,6 +32,7 @@
32#include <sound/pcm.h> 32#include <sound/pcm.h>
33#include <sound/pcm_params.h> 33#include <sound/pcm_params.h>
34#include <sound/soc.h> 34#include <sound/soc.h>
35#include <sound/dmaengine_pcm.h>
35 36
36#include "tegra20_spdif.h" 37#include "tegra20_spdif.h"
37 38
@@ -318,9 +319,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev)
318 } 319 }
319 320
320 spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT; 321 spdif->playback_dma_data.addr = mem->start + TEGRA20_SPDIF_DATA_OUT;
321 spdif->playback_dma_data.wrap = 4; 322 spdif->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
322 spdif->playback_dma_data.width = 32; 323 spdif->capture_dma_data.maxburst = 4;
323 spdif->playback_dma_data.req_sel = dmareq->start; 324 spdif->playback_dma_data.slave_id = dmareq->start;
324 325
325 pm_runtime_enable(&pdev->dev); 326 pm_runtime_enable(&pdev->dev);
326 if (!pm_runtime_enabled(&pdev->dev)) { 327 if (!pm_runtime_enabled(&pdev->dev)) {
diff --git a/sound/soc/tegra/tegra20_spdif.h b/sound/soc/tegra/tegra20_spdif.h
index b48d699fd583..85a9aefcc287 100644
--- a/sound/soc/tegra/tegra20_spdif.h
+++ b/sound/soc/tegra/tegra20_spdif.h
@@ -462,8 +462,8 @@
462 462
463struct tegra20_spdif { 463struct tegra20_spdif {
464 struct clk *clk_spdif_out; 464 struct clk *clk_spdif_out;
465 struct tegra_pcm_dma_params capture_dma_data; 465 struct snd_dmaengine_dai_dma_data capture_dma_data;
466 struct tegra_pcm_dma_params playback_dma_data; 466 struct snd_dmaengine_dai_dma_data playback_dma_data;
467 struct regmap *regmap; 467 struct regmap *regmap;
468}; 468};
469 469
diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index e5cfb4ac41ba..5e08f3e7e6cf 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -95,8 +95,8 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
95} 95}
96 96
97int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, 97int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
98 unsigned long *fiforeg, 98 dma_addr_t *fiforeg,
99 unsigned long *reqsel) 99 unsigned int *reqsel)
100{ 100{
101 int channel; 101 int channel;
102 u32 reg, val; 102 u32 reg, val;
@@ -178,8 +178,8 @@ int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif)
178EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo); 178EXPORT_SYMBOL_GPL(tegra30_ahub_free_rx_fifo);
179 179
180int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, 180int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
181 unsigned long *fiforeg, 181 dma_addr_t *fiforeg,
182 unsigned long *reqsel) 182 unsigned int *reqsel)
183{ 183{
184 int channel; 184 int channel;
185 u32 reg, val; 185 u32 reg, val;
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index e690e2eecc92..b7d7c1a30302 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -451,15 +451,15 @@ enum tegra30_ahub_rxcif {
451}; 451};
452 452
453extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif, 453extern int tegra30_ahub_allocate_rx_fifo(enum tegra30_ahub_rxcif *rxcif,
454 unsigned long *fiforeg, 454 dma_addr_t *fiforeg,
455 unsigned long *reqsel); 455 unsigned int *reqsel);
456extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif); 456extern int tegra30_ahub_enable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
457extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif); 457extern int tegra30_ahub_disable_rx_fifo(enum tegra30_ahub_rxcif rxcif);
458extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif); 458extern int tegra30_ahub_free_rx_fifo(enum tegra30_ahub_rxcif rxcif);
459 459
460extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif, 460extern int tegra30_ahub_allocate_tx_fifo(enum tegra30_ahub_txcif *txcif,
461 unsigned long *fiforeg, 461 dma_addr_t *fiforeg,
462 unsigned long *reqsel); 462 unsigned int *reqsel);
463extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif); 463extern int tegra30_ahub_enable_tx_fifo(enum tegra30_ahub_txcif txcif);
464extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif); 464extern int tegra30_ahub_disable_tx_fifo(enum tegra30_ahub_txcif txcif);
465extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif); 465extern int tegra30_ahub_free_tx_fifo(enum tegra30_ahub_txcif txcif);
diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c
index f4e1ce82750a..857ec21e3c7d 100644
--- a/sound/soc/tegra/tegra30_i2s.c
+++ b/sound/soc/tegra/tegra30_i2s.c
@@ -38,6 +38,7 @@
38#include <sound/pcm.h> 38#include <sound/pcm.h>
39#include <sound/pcm_params.h> 39#include <sound/pcm_params.h>
40#include <sound/soc.h> 40#include <sound/soc.h>
41#include <sound/dmaengine_pcm.h>
41 42
42#include "tegra30_ahub.h" 43#include "tegra30_ahub.h"
43#include "tegra30_i2s.h" 44#include "tegra30_i2s.h"
@@ -80,17 +81,17 @@ static int tegra30_i2s_startup(struct snd_pcm_substream *substream,
80 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 81 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
81 ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif, 82 ret = tegra30_ahub_allocate_tx_fifo(&i2s->playback_fifo_cif,
82 &i2s->playback_dma_data.addr, 83 &i2s->playback_dma_data.addr,
83 &i2s->playback_dma_data.req_sel); 84 &i2s->playback_dma_data.slave_id);
84 i2s->playback_dma_data.wrap = 4; 85 i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
85 i2s->playback_dma_data.width = 32; 86 i2s->playback_dma_data.maxburst = 4;
86 tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif, 87 tegra30_ahub_set_rx_cif_source(i2s->playback_i2s_cif,
87 i2s->playback_fifo_cif); 88 i2s->playback_fifo_cif);
88 } else { 89 } else {
89 ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif, 90 ret = tegra30_ahub_allocate_rx_fifo(&i2s->capture_fifo_cif,
90 &i2s->capture_dma_data.addr, 91 &i2s->capture_dma_data.addr,
91 &i2s->capture_dma_data.req_sel); 92 &i2s->capture_dma_data.slave_id);
92 i2s->capture_dma_data.wrap = 4; 93 i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
93 i2s->capture_dma_data.width = 32; 94 i2s->capture_dma_data.maxburst = 4;
94 tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif, 95 tegra30_ahub_set_rx_cif_source(i2s->capture_fifo_cif,
95 i2s->capture_i2s_cif); 96 i2s->capture_i2s_cif);
96 } 97 }
diff --git a/sound/soc/tegra/tegra30_i2s.h b/sound/soc/tegra/tegra30_i2s.h
index a294d942b9f7..bea23afe3b9f 100644
--- a/sound/soc/tegra/tegra30_i2s.h
+++ b/sound/soc/tegra/tegra30_i2s.h
@@ -231,10 +231,10 @@ struct tegra30_i2s {
231 struct clk *clk_i2s; 231 struct clk *clk_i2s;
232 enum tegra30_ahub_txcif capture_i2s_cif; 232 enum tegra30_ahub_txcif capture_i2s_cif;
233 enum tegra30_ahub_rxcif capture_fifo_cif; 233 enum tegra30_ahub_rxcif capture_fifo_cif;
234 struct tegra_pcm_dma_params capture_dma_data; 234 struct snd_dmaengine_dai_dma_data capture_dma_data;
235 enum tegra30_ahub_rxcif playback_i2s_cif; 235 enum tegra30_ahub_rxcif playback_i2s_cif;
236 enum tegra30_ahub_txcif playback_fifo_cif; 236 enum tegra30_ahub_txcif playback_fifo_cif;
237 struct tegra_pcm_dma_params playback_dma_data; 237 struct snd_dmaengine_dai_dma_data playback_dma_data;
238 struct regmap *regmap; 238 struct regmap *regmap;
239}; 239};
240 240
diff --git a/sound/soc/tegra/tegra_pcm.c b/sound/soc/tegra/tegra_pcm.c
index 5e2c55c5b255..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,191 +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_close(struct snd_pcm_substream *substream)
77{
78 snd_dmaengine_pcm_close(substream);
79 return 0;
80}
81
82static int tegra_pcm_hw_params(struct snd_pcm_substream *substream,
83 struct snd_pcm_hw_params *params)
84{
85 struct snd_soc_pcm_runtime *rtd = substream->private_data;
86 struct device *dev = rtd->platform->dev;
87 struct dma_chan *chan = snd_dmaengine_pcm_get_chan(substream);
88 struct tegra_pcm_dma_params *dmap;
89 struct dma_slave_config slave_config;
90 int ret;
91
92 dmap = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
93
94 ret = snd_hwparams_to_dma_slave_config(substream, params,
95 &slave_config);
96 if (ret) {
97 dev_err(dev, "hw params config failed with err %d\n", ret);
98 return ret;
99 }
100
101 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
102 slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
103 slave_config.dst_addr = dmap->addr;
104 slave_config.dst_maxburst = 4;
105 } else {
106 slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
107 slave_config.src_addr = dmap->addr;
108 slave_config.src_maxburst = 4;
109 }
110 slave_config.slave_id = dmap->req_sel;
111
112 ret = dmaengine_slave_config(chan, &slave_config);
113 if (ret < 0) {
114 dev_err(dev, "dma slave config failed with err %d\n", ret);
115 return ret;
116 }
117
118 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
119 return 0;
120}
121
122static int tegra_pcm_hw_free(struct snd_pcm_substream *substream)
123{
124 snd_pcm_set_runtime_buffer(substream, NULL);
125 return 0;
126}
127
128static int tegra_pcm_mmap(struct snd_pcm_substream *substream,
129 struct vm_area_struct *vma)
130{
131 struct snd_pcm_runtime *runtime = substream->runtime;
132
133 return dma_mmap_writecombine(substream->pcm->card->dev, vma,
134 runtime->dma_area,
135 runtime->dma_addr,
136 runtime->dma_bytes);
137}
138
139static struct snd_pcm_ops tegra_pcm_ops = {
140 .open = tegra_pcm_open,
141 .close = tegra_pcm_close,
142 .ioctl = snd_pcm_lib_ioctl,
143 .hw_params = tegra_pcm_hw_params,
144 .hw_free = tegra_pcm_hw_free,
145 .trigger = snd_dmaengine_pcm_trigger,
146 .pointer = snd_dmaengine_pcm_pointer,
147 .mmap = tegra_pcm_mmap,
148};
149
150static int tegra_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
151{
152 struct snd_pcm_substream *substream = pcm->streams[stream].substream;
153 struct snd_dma_buffer *buf = &substream->dma_buffer;
154 size_t size = tegra_pcm_hardware.buffer_bytes_max;
155
156 buf->area = dma_alloc_writecombine(pcm->card->dev, size,
157 &buf->addr, GFP_KERNEL);
158 if (!buf->area)
159 return -ENOMEM;
160
161 buf->dev.type = SNDRV_DMA_TYPE_DEV;
162 buf->dev.dev = pcm->card->dev;
163 buf->private_data = NULL;
164 buf->bytes = size;
165
166 return 0;
167}
168
169static void tegra_pcm_deallocate_dma_buffer(struct snd_pcm *pcm, int stream)
170{
171 struct snd_pcm_substream *substream;
172 struct snd_dma_buffer *buf;
173
174 substream = pcm->streams[stream].substream;
175 if (!substream)
176 return;
177
178 buf = &substream->dma_buffer;
179 if (!buf->area)
180 return;
181
182 dma_free_writecombine(pcm->card->dev, buf->bytes,
183 buf->area, buf->addr);
184 buf->area = NULL;
185}
186
187static u64 tegra_dma_mask = DMA_BIT_MASK(32);
188
189static int tegra_pcm_new(struct snd_soc_pcm_runtime *rtd)
190{
191 struct snd_card *card = rtd->card->snd_card;
192 struct snd_pcm *pcm = rtd->pcm;
193 int ret = 0;
194
195 if (!card->dev->dma_mask)
196 card->dev->dma_mask = &tegra_dma_mask;
197 if (!card->dev->coherent_dma_mask)
198 card->dev->coherent_dma_mask = DMA_BIT_MASK(32);
199
200 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream) {
201 ret = tegra_pcm_preallocate_dma_buffer(pcm,
202 SNDRV_PCM_STREAM_PLAYBACK);
203 if (ret)
204 goto err;
205 }
206
207 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream) {
208 ret = tegra_pcm_preallocate_dma_buffer(pcm,
209 SNDRV_PCM_STREAM_CAPTURE);
210 if (ret)
211 goto err_free_play;
212 }
213
214 return 0;
215
216err_free_play:
217 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
218err:
219 return ret;
220}
221
222static void tegra_pcm_free(struct snd_pcm *pcm)
223{
224 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_CAPTURE);
225 tegra_pcm_deallocate_dma_buffer(pcm, SNDRV_PCM_STREAM_PLAYBACK);
226}
227
228static struct snd_soc_platform_driver tegra_pcm_platform = {
229 .ops = &tegra_pcm_ops,
230 .pcm_new = tegra_pcm_new,
231 .pcm_free = tegra_pcm_free,
232}; 61};
233 62
234int tegra_pcm_platform_register(struct device *dev) 63int tegra_pcm_platform_register(struct device *dev)
235{ 64{
236 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);
237} 68}
238EXPORT_SYMBOL_GPL(tegra_pcm_platform_register); 69EXPORT_SYMBOL_GPL(tegra_pcm_platform_register);
239 70
240void tegra_pcm_platform_unregister(struct device *dev) 71void tegra_pcm_platform_unregister(struct device *dev)
241{ 72{
242 snd_soc_unregister_platform(dev); 73 return snd_dmaengine_pcm_unregister(dev);
243} 74}
244EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister); 75EXPORT_SYMBOL_GPL(tegra_pcm_platform_unregister);
245 76
diff --git a/sound/soc/tegra/tegra_pcm.h b/sound/soc/tegra/tegra_pcm.h
index bc8b46af928e..68ad901714a9 100644
--- a/sound/soc/tegra/tegra_pcm.h
+++ b/sound/soc/tegra/tegra_pcm.h
@@ -31,13 +31,6 @@
31#ifndef __TEGRA_PCM_H__ 31#ifndef __TEGRA_PCM_H__
32#define __TEGRA_PCM_H__ 32#define __TEGRA_PCM_H__
33 33
34struct tegra_pcm_dma_params {
35 unsigned long addr;
36 unsigned long wrap;
37 unsigned long width;
38 unsigned long req_sel;
39};
40
41int tegra_pcm_platform_register(struct device *dev); 34int tegra_pcm_platform_register(struct device *dev);
42void tegra_pcm_platform_unregister(struct device *dev); 35void tegra_pcm_platform_unregister(struct device *dev);
43 36
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 846fa82a58d0..b6e5ae277299 100644
--- a/sound/soc/ux500/ux500_pcm.c
+++ b/sound/soc/ux500/ux500_pcm.c
@@ -28,28 +28,19 @@
28#include "ux500_msp_i2s.h" 28#include "ux500_msp_i2s.h"
29#include "ux500_pcm.h" 29#include "ux500_pcm.h"
30 30
31static struct snd_pcm_hardware ux500_pcm_hw_playback = { 31#define UX500_PLATFORM_MIN_RATE 8000
32 .info = SNDRV_PCM_INFO_INTERLEAVED | 32#define UX500_PLATFORM_MAX_RATE 48000
33 SNDRV_PCM_INFO_MMAP | 33
34 SNDRV_PCM_INFO_RESUME | 34#define UX500_PLATFORM_MIN_CHANNELS 1
35 SNDRV_PCM_INFO_PAUSE, 35#define UX500_PLATFORM_MAX_CHANNELS 8
36 .formats = SNDRV_PCM_FMTBIT_S16_LE |
37 SNDRV_PCM_FMTBIT_U16_LE |
38 SNDRV_PCM_FMTBIT_S16_BE |
39 SNDRV_PCM_FMTBIT_U16_BE,
40 .rates = SNDRV_PCM_RATE_KNOT,
41 .rate_min = UX500_PLATFORM_MIN_RATE_PLAYBACK,
42 .rate_max = UX500_PLATFORM_MAX_RATE_PLAYBACK,
43 .channels_min = UX500_PLATFORM_MIN_CHANNELS,
44 .channels_max = UX500_PLATFORM_MAX_CHANNELS,
45 .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
46 .period_bytes_min = UX500_PLATFORM_PERIODS_BYTES_MIN,
47 .period_bytes_max = UX500_PLATFORM_PERIODS_BYTES_MAX,
48 .periods_min = UX500_PLATFORM_PERIODS_MIN,
49 .periods_max = UX500_PLATFORM_PERIODS_MAX,
50};
51 36
52static struct snd_pcm_hardware ux500_pcm_hw_capture = { 37#define UX500_PLATFORM_PERIODS_BYTES_MIN 128
38#define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE)
39#define UX500_PLATFORM_PERIODS_MIN 2
40#define UX500_PLATFORM_PERIODS_MAX 48
41#define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE)
42
43static const struct snd_pcm_hardware ux500_pcm_hw = {
53 .info = SNDRV_PCM_INFO_INTERLEAVED | 44 .info = SNDRV_PCM_INFO_INTERLEAVED |
54 SNDRV_PCM_INFO_MMAP | 45 SNDRV_PCM_INFO_MMAP |
55 SNDRV_PCM_INFO_RESUME | 46 SNDRV_PCM_INFO_RESUME |
@@ -59,8 +50,8 @@ static struct snd_pcm_hardware ux500_pcm_hw_capture = {
59 SNDRV_PCM_FMTBIT_S16_BE | 50 SNDRV_PCM_FMTBIT_S16_BE |
60 SNDRV_PCM_FMTBIT_U16_BE, 51 SNDRV_PCM_FMTBIT_U16_BE,
61 .rates = SNDRV_PCM_RATE_KNOT, 52 .rates = SNDRV_PCM_RATE_KNOT,
62 .rate_min = UX500_PLATFORM_MIN_RATE_CAPTURE, 53 .rate_min = UX500_PLATFORM_MIN_RATE,
63 .rate_max = UX500_PLATFORM_MAX_RATE_CAPTURE, 54 .rate_max = UX500_PLATFORM_MAX_RATE,
64 .channels_min = UX500_PLATFORM_MIN_CHANNELS, 55 .channels_min = UX500_PLATFORM_MIN_CHANNELS,
65 .channels_max = UX500_PLATFORM_MAX_CHANNELS, 56 .channels_max = UX500_PLATFORM_MAX_CHANNELS,
66 .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX, 57 .buffer_bytes_max = UX500_PLATFORM_BUFFER_BYTES_MAX,
@@ -70,64 +61,23 @@ static struct snd_pcm_hardware ux500_pcm_hw_capture = {
70 .periods_max = UX500_PLATFORM_PERIODS_MAX, 61 .periods_max = UX500_PLATFORM_PERIODS_MAX,
71}; 62};
72 63
73static void ux500_pcm_dma_hw_free(struct device *dev, 64static struct dma_chan *ux500_pcm_request_chan(struct snd_soc_pcm_runtime *rtd,
74 struct snd_pcm_substream *substream) 65 struct snd_pcm_substream *substream)
75{ 66{
76 struct snd_pcm_runtime *runtime = substream->runtime;
77 struct snd_dma_buffer *buf = runtime->dma_buffer_p;
78
79 if (runtime->dma_area == NULL)
80 return;
81
82 if (buf != &substream->dma_buffer) {
83 dma_free_coherent(buf->dev.dev, buf->bytes, buf->area,
84 buf->addr);
85 kfree(runtime->dma_buffer_p);
86 }
87
88 snd_pcm_set_runtime_buffer(substream, NULL);
89}
90
91static int ux500_pcm_open(struct snd_pcm_substream *substream)
92{
93 int stream_id = substream->pstr->stream;
94 struct snd_pcm_runtime *runtime = substream->runtime;
95 struct snd_soc_pcm_runtime *rtd = substream->private_data;
96 struct snd_soc_dai *dai = rtd->cpu_dai; 67 struct snd_soc_dai *dai = rtd->cpu_dai;
97 struct device *dev = dai->dev; 68 struct device *dev = dai->dev;
98 int ret;
99 struct ux500_msp_dma_params *dma_params;
100 u16 per_data_width, mem_data_width; 69 u16 per_data_width, mem_data_width;
101 struct stedma40_chan_cfg *dma_cfg; 70 struct stedma40_chan_cfg *dma_cfg;
71 struct ux500_msp_dma_params *dma_params;
102 72
103 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,
104 snd_pcm_stream_str(substream)); 74 snd_pcm_stream_str(substream));
105 75
106 dev_dbg(dev, "%s: Set runtime hwparams.\n", __func__); 76 dma_params = snd_soc_dai_get_dma_data(dai, substream);
107 if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) 77 dma_cfg = dma_params->dma_cfg;
108 snd_soc_set_runtime_hwparams(substream,
109 &ux500_pcm_hw_playback);
110 else
111 snd_soc_set_runtime_hwparams(substream,
112 &ux500_pcm_hw_capture);
113
114 /* ensure that buffer size is a multiple of period size */
115 ret = snd_pcm_hw_constraint_integer(runtime,
116 SNDRV_PCM_HW_PARAM_PERIODS);
117 if (ret < 0) {
118 dev_err(dev, "%s: Error: snd_pcm_hw_constraints failed (%d)\n",
119 __func__, ret);
120 return ret;
121 }
122
123 dev_dbg(dev, "%s: Set hw-struct for %s.\n", __func__,
124 snd_pcm_stream_str(substream));
125 runtime->hw = (stream_id == SNDRV_PCM_STREAM_PLAYBACK) ?
126 ux500_pcm_hw_playback : ux500_pcm_hw_capture;
127 78
128 mem_data_width = STEDMA40_HALFWORD_WIDTH; 79 mem_data_width = STEDMA40_HALFWORD_WIDTH;
129 80
130 dma_params = snd_soc_dai_get_dma_data(dai, substream);
131 switch (dma_params->data_size) { 81 switch (dma_params->data_size) {
132 case 32: 82 case 32:
133 per_data_width = STEDMA40_WORD_WIDTH; 83 per_data_width = STEDMA40_WORD_WIDTH;
@@ -140,13 +90,8 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
140 break; 90 break;
141 default: 91 default:
142 per_data_width = STEDMA40_WORD_WIDTH; 92 per_data_width = STEDMA40_WORD_WIDTH;
143 dev_warn(rtd->platform->dev,
144 "%s: Unknown data-size (%d)! Assuming 32 bits.\n",
145 __func__, dma_params->data_size);
146 } 93 }
147 94
148 dma_cfg = dma_params->dma_cfg;
149
150 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 95 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
151 dma_cfg->src_info.data_width = mem_data_width; 96 dma_cfg->src_info.data_width = mem_data_width;
152 dma_cfg->dst_info.data_width = per_data_width; 97 dma_cfg->dst_info.data_width = per_data_width;
@@ -155,137 +100,24 @@ static int ux500_pcm_open(struct snd_pcm_substream *substream)
155 dma_cfg->dst_info.data_width = mem_data_width; 100 dma_cfg->dst_info.data_width = mem_data_width;
156 } 101 }
157 102
158 103 return snd_dmaengine_pcm_request_channel(stedma40_filter, dma_cfg);
159 ret = snd_dmaengine_pcm_open(substream, stedma40_filter, dma_cfg);
160 if (ret) {
161 dev_dbg(dai->dev,
162 "%s: ERROR: snd_dmaengine_pcm_open failed (%d)!\n",
163 __func__, ret);
164 return ret;
165 }
166
167 snd_dmaengine_pcm_set_data(substream, dma_cfg);
168
169 return 0;
170}
171
172static int ux500_pcm_close(struct snd_pcm_substream *substream)
173{
174 struct snd_soc_pcm_runtime *rtd = substream->private_data;
175 struct snd_soc_dai *dai = rtd->cpu_dai;
176
177 dev_dbg(dai->dev, "%s: Enter\n", __func__);
178
179 snd_dmaengine_pcm_close(substream);
180
181 return 0;
182}
183
184static int ux500_pcm_hw_params(struct snd_pcm_substream *substream,
185 struct snd_pcm_hw_params *hw_params)
186{
187 struct snd_pcm_runtime *runtime = substream->runtime;
188 struct snd_dma_buffer *buf = runtime->dma_buffer_p;
189 struct snd_soc_pcm_runtime *rtd = substream->private_data;
190 int ret = 0;
191 int size;
192
193 dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
194
195 size = params_buffer_bytes(hw_params);
196
197 if (buf) {
198 if (buf->bytes >= size)
199 goto out;
200 ux500_pcm_dma_hw_free(NULL, substream);
201 }
202
203 if (substream->dma_buffer.area != NULL &&
204 substream->dma_buffer.bytes >= size) {
205 buf = &substream->dma_buffer;
206 } else {
207 buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL);
208 if (!buf)
209 goto nomem;
210
211 buf->dev.type = SNDRV_DMA_TYPE_DEV;
212 buf->dev.dev = NULL;
213 buf->area = dma_alloc_coherent(NULL, size, &buf->addr,
214 GFP_KERNEL);
215 buf->bytes = size;
216 buf->private_data = NULL;
217
218 if (!buf->area)
219 goto free;
220 }
221 snd_pcm_set_runtime_buffer(substream, buf);
222 ret = 1;
223 out:
224 runtime->dma_bytes = size;
225 return ret;
226
227 free:
228 kfree(buf);
229 nomem:
230 return -ENOMEM;
231} 104}
232 105
233static int ux500_pcm_hw_free(struct snd_pcm_substream *substream) 106static const struct snd_dmaengine_pcm_config ux500_dmaengine_pcm_config = {
234{ 107 .pcm_hardware = &ux500_pcm_hw,
235 struct snd_soc_pcm_runtime *rtd = substream->private_data; 108 .compat_request_channel = ux500_pcm_request_chan,
236 109 .prealloc_buffer_size = 128 * 1024,
237 dev_dbg(rtd->platform->dev, "%s: Enter\n", __func__);
238
239 ux500_pcm_dma_hw_free(NULL, substream);
240
241 return 0;
242}
243
244static int ux500_pcm_mmap(struct snd_pcm_substream *substream,
245 struct vm_area_struct *vma)
246{
247 struct snd_pcm_runtime *runtime = substream->runtime;
248 struct snd_soc_pcm_runtime *rtd = substream->private_data;
249
250 dev_dbg(rtd->platform->dev, "%s: Enter.\n", __func__);
251
252 return dma_mmap_coherent(NULL, vma, runtime->dma_area,
253 runtime->dma_addr, runtime->dma_bytes);
254}
255
256static struct snd_pcm_ops ux500_pcm_ops = {
257 .open = ux500_pcm_open,
258 .close = ux500_pcm_close,
259 .ioctl = snd_pcm_lib_ioctl,
260 .hw_params = ux500_pcm_hw_params,
261 .hw_free = ux500_pcm_hw_free,
262 .trigger = snd_dmaengine_pcm_trigger,
263 .pointer = snd_dmaengine_pcm_pointer_no_residue,
264 .mmap = ux500_pcm_mmap
265};
266
267int ux500_pcm_new(struct snd_soc_pcm_runtime *rtd)
268{
269 struct snd_pcm *pcm = rtd->pcm;
270
271 dev_dbg(rtd->platform->dev, "%s: Enter (id = '%s').\n", __func__,
272 pcm->id);
273
274 pcm->info_flags = 0;
275
276 return 0;
277}
278
279static struct snd_soc_platform_driver ux500_pcm_soc_drv = {
280 .ops = &ux500_pcm_ops,
281 .pcm_new = ux500_pcm_new,
282}; 110};
283 111
284int ux500_pcm_register_platform(struct platform_device *pdev) 112int ux500_pcm_register_platform(struct platform_device *pdev)
285{ 113{
286 int ret; 114 int ret;
287 115
288 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);
289 if (ret < 0) { 121 if (ret < 0) {
290 dev_err(&pdev->dev, 122 dev_err(&pdev->dev,
291 "%s: ERROR: Failed to register platform '%s' (%d)!\n", 123 "%s: ERROR: Failed to register platform '%s' (%d)!\n",
@@ -299,8 +131,7 @@ EXPORT_SYMBOL_GPL(ux500_pcm_register_platform);
299 131
300int ux500_pcm_unregister_platform(struct platform_device *pdev) 132int ux500_pcm_unregister_platform(struct platform_device *pdev)
301{ 133{
302 snd_soc_unregister_platform(&pdev->dev); 134 snd_dmaengine_pcm_unregister(&pdev->dev);
303
304 return 0; 135 return 0;
305} 136}
306EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform); 137EXPORT_SYMBOL_GPL(ux500_pcm_unregister_platform);
diff --git a/sound/soc/ux500/ux500_pcm.h b/sound/soc/ux500/ux500_pcm.h
index 76d344476afc..d76e1aff6458 100644
--- a/sound/soc/ux500/ux500_pcm.h
+++ b/sound/soc/ux500/ux500_pcm.h
@@ -18,20 +18,6 @@
18 18
19#include <linux/workqueue.h> 19#include <linux/workqueue.h>
20 20
21#define UX500_PLATFORM_MIN_RATE_PLAYBACK 8000
22#define UX500_PLATFORM_MAX_RATE_PLAYBACK 48000
23#define UX500_PLATFORM_MIN_RATE_CAPTURE 8000
24#define UX500_PLATFORM_MAX_RATE_CAPTURE 48000
25
26#define UX500_PLATFORM_MIN_CHANNELS 1
27#define UX500_PLATFORM_MAX_CHANNELS 8
28
29#define UX500_PLATFORM_PERIODS_BYTES_MIN 128
30#define UX500_PLATFORM_PERIODS_BYTES_MAX (64 * PAGE_SIZE)
31#define UX500_PLATFORM_PERIODS_MIN 2
32#define UX500_PLATFORM_PERIODS_MAX 48
33#define UX500_PLATFORM_BUFFER_BYTES_MAX (2048 * PAGE_SIZE)
34
35int ux500_pcm_register_platform(struct platform_device *pdev); 21int ux500_pcm_register_platform(struct platform_device *pdev);
36int ux500_pcm_unregister_platform(struct platform_device *pdev); 22int ux500_pcm_unregister_platform(struct platform_device *pdev);
37 23