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>
23 #include <sound/core.h>
24 #include <sound/initval.h>
25 #include <sound/pcm.h>
26 #include <sound/pcm_params.h>
27 #include <sound/soc.h>
29 #include <mach/dma-mx1-mx2.h>
33 struct imx_pcm_runtime_data
{
35 struct scatterlist
*sg_list
;
38 unsigned long dma_addr
;
40 struct snd_pcm_substream
*substream
;
43 unsigned long period_cnt
;
48 /* Called by the DMA framework when a period has elapsed */
49 static void imx_ssi_dma_progression(int channel
, void *data
,
50 struct scatterlist
*sg
)
52 struct snd_pcm_substream
*substream
= data
;
53 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
54 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
59 runtime
= iprtd
->substream
->runtime
;
61 iprtd
->offset
= sg
->dma_address
- runtime
->dma_addr
;
63 snd_pcm_period_elapsed(iprtd
->substream
);
66 static void imx_ssi_dma_callback(int channel
, void *data
)
68 pr_err("%s shouldn't be called\n", __func__
);
71 static void snd_imx_dma_err_callback(int channel
, void *data
, int err
)
73 pr_err("DMA error callback called\n");
75 pr_err("DMA timeout on channel %d -%s%s%s%s\n",
77 err
& IMX_DMA_ERR_BURST
? " burst" : "",
78 err
& IMX_DMA_ERR_REQUEST
? " request" : "",
79 err
& IMX_DMA_ERR_TRANSFER
? " transfer" : "",
80 err
& IMX_DMA_ERR_BUFFER
? " buffer" : "");
83 static int imx_ssi_dma_alloc(struct snd_pcm_substream
*substream
)
85 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
86 struct imx_pcm_dma_params
*dma_params
= rtd
->dai
->cpu_dai
->dma_data
;
87 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
88 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
91 iprtd
->dma
= imx_dma_request_by_prio(DRV_NAME
, DMA_PRIO_HIGH
);
93 pr_err("Failed to claim the audio DMA\n");
97 ret
= imx_dma_setup_handlers(iprtd
->dma
,
99 snd_imx_dma_err_callback
, substream
);
103 ret
= imx_dma_setup_progression_handler(iprtd
->dma
,
104 imx_ssi_dma_progression
);
106 pr_err("Failed to setup the DMA handler\n");
110 ret
= imx_dma_config_channel(iprtd
->dma
,
111 IMX_DMA_MEMSIZE_16
| IMX_DMA_TYPE_FIFO
,
112 IMX_DMA_MEMSIZE_32
| IMX_DMA_TYPE_LINEAR
,
115 pr_err("Cannot configure DMA channel: %d\n", ret
);
119 imx_dma_config_burstlen(iprtd
->dma
, dma_params
->burstsize
* 2);
123 imx_dma_free(iprtd
->dma
);
127 static int snd_imx_pcm_hw_params(struct snd_pcm_substream
*substream
,
128 struct snd_pcm_hw_params
*params
)
130 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
131 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
133 unsigned long dma_addr
;
135 imx_ssi_dma_alloc(substream
);
137 iprtd
->size
= params_buffer_bytes(params
);
138 iprtd
->periods
= params_periods(params
);
139 iprtd
->period
= params_period_bytes(params
);
141 iprtd
->period_time
= HZ
/ (params_rate(params
) /
142 params_period_size(params
));
144 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
146 if (iprtd
->sg_count
!= iprtd
->periods
) {
147 kfree(iprtd
->sg_list
);
149 iprtd
->sg_list
= kcalloc(iprtd
->periods
+ 1,
150 sizeof(struct scatterlist
), GFP_KERNEL
);
153 iprtd
->sg_count
= iprtd
->periods
+ 1;
156 sg_init_table(iprtd
->sg_list
, iprtd
->sg_count
);
157 dma_addr
= runtime
->dma_addr
;
159 for (i
= 0; i
< iprtd
->periods
; i
++) {
160 iprtd
->sg_list
[i
].page_link
= 0;
161 iprtd
->sg_list
[i
].offset
= 0;
162 iprtd
->sg_list
[i
].dma_address
= dma_addr
;
163 iprtd
->sg_list
[i
].length
= iprtd
->period
;
164 dma_addr
+= iprtd
->period
;
168 iprtd
->sg_list
[iprtd
->sg_count
- 1].offset
= 0;
169 iprtd
->sg_list
[iprtd
->sg_count
- 1].length
= 0;
170 iprtd
->sg_list
[iprtd
->sg_count
- 1].page_link
=
171 ((unsigned long) iprtd
->sg_list
| 0x01) & ~0x02;
175 static int snd_imx_pcm_hw_free(struct snd_pcm_substream
*substream
)
177 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
178 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
180 if (iprtd
->dma
>= 0) {
181 imx_dma_free(iprtd
->dma
);
182 iprtd
->dma
= -EINVAL
;
185 kfree(iprtd
->sg_list
);
186 iprtd
->sg_list
= NULL
;
191 static int snd_imx_pcm_prepare(struct snd_pcm_substream
*substream
)
193 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
194 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
195 struct imx_pcm_dma_params
*dma_params
= rtd
->dai
->cpu_dai
->dma_data
;
196 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
199 iprtd
->substream
= substream
;
200 iprtd
->buf
= (unsigned int *)substream
->dma_buffer
.area
;
201 iprtd
->period_cnt
= 0;
203 pr_debug("%s: buf: %p period: %d periods: %d\n",
204 __func__
, iprtd
->buf
, iprtd
->period
, iprtd
->periods
);
206 err
= imx_dma_setup_sg(iprtd
->dma
, iprtd
->sg_list
, iprtd
->sg_count
,
207 IMX_DMA_LENGTH_LOOP
, dma_params
->dma_addr
,
208 substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
209 DMA_MODE_WRITE
: DMA_MODE_READ
);
216 static int snd_imx_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
218 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
219 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
222 case SNDRV_PCM_TRIGGER_START
:
223 case SNDRV_PCM_TRIGGER_RESUME
:
224 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
225 imx_dma_enable(iprtd
->dma
);
229 case SNDRV_PCM_TRIGGER_STOP
:
230 case SNDRV_PCM_TRIGGER_SUSPEND
:
231 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
232 imx_dma_disable(iprtd
->dma
);
242 static snd_pcm_uframes_t
snd_imx_pcm_pointer(struct snd_pcm_substream
*substream
)
244 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
245 struct imx_pcm_runtime_data
*iprtd
= runtime
->private_data
;
247 return bytes_to_frames(substream
->runtime
, iprtd
->offset
);
250 static struct snd_pcm_hardware snd_imx_hardware
= {
251 .info
= SNDRV_PCM_INFO_INTERLEAVED
|
252 SNDRV_PCM_INFO_BLOCK_TRANSFER
|
253 SNDRV_PCM_INFO_MMAP
|
254 SNDRV_PCM_INFO_MMAP_VALID
|
255 SNDRV_PCM_INFO_PAUSE
|
256 SNDRV_PCM_INFO_RESUME
,
257 .formats
= SNDRV_PCM_FMTBIT_S16_LE
,
261 .buffer_bytes_max
= IMX_SSI_DMABUF_SIZE
,
262 .period_bytes_min
= 128,
263 .period_bytes_max
= 16 * 1024,
269 static int snd_imx_open(struct snd_pcm_substream
*substream
)
271 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
272 struct imx_pcm_runtime_data
*iprtd
;
275 iprtd
= kzalloc(sizeof(*iprtd
), GFP_KERNEL
);
276 runtime
->private_data
= iprtd
;
278 ret
= snd_pcm_hw_constraint_integer(substream
->runtime
,
279 SNDRV_PCM_HW_PARAM_PERIODS
);
283 snd_soc_set_runtime_hwparams(substream
, &snd_imx_hardware
);
287 static struct snd_pcm_ops imx_pcm_ops
= {
288 .open
= snd_imx_open
,
289 .ioctl
= snd_pcm_lib_ioctl
,
290 .hw_params
= snd_imx_pcm_hw_params
,
291 .hw_free
= snd_imx_pcm_hw_free
,
292 .prepare
= snd_imx_pcm_prepare
,
293 .trigger
= snd_imx_pcm_trigger
,
294 .pointer
= snd_imx_pcm_pointer
,
295 .mmap
= snd_imx_pcm_mmap
,
298 static struct snd_soc_platform imx_soc_platform_dma
= {
300 .pcm_ops
= &imx_pcm_ops
,
301 .pcm_new
= imx_pcm_new
,
302 .pcm_free
= imx_pcm_free
,
305 struct snd_soc_platform
*imx_ssi_dma_mx2_init(struct platform_device
*pdev
,
308 ssi
->dma_params_tx
.burstsize
= DMA_TXFIFO_BURST
;
309 ssi
->dma_params_rx
.burstsize
= DMA_RXFIFO_BURST
;
311 return &imx_soc_platform_dma
;