2 * imx-pcm-dma-mx2.c -- ALSA Soc Audio Layer
4 * Copyright 2009 Sascha Hauer <s.hauer@pengutronix.de>
6 * This code is based on code copyrighted by Freescale,
7 * Liam Girdwood, Javier Martin and probably others.
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.
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>
22 #include <linux/slab.h>
24 #include <sound/core.h>
25 #include <sound/initval.h>
26 #include <sound/pcm.h>
27 #include <sound/pcm_params.h>
28 #include <sound/soc.h>
30 #include <mach/dma-mx1-mx2.h>
34 struct imx_pcm_runtime_data
{
36 struct scatterlist
*sg_list
;
39 unsigned long dma_addr
;
41 struct snd_pcm_substream
*substream
;
44 unsigned long period_cnt
;
49 /* Called by the DMA framework when a period has elapsed */
50 static void imx_ssi_dma_progression(int channel
, void *data
,
51 struct scatterlist
*sg
)
53 struct snd_pcm_substream
*substream
= data
;
54 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
55 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
60 runtime
= iprtd
->substream
->runtime
;
62 iprtd
->offset
= sg
->dma_address
- runtime
->dma_addr
;
64 snd_pcm_period_elapsed(iprtd
->substream
);
67 static void imx_ssi_dma_callback(int channel
, void *data
)
69 pr_err("%s shouldn't be called\n", __func__
);
72 static void snd_imx_dma_err_callback(int channel
, void *data
, int err
)
74 pr_err("DMA error callback called\n");
76 pr_err("DMA timeout on channel %d -%s%s%s%s\n",
78 err
& IMX_DMA_ERR_BURST
? " burst" : "",
79 err
& IMX_DMA_ERR_REQUEST
? " request" : "",
80 err
& IMX_DMA_ERR_TRANSFER
? " transfer" : "",
81 err
& IMX_DMA_ERR_BUFFER
? " buffer" : "");
84 static int imx_ssi_dma_alloc(struct snd_pcm_substream
*substream
)
86 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
87 struct imx_pcm_dma_params
*dma_params
= rtd
->dai
->cpu_dai
->dma_data
;
88 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
89 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
92 iprtd
->dma
= imx_dma_request_by_prio(DRV_NAME
, DMA_PRIO_HIGH
);
94 pr_err("Failed to claim the audio DMA\n");
98 ret
= imx_dma_setup_handlers(iprtd
->dma
,
100 snd_imx_dma_err_callback
, substream
);
104 ret
= imx_dma_setup_progression_handler(iprtd
->dma
,
105 imx_ssi_dma_progression
);
107 pr_err("Failed to setup the DMA handler\n");
111 ret
= imx_dma_config_channel(iprtd
->dma
,
112 IMX_DMA_MEMSIZE_16
| IMX_DMA_TYPE_FIFO
,
113 IMX_DMA_MEMSIZE_32
| IMX_DMA_TYPE_LINEAR
,
116 pr_err("Cannot configure DMA channel: %d\n", ret
);
120 imx_dma_config_burstlen(iprtd
->dma
, dma_params
->burstsize
* 2);
124 imx_dma_free(iprtd
->dma
);
128 static int snd_imx_pcm_hw_params(struct snd_pcm_substream
*substream
,
129 struct snd_pcm_hw_params
*params
)
131 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
132 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
134 unsigned long dma_addr
;
136 imx_ssi_dma_alloc(substream
);
138 iprtd
->size
= params_buffer_bytes(params
);
139 iprtd
->periods
= params_periods(params
);
140 iprtd
->period
= params_period_bytes(params
);
142 iprtd
->period_time
= HZ
/ (params_rate(params
) /
143 params_period_size(params
));
145 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
147 if (iprtd
->sg_count
!= iprtd
->periods
) {
148 kfree(iprtd
->sg_list
);
150 iprtd
->sg_list
= kcalloc(iprtd
->periods
+ 1,
151 sizeof(struct scatterlist
), GFP_KERNEL
);
154 iprtd
->sg_count
= iprtd
->periods
+ 1;
157 sg_init_table(iprtd
->sg_list
, iprtd
->sg_count
);
158 dma_addr
= runtime
->dma_addr
;
160 for (i
= 0; i
< iprtd
->periods
; i
++) {
161 iprtd
->sg_list
[i
].page_link
= 0;
162 iprtd
->sg_list
[i
].offset
= 0;
163 iprtd
->sg_list
[i
].dma_address
= dma_addr
;
164 iprtd
->sg_list
[i
].length
= iprtd
->period
;
165 dma_addr
+= iprtd
->period
;
169 iprtd
->sg_list
[iprtd
->sg_count
- 1].offset
= 0;
170 iprtd
->sg_list
[iprtd
->sg_count
- 1].length
= 0;
171 iprtd
->sg_list
[iprtd
->sg_count
- 1].page_link
=
172 ((unsigned long) iprtd
->sg_list
| 0x01) & ~0x02;
176 static int snd_imx_pcm_hw_free(struct snd_pcm_substream
*substream
)
178 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
179 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
181 if (iprtd
->dma
>= 0) {
182 imx_dma_free(iprtd
->dma
);
183 iprtd
->dma
= -EINVAL
;
186 kfree(iprtd
->sg_list
);
187 iprtd
->sg_list
= NULL
;
192 static int snd_imx_pcm_prepare(struct snd_pcm_substream
*substream
)
194 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
195 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
196 struct imx_pcm_dma_params
*dma_params
= rtd
->dai
->cpu_dai
->dma_data
;
197 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
200 iprtd
->substream
= substream
;
201 iprtd
->buf
= (unsigned int *)substream
->dma_buffer
.area
;
202 iprtd
->period_cnt
= 0;
204 pr_debug("%s: buf: %p period: %d periods: %d\n",
205 __func__
, iprtd
->buf
, iprtd
->period
, iprtd
->periods
);
207 err
= imx_dma_setup_sg(iprtd
->dma
, iprtd
->sg_list
, iprtd
->sg_count
,
208 IMX_DMA_LENGTH_LOOP
, dma_params
->dma_addr
,
209 substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
210 DMA_MODE_WRITE
: DMA_MODE_READ
);
217 static int snd_imx_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
219 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
220 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
223 case SNDRV_PCM_TRIGGER_START
:
224 case SNDRV_PCM_TRIGGER_RESUME
:
225 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
226 imx_dma_enable(iprtd
->dma
);
230 case SNDRV_PCM_TRIGGER_STOP
:
231 case SNDRV_PCM_TRIGGER_SUSPEND
:
232 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
233 imx_dma_disable(iprtd
->dma
);
243 static snd_pcm_uframes_t
snd_imx_pcm_pointer(struct snd_pcm_substream
*substream
)
245 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
246 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
248 return bytes_to_frames(substream
->runtime
, iprtd
->offset
);
251 static struct snd_pcm_hardware snd_imx_hardware
= {
252 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
253 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
254 SNDRV_PCM_INFO_MMAP
|
255 SNDRV_PCM_INFO_MMAP_VALID
|
256 SNDRV_PCM_INFO_PAUSE
|
257 SNDRV_PCM_INFO_RESUME
,
258 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
262 .buffer_bytes_max
= IMX_SSI_DMABUF_SIZE
,
263 .period_bytes_min
= 128,
264 .period_bytes_max
= 16 * 1024,
270 static int snd_imx_open(struct snd_pcm_substream
*substream
)
272 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
273 struct imx_pcm_runtime_data
*iprtd
;
276 iprtd
= kzalloc(sizeof(*iprtd
), GFP_KERNEL
);
277 runtime
->private_data
= iprtd
;
279 ret
= snd_pcm_hw_constraint_integer(substream
->runtime
,
280 SNDRV_PCM_HW_PARAM_PERIODS
);
284 snd_soc_set_runtime_hwparams(substream
, &snd_imx_hardware
);
288 static struct snd_pcm_ops imx_pcm_ops
= {
289 .open
= snd_imx_open
,
290 .ioctl
= snd_pcm_lib_ioctl
,
291 .hw_params
= snd_imx_pcm_hw_params
,
292 .hw_free
= snd_imx_pcm_hw_free
,
293 .prepare
= snd_imx_pcm_prepare
,
294 .trigger
= snd_imx_pcm_trigger
,
295 .pointer
= snd_imx_pcm_pointer
,
296 .mmap
= snd_imx_pcm_mmap
,
299 static struct snd_soc_platform imx_soc_platform_dma
= {
301 .pcm_ops
= &imx_pcm_ops
,
302 .pcm_new
= imx_pcm_new
,
303 .pcm_free
= imx_pcm_free
,
306 struct snd_soc_platform
*imx_ssi_dma_mx2_init(struct platform_device
*pdev
,
309 ssi
->dma_params_tx
.burstsize
= DMA_TXFIFO_BURST
;
310 ssi
->dma_params_rx
.burstsize
= DMA_RXFIFO_BURST
;
312 return &imx_soc_platform_dma
;