2 * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
4 * Based on sound/soc/imx/imx-pcm-dma-mx2.c
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <linux/clk.h>
22 #include <linux/delay.h>
23 #include <linux/device.h>
24 #include <linux/dma-mapping.h>
25 #include <linux/init.h>
26 #include <linux/interrupt.h>
27 #include <linux/module.h>
28 #include <linux/platform_device.h>
29 #include <linux/slab.h>
30 #include <linux/dmaengine.h>
32 #include <sound/core.h>
33 #include <sound/initval.h>
34 #include <sound/pcm.h>
35 #include <sound/pcm_params.h>
36 #include <sound/soc.h>
41 static struct snd_pcm_hardware snd_mxs_hardware
= {
42 .info
= SNDRV_PCM_INFO_MMAP
|
43 SNDRV_PCM_INFO_MMAP_VALID
|
44 SNDRV_PCM_INFO_PAUSE
|
45 SNDRV_PCM_INFO_RESUME
|
46 SNDRV_PCM_INFO_INTERLEAVED
,
47 .formats
= SNDRV_PCM_FMTBIT_S16_LE
|
48 SNDRV_PCM_FMTBIT_S20_3LE
|
49 SNDRV_PCM_FMTBIT_S24_LE
,
52 .period_bytes_min
= 32,
53 .period_bytes_max
= 8192,
56 .buffer_bytes_max
= 64 * 1024,
61 static void audio_dma_irq(void *data
)
63 struct snd_pcm_substream
*substream
= (struct snd_pcm_substream
*)data
;
64 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
65 struct mxs_pcm_runtime_data
*iprtd
= runtime
->private_data
;
67 iprtd
->offset
+= iprtd
->period_bytes
;
68 iprtd
->offset
%= iprtd
->period_bytes
* iprtd
->periods
;
69 snd_pcm_period_elapsed(substream
);
72 static bool filter(struct dma_chan
*chan
, void *param
)
74 struct mxs_pcm_runtime_data
*iprtd
= param
;
75 struct mxs_pcm_dma_params
*dma_params
= iprtd
->dma_params
;
77 if (!mxs_dma_is_apbx(chan
))
80 if (chan
->chan_id
!= dma_params
->chan_num
)
83 chan
->private = &iprtd
->dma_data
;
88 static int mxs_dma_alloc(struct snd_pcm_substream
*substream
,
89 struct snd_pcm_hw_params
*params
)
91 struct snd_soc_pcm_runtime
*rtd
= substream
->private_data
;
92 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
93 struct mxs_pcm_runtime_data
*iprtd
= runtime
->private_data
;
96 iprtd
->dma_params
= snd_soc_dai_get_dma_data(rtd
->cpu_dai
, substream
);
99 dma_cap_set(DMA_SLAVE
, mask
);
100 iprtd
->dma_data
.chan_irq
= iprtd
->dma_params
->chan_irq
;
101 iprtd
->dma_chan
= dma_request_channel(mask
, filter
, iprtd
);
102 if (!iprtd
->dma_chan
)
108 static int snd_mxs_pcm_hw_params(struct snd_pcm_substream
*substream
,
109 struct snd_pcm_hw_params
*params
)
111 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
112 struct mxs_pcm_runtime_data
*iprtd
= runtime
->private_data
;
113 unsigned long dma_addr
;
114 struct dma_chan
*chan
;
117 ret
= mxs_dma_alloc(substream
, params
);
120 chan
= iprtd
->dma_chan
;
122 iprtd
->size
= params_buffer_bytes(params
);
123 iprtd
->periods
= params_periods(params
);
124 iprtd
->period_bytes
= params_period_bytes(params
);
126 iprtd
->period_time
= HZ
/ (params_rate(params
) /
127 params_period_size(params
));
129 snd_pcm_set_runtime_buffer(substream
, &substream
->dma_buffer
);
131 dma_addr
= runtime
->dma_addr
;
133 iprtd
->buf
= substream
->dma_buffer
.area
;
135 iprtd
->desc
= chan
->device
->device_prep_dma_cyclic(chan
, dma_addr
,
136 iprtd
->period_bytes
* iprtd
->periods
,
138 substream
->stream
== SNDRV_PCM_STREAM_PLAYBACK
?
139 DMA_MEM_TO_DEV
: DMA_DEV_TO_MEM
);
141 dev_err(&chan
->dev
->device
, "cannot prepare slave dma\n");
145 iprtd
->desc
->callback
= audio_dma_irq
;
146 iprtd
->desc
->callback_param
= substream
;
151 static int snd_mxs_pcm_hw_free(struct snd_pcm_substream
*substream
)
153 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
154 struct mxs_pcm_runtime_data
*iprtd
= runtime
->private_data
;
156 if (iprtd
->dma_chan
) {
157 dma_release_channel(iprtd
->dma_chan
);
158 iprtd
->dma_chan
= NULL
;
164 static int snd_mxs_pcm_trigger(struct snd_pcm_substream
*substream
, int cmd
)
166 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
167 struct mxs_pcm_runtime_data
*iprtd
= runtime
->private_data
;
170 case SNDRV_PCM_TRIGGER_START
:
171 case SNDRV_PCM_TRIGGER_RESUME
:
172 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE
:
173 dmaengine_submit(iprtd
->desc
);
176 case SNDRV_PCM_TRIGGER_STOP
:
177 case SNDRV_PCM_TRIGGER_SUSPEND
:
178 case SNDRV_PCM_TRIGGER_PAUSE_PUSH
:
179 dmaengine_terminate_all(iprtd
->dma_chan
);
189 static snd_pcm_uframes_t
snd_mxs_pcm_pointer(
190 struct snd_pcm_substream
*substream
)
192 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
193 struct mxs_pcm_runtime_data
*iprtd
= runtime
->private_data
;
195 return bytes_to_frames(substream
->runtime
, iprtd
->offset
);
198 static int snd_mxs_open(struct snd_pcm_substream
*substream
)
200 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
201 struct mxs_pcm_runtime_data
*iprtd
;
204 iprtd
= kzalloc(sizeof(*iprtd
), GFP_KERNEL
);
207 runtime
->private_data
= iprtd
;
209 ret
= snd_pcm_hw_constraint_integer(substream
->runtime
,
210 SNDRV_PCM_HW_PARAM_PERIODS
);
216 snd_soc_set_runtime_hwparams(substream
, &snd_mxs_hardware
);
221 static int snd_mxs_close(struct snd_pcm_substream
*substream
)
223 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
224 struct mxs_pcm_runtime_data
*iprtd
= runtime
->private_data
;
231 static int snd_mxs_pcm_mmap(struct snd_pcm_substream
*substream
,
232 struct vm_area_struct
*vma
)
234 struct snd_pcm_runtime
*runtime
= substream
->runtime
;
236 return dma_mmap_writecombine(substream
->pcm
->card
->dev
, vma
,
242 static struct snd_pcm_ops mxs_pcm_ops
= {
243 .open
= snd_mxs_open
,
244 .close
= snd_mxs_close
,
245 .ioctl
= snd_pcm_lib_ioctl
,
246 .hw_params
= snd_mxs_pcm_hw_params
,
247 .hw_free
= snd_mxs_pcm_hw_free
,
248 .trigger
= snd_mxs_pcm_trigger
,
249 .pointer
= snd_mxs_pcm_pointer
,
250 .mmap
= snd_mxs_pcm_mmap
,
253 static int mxs_pcm_preallocate_dma_buffer(struct snd_pcm
*pcm
, int stream
)
255 struct snd_pcm_substream
*substream
= pcm
->streams
[stream
].substream
;
256 struct snd_dma_buffer
*buf
= &substream
->dma_buffer
;
257 size_t size
= snd_mxs_hardware
.buffer_bytes_max
;
259 buf
->dev
.type
= SNDRV_DMA_TYPE_DEV
;
260 buf
->dev
.dev
= pcm
->card
->dev
;
261 buf
->private_data
= NULL
;
262 buf
->area
= dma_alloc_writecombine(pcm
->card
->dev
, size
,
263 &buf
->addr
, GFP_KERNEL
);
271 static u64 mxs_pcm_dmamask
= DMA_BIT_MASK(32);
272 static int mxs_pcm_new(struct snd_soc_pcm_runtime
*rtd
)
274 struct snd_card
*card
= rtd
->card
->snd_card
;
275 struct snd_pcm
*pcm
= rtd
->pcm
;
278 if (!card
->dev
->dma_mask
)
279 card
->dev
->dma_mask
= &mxs_pcm_dmamask
;
280 if (!card
->dev
->coherent_dma_mask
)
281 card
->dev
->coherent_dma_mask
= DMA_BIT_MASK(32);
283 if (pcm
->streams
[SNDRV_PCM_STREAM_PLAYBACK
].substream
) {
284 ret
= mxs_pcm_preallocate_dma_buffer(pcm
,
285 SNDRV_PCM_STREAM_PLAYBACK
);
290 if (pcm
->streams
[SNDRV_PCM_STREAM_CAPTURE
].substream
) {
291 ret
= mxs_pcm_preallocate_dma_buffer(pcm
,
292 SNDRV_PCM_STREAM_CAPTURE
);
301 static void mxs_pcm_free(struct snd_pcm
*pcm
)
303 struct snd_pcm_substream
*substream
;
304 struct snd_dma_buffer
*buf
;
307 for (stream
= 0; stream
< 2; stream
++) {
308 substream
= pcm
->streams
[stream
].substream
;
312 buf
= &substream
->dma_buffer
;
316 dma_free_writecombine(pcm
->card
->dev
, buf
->bytes
,
317 buf
->area
, buf
->addr
);
322 static struct snd_soc_platform_driver mxs_soc_platform
= {
324 .pcm_new
= mxs_pcm_new
,
325 .pcm_free
= mxs_pcm_free
,
328 static int __devinit
mxs_soc_platform_probe(struct platform_device
*pdev
)
330 return snd_soc_register_platform(&pdev
->dev
, &mxs_soc_platform
);
333 static int __devexit
mxs_soc_platform_remove(struct platform_device
*pdev
)
335 snd_soc_unregister_platform(&pdev
->dev
);
340 static struct platform_driver mxs_pcm_driver
= {
342 .name
= "mxs-pcm-audio",
343 .owner
= THIS_MODULE
,
345 .probe
= mxs_soc_platform_probe
,
346 .remove
= __devexit_p(mxs_soc_platform_remove
),
349 module_platform_driver(mxs_pcm_driver
);
351 MODULE_LICENSE("GPL");
352 MODULE_ALIAS("platform:mxs-pcm-audio");