dmaengine: Add flow controller information to dma_slave_config
[linux-2.6-block.git] / sound / soc / imx / imx-pcm-dma-mx2.c
CommitLineData
8380222e
SH
1/*
2 * imx-pcm-dma-mx2.c -- ALSA Soc Audio Layer
3 *
4 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
5 *
6 * This code is based on code copyrighted by Freescale,
7 * Liam Girdwood, Javier Martin and probably others.
8 *
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by the
11 * Free Software Foundation; either version 2 of the License, or (at your
12 * option) any later version.
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>
5a0e3ad6 22#include <linux/slab.h>
bf974a0d 23#include <linux/dmaengine.h>
8380222e
SH
24
25#include <sound/core.h>
26#include <sound/initval.h>
27#include <sound/pcm.h>
28#include <sound/pcm_params.h>
29#include <sound/soc.h>
30
bf974a0d 31#include <mach/dma.h>
8380222e
SH
32
33#include "imx-ssi.h"
34
35struct imx_pcm_runtime_data {
bf974a0d 36 int period_bytes;
8380222e 37 int periods;
8380222e 38 int dma;
8380222e
SH
39 unsigned long offset;
40 unsigned long size;
8380222e
SH
41 void *buf;
42 int period_time;
bf974a0d
SH
43 struct dma_async_tx_descriptor *desc;
44 struct dma_chan *dma_chan;
45 struct imx_dma_data dma_data;
8380222e
SH
46};
47
bf974a0d 48static void audio_dma_irq(void *data)
8380222e 49{
bf974a0d 50 struct snd_pcm_substream *substream = (struct snd_pcm_substream *)data;
8380222e
SH
51 struct snd_pcm_runtime *runtime = substream->runtime;
52 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
53
bf974a0d
SH
54 iprtd->offset += iprtd->period_bytes;
55 iprtd->offset %= iprtd->period_bytes * iprtd->periods;
8380222e 56
bf974a0d 57 snd_pcm_period_elapsed(substream);
8380222e
SH
58}
59
bf974a0d 60static bool filter(struct dma_chan *chan, void *param)
8380222e 61{
bf974a0d 62 struct imx_pcm_runtime_data *iprtd = param;
8380222e 63
bf974a0d
SH
64 if (!imx_dma_is_general_purpose(chan))
65 return false;
8380222e 66
bf974a0d 67 chan->private = &iprtd->dma_data;
671999cb 68
bf974a0d 69 return true;
8380222e
SH
70}
71
bf974a0d
SH
72static int imx_ssi_dma_alloc(struct snd_pcm_substream *substream,
73 struct snd_pcm_hw_params *params)
8380222e
SH
74{
75 struct snd_soc_pcm_runtime *rtd = substream->private_data;
5f712b2b 76 struct imx_pcm_dma_params *dma_params;
8380222e
SH
77 struct snd_pcm_runtime *runtime = substream->runtime;
78 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
bf974a0d
SH
79 struct dma_slave_config slave_config;
80 dma_cap_mask_t mask;
81 enum dma_slave_buswidth buswidth;
8380222e
SH
82 int ret;
83
f0fba2ad 84 dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
5f712b2b 85
bf974a0d
SH
86 iprtd->dma_data.peripheral_type = IMX_DMATYPE_SSI;
87 iprtd->dma_data.priority = DMA_PRIO_HIGH;
88 iprtd->dma_data.dma_request = dma_params->dma;
8380222e 89
bf974a0d 90 /* Try to grab a DMA channel */
220d9f25
JM
91 if (!iprtd->dma_chan) {
92 dma_cap_zero(mask);
93 dma_cap_set(DMA_SLAVE, mask);
94 iprtd->dma_chan = dma_request_channel(mask, filter, iprtd);
95 if (!iprtd->dma_chan)
96 return -EINVAL;
97 }
8380222e 98
bf974a0d
SH
99 switch (params_format(params)) {
100 case SNDRV_PCM_FORMAT_S16_LE:
101 buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES;
102 break;
103 case SNDRV_PCM_FORMAT_S20_3LE:
104 case SNDRV_PCM_FORMAT_S24_LE:
105 buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES;
106 break;
107 default:
108 return 0;
8380222e
SH
109 }
110
bf974a0d 111 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
35e16581 112 slave_config.direction = DMA_MEM_TO_DEV;
bf974a0d
SH
113 slave_config.dst_addr = dma_params->dma_addr;
114 slave_config.dst_addr_width = buswidth;
6584cb88 115 slave_config.dst_maxburst = dma_params->burstsize;
bf974a0d 116 } else {
35e16581 117 slave_config.direction = DMA_DEV_TO_MEM;
bf974a0d
SH
118 slave_config.src_addr = dma_params->dma_addr;
119 slave_config.src_addr_width = buswidth;
6584cb88 120 slave_config.src_maxburst = dma_params->burstsize;
8380222e
SH
121 }
122
bf974a0d
SH
123 ret = dmaengine_slave_config(iprtd->dma_chan, &slave_config);
124 if (ret)
125 return ret;
8380222e
SH
126
127 return 0;
8380222e
SH
128}
129
130static int snd_imx_pcm_hw_params(struct snd_pcm_substream *substream,
131 struct snd_pcm_hw_params *params)
132{
bf974a0d 133 struct snd_soc_pcm_runtime *rtd = substream->private_data;
8380222e
SH
134 struct snd_pcm_runtime *runtime = substream->runtime;
135 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
8380222e 136 unsigned long dma_addr;
bf974a0d
SH
137 struct dma_chan *chan;
138 struct imx_pcm_dma_params *dma_params;
139 int ret;
8380222e 140
bf974a0d
SH
141 dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
142 ret = imx_ssi_dma_alloc(substream, params);
143 if (ret)
144 return ret;
145 chan = iprtd->dma_chan;
8380222e
SH
146
147 iprtd->size = params_buffer_bytes(params);
148 iprtd->periods = params_periods(params);
bf974a0d 149 iprtd->period_bytes = params_period_bytes(params);
8380222e
SH
150 iprtd->offset = 0;
151 iprtd->period_time = HZ / (params_rate(params) /
152 params_period_size(params));
153
154 snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
155
8380222e
SH
156 dma_addr = runtime->dma_addr;
157
bf974a0d
SH
158 iprtd->buf = (unsigned int *)substream->dma_buffer.area;
159
160 iprtd->desc = chan->device->device_prep_dma_cyclic(chan, dma_addr,
161 iprtd->period_bytes * iprtd->periods,
162 iprtd->period_bytes,
163 substream->stream == SNDRV_PCM_STREAM_PLAYBACK ?
35e16581 164 DMA_MEM_TO_DEV : DMA_DEV_TO_MEM);
bf974a0d
SH
165 if (!iprtd->desc) {
166 dev_err(&chan->dev->device, "cannot prepare slave dma\n");
167 return -EINVAL;
8380222e
SH
168 }
169
bf974a0d
SH
170 iprtd->desc->callback = audio_dma_irq;
171 iprtd->desc->callback_param = substream;
172
8380222e
SH
173 return 0;
174}
175
176static int snd_imx_pcm_hw_free(struct snd_pcm_substream *substream)
177{
178 struct snd_pcm_runtime *runtime = substream->runtime;
179 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
180
bf974a0d
SH
181 if (iprtd->dma_chan) {
182 dma_release_channel(iprtd->dma_chan);
183 iprtd->dma_chan = NULL;
8380222e
SH
184 }
185
8380222e
SH
186 return 0;
187}
188
189static int snd_imx_pcm_prepare(struct snd_pcm_substream *substream)
190{
8380222e 191 struct snd_soc_pcm_runtime *rtd = substream->private_data;
5f712b2b 192 struct imx_pcm_dma_params *dma_params;
8380222e 193
f0fba2ad 194 dma_params = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream);
5f712b2b 195
8380222e
SH
196 return 0;
197}
198
199static int snd_imx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
200{
201 struct snd_pcm_runtime *runtime = substream->runtime;
202 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
203
204 switch (cmd) {
205 case SNDRV_PCM_TRIGGER_START:
206 case SNDRV_PCM_TRIGGER_RESUME:
207 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
bf974a0d 208 dmaengine_submit(iprtd->desc);
c0fa6c8a 209 dma_async_issue_pending(iprtd->dma_chan);
8380222e
SH
210
211 break;
212
213 case SNDRV_PCM_TRIGGER_STOP:
214 case SNDRV_PCM_TRIGGER_SUSPEND:
215 case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
bf974a0d 216 dmaengine_terminate_all(iprtd->dma_chan);
8380222e
SH
217
218 break;
219 default:
220 return -EINVAL;
221 }
222
223 return 0;
224}
225
226static snd_pcm_uframes_t snd_imx_pcm_pointer(struct snd_pcm_substream *substream)
227{
228 struct snd_pcm_runtime *runtime = substream->runtime;
229 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
230
bf974a0d
SH
231 pr_debug("%s: %ld %ld\n", __func__, iprtd->offset,
232 bytes_to_frames(substream->runtime, iprtd->offset));
233
8380222e
SH
234 return bytes_to_frames(substream->runtime, iprtd->offset);
235}
236
237static struct snd_pcm_hardware snd_imx_hardware = {
238 .info = SNDRV_PCM_INFO_INTERLEAVED |
239 SNDRV_PCM_INFO_BLOCK_TRANSFER |
240 SNDRV_PCM_INFO_MMAP |
241 SNDRV_PCM_INFO_MMAP_VALID |
242 SNDRV_PCM_INFO_PAUSE |
243 SNDRV_PCM_INFO_RESUME,
244 .formats = SNDRV_PCM_FMTBIT_S16_LE,
245 .rate_min = 8000,
246 .channels_min = 2,
247 .channels_max = 2,
248 .buffer_bytes_max = IMX_SSI_DMABUF_SIZE,
249 .period_bytes_min = 128,
bf974a0d 250 .period_bytes_max = 65535, /* Limited by SDMA engine */
8380222e
SH
251 .periods_min = 2,
252 .periods_max = 255,
253 .fifo_size = 0,
254};
255
256static int snd_imx_open(struct snd_pcm_substream *substream)
257{
258 struct snd_pcm_runtime *runtime = substream->runtime;
259 struct imx_pcm_runtime_data *iprtd;
260 int ret;
261
262 iprtd = kzalloc(sizeof(*iprtd), GFP_KERNEL);
51b6dfb6
KV
263 if (iprtd == NULL)
264 return -ENOMEM;
8380222e
SH
265 runtime->private_data = iprtd;
266
267 ret = snd_pcm_hw_constraint_integer(substream->runtime,
268 SNDRV_PCM_HW_PARAM_PERIODS);
51b6dfb6
KV
269 if (ret < 0) {
270 kfree(iprtd);
8380222e 271 return ret;
51b6dfb6 272 }
8380222e
SH
273
274 snd_soc_set_runtime_hwparams(substream, &snd_imx_hardware);
bf974a0d
SH
275
276 return 0;
277}
278
279static int snd_imx_close(struct snd_pcm_substream *substream)
280{
281 struct snd_pcm_runtime *runtime = substream->runtime;
282 struct imx_pcm_runtime_data *iprtd = runtime->private_data;
283
284 kfree(iprtd);
285
8380222e
SH
286 return 0;
287}
288
289static struct snd_pcm_ops imx_pcm_ops = {
290 .open = snd_imx_open,
bf974a0d 291 .close = snd_imx_close,
8380222e
SH
292 .ioctl = snd_pcm_lib_ioctl,
293 .hw_params = snd_imx_pcm_hw_params,
294 .hw_free = snd_imx_pcm_hw_free,
295 .prepare = snd_imx_pcm_prepare,
296 .trigger = snd_imx_pcm_trigger,
297 .pointer = snd_imx_pcm_pointer,
298 .mmap = snd_imx_pcm_mmap,
299};
300
f0fba2ad
LG
301static struct snd_soc_platform_driver imx_soc_platform_mx2 = {
302 .ops = &imx_pcm_ops,
8380222e
SH
303 .pcm_new = imx_pcm_new,
304 .pcm_free = imx_pcm_free,
305};
306
f0fba2ad 307static int __devinit imx_soc_platform_probe(struct platform_device *pdev)
8380222e 308{
2c4cf17a
WS
309 struct imx_ssi *ssi = platform_get_drvdata(pdev);
310
311 ssi->dma_params_tx.burstsize = 6;
312 ssi->dma_params_rx.burstsize = 4;
313
f0fba2ad
LG
314 return snd_soc_register_platform(&pdev->dev, &imx_soc_platform_mx2);
315}
316
317static int __devexit imx_soc_platform_remove(struct platform_device *pdev)
318{
319 snd_soc_unregister_platform(&pdev->dev);
320 return 0;
321}
322
323static struct platform_driver imx_pcm_driver = {
324 .driver = {
325 .name = "imx-pcm-audio",
326 .owner = THIS_MODULE,
327 },
f0fba2ad
LG
328 .probe = imx_soc_platform_probe,
329 .remove = __devexit_p(imx_soc_platform_remove),
330};
331
7a24b2ba 332module_platform_driver(imx_pcm_driver);
96dcabb9
APR
333MODULE_LICENSE("GPL");
334MODULE_ALIAS("platform:imx-pcm-audio");