]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - sound/soc/pxa/pxa2xx-pcm.c
ff32f892287ee614bc31c19b6896df0d7aa636f5
[karo-tx-linux.git] / sound / soc / pxa / pxa2xx-pcm.c
1 /*
2  * linux/sound/arm/pxa2xx-pcm.c -- ALSA PCM interface for the Intel PXA2xx chip
3  *
4  * Author:      Nicolas Pitre
5  * Created:     Nov 30, 2004
6  * Copyright:   (C) 2004 MontaVista Software, Inc.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/platform_device.h>
16 #include <linux/slab.h>
17 #include <linux/dma-mapping.h>
18
19 #include <sound/driver.h>
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc.h>
24
25 #include <asm/dma.h>
26 #include <asm/hardware.h>
27 #include <asm/arch/pxa-regs.h>
28 #include <asm/arch/audio.h>
29
30 #include "pxa2xx-pcm.h"
31
32 static const struct snd_pcm_hardware pxa2xx_pcm_hardware = {
33         .info                   = SNDRV_PCM_INFO_MMAP |
34                                   SNDRV_PCM_INFO_MMAP_VALID |
35                                   SNDRV_PCM_INFO_INTERLEAVED |
36                                   SNDRV_PCM_INFO_PAUSE |
37                                   SNDRV_PCM_INFO_RESUME,
38         .formats                = SNDRV_PCM_FMTBIT_S16_LE |
39                                         SNDRV_PCM_FMTBIT_S24_LE |
40                                         SNDRV_PCM_FMTBIT_S32_LE,
41         .period_bytes_min       = 32,
42         .period_bytes_max       = 8192 - 32,
43         .periods_min            = 1,
44         .periods_max            = PAGE_SIZE/sizeof(pxa_dma_desc),
45         .buffer_bytes_max       = 128 * 1024,
46         .fifo_size              = 32,
47 };
48
49 struct pxa2xx_runtime_data {
50         int dma_ch;
51         struct pxa2xx_pcm_dma_params *params;
52         pxa_dma_desc *dma_desc_array;
53         dma_addr_t dma_desc_array_phys;
54 };
55
56 static void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
57 {
58         struct snd_pcm_substream *substream = dev_id;
59         struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
60         int dcsr;
61
62         dcsr = DCSR(dma_ch);
63         DCSR(dma_ch) = dcsr & ~DCSR_STOPIRQEN;
64
65         if (dcsr & DCSR_ENDINTR) {
66                 snd_pcm_period_elapsed(substream);
67         } else {
68                 printk( KERN_ERR "%s: DMA error on channel %d (DCSR=%#x)\n",
69                         prtd->params->name, dma_ch, dcsr );
70         }
71 }
72
73 static int pxa2xx_pcm_hw_params(struct snd_pcm_substream *substream,
74         struct snd_pcm_hw_params *params)
75 {
76         struct snd_pcm_runtime *runtime = substream->runtime;
77         struct pxa2xx_runtime_data *prtd = runtime->private_data;
78         struct snd_soc_pcm_runtime *rtd = substream->private_data;
79         struct pxa2xx_pcm_dma_params *dma = rtd->cpu_dai->dma_data;
80         size_t totsize = params_buffer_bytes(params);
81         size_t period = params_period_bytes(params);
82         pxa_dma_desc *dma_desc;
83         dma_addr_t dma_buff_phys, next_desc_phys;
84         int ret;
85
86         /* this may get called several times by oss emulation
87          * with different params */
88         if (prtd->params == NULL) {
89                 prtd->params = dma;
90                 ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
91                               pxa2xx_pcm_dma_irq, substream);
92                 if (ret < 0)
93                         return ret;
94                 prtd->dma_ch = ret;
95         } else if (prtd->params != dma) {
96                 pxa_free_dma(prtd->dma_ch);
97                 prtd->params = dma;
98                 ret = pxa_request_dma(prtd->params->name, DMA_PRIO_LOW,
99                               pxa2xx_pcm_dma_irq, substream);
100                 if (ret < 0)
101                         return ret;
102                 prtd->dma_ch = ret;
103         }
104
105         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
106         runtime->dma_bytes = totsize;
107
108         dma_desc = prtd->dma_desc_array;
109         next_desc_phys = prtd->dma_desc_array_phys;
110         dma_buff_phys = runtime->dma_addr;
111         do {
112                 next_desc_phys += sizeof(pxa_dma_desc);
113                 dma_desc->ddadr = next_desc_phys;
114                 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
115                         dma_desc->dsadr = dma_buff_phys;
116                         dma_desc->dtadr = prtd->params->dev_addr;
117                 } else {
118                         dma_desc->dsadr = prtd->params->dev_addr;
119                         dma_desc->dtadr = dma_buff_phys;
120                 }
121                 if (period > totsize)
122                         period = totsize;
123                 dma_desc->dcmd = prtd->params->dcmd | period | DCMD_ENDIRQEN;
124                 dma_desc++;
125                 dma_buff_phys += period;
126         } while (totsize -= period);
127         dma_desc[-1].ddadr = prtd->dma_desc_array_phys;
128
129         return 0;
130 }
131
132 static int pxa2xx_pcm_hw_free(struct snd_pcm_substream *substream)
133 {
134         struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
135
136         if (prtd && prtd->params)
137                 *prtd->params->drcmr = 0;
138
139         if (prtd->dma_ch) {
140                 snd_pcm_set_runtime_buffer(substream, NULL);
141                 pxa_free_dma(prtd->dma_ch);
142                 prtd->dma_ch = 0;
143         }
144
145         return 0;
146 }
147
148 static int pxa2xx_pcm_prepare(struct snd_pcm_substream *substream)
149 {
150         struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
151
152         DCSR(prtd->dma_ch) &= ~DCSR_RUN;
153         DCSR(prtd->dma_ch) = 0;
154         DCMD(prtd->dma_ch) = 0;
155         *prtd->params->drcmr = prtd->dma_ch | DRCMR_MAPVLD;
156
157         return 0;
158 }
159
160 static int pxa2xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
161 {
162         struct pxa2xx_runtime_data *prtd = substream->runtime->private_data;
163         int ret = 0;
164
165         switch (cmd) {
166         case SNDRV_PCM_TRIGGER_START:
167                 DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
168                 DCSR(prtd->dma_ch) = DCSR_RUN;
169                 break;
170
171         case SNDRV_PCM_TRIGGER_STOP:
172         case SNDRV_PCM_TRIGGER_SUSPEND:
173         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
174                 DCSR(prtd->dma_ch) &= ~DCSR_RUN;
175                 break;
176
177         case SNDRV_PCM_TRIGGER_RESUME:
178                 DCSR(prtd->dma_ch) |= DCSR_RUN;
179                 break;
180         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
181                 DDADR(prtd->dma_ch) = prtd->dma_desc_array_phys;
182                 DCSR(prtd->dma_ch) |= DCSR_RUN;
183                 break;
184
185         default:
186                 ret = -EINVAL;
187         }
188
189         return ret;
190 }
191
192 static snd_pcm_uframes_t
193 pxa2xx_pcm_pointer(struct snd_pcm_substream *substream)
194 {
195         struct snd_pcm_runtime *runtime = substream->runtime;
196         struct pxa2xx_runtime_data *prtd = runtime->private_data;
197
198         dma_addr_t ptr = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
199                          DSADR(prtd->dma_ch) : DTADR(prtd->dma_ch);
200         snd_pcm_uframes_t x = bytes_to_frames(runtime, ptr - runtime->dma_addr);
201
202         if (x == runtime->buffer_size)
203                 x = 0;
204         return x;
205 }
206
207 static int pxa2xx_pcm_open(struct snd_pcm_substream *substream)
208 {
209         struct snd_pcm_runtime *runtime = substream->runtime;
210         struct pxa2xx_runtime_data *prtd;
211         int ret;
212
213         snd_soc_set_runtime_hwparams(substream, &pxa2xx_pcm_hardware);
214
215         /*
216          * For mysterious reasons (and despite what the manual says)
217          * playback samples are lost if the DMA count is not a multiple
218          * of the DMA burst size.  Let's add a rule to enforce that.
219          */
220         ret = snd_pcm_hw_constraint_step(runtime, 0,
221                 SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 32);
222         if (ret)
223                 goto out;
224
225         ret = snd_pcm_hw_constraint_step(runtime, 0,
226                 SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 32);
227         if (ret)
228                 goto out;
229
230         prtd = kzalloc(sizeof(struct pxa2xx_runtime_data), GFP_KERNEL);
231         if (prtd == NULL) {
232                 ret = -ENOMEM;
233                 goto out;
234         }
235
236         prtd->dma_desc_array =
237                 dma_alloc_writecombine(substream->pcm->card->dev, PAGE_SIZE,
238                                        &prtd->dma_desc_array_phys, GFP_KERNEL);
239         if (!prtd->dma_desc_array) {
240                 ret = -ENOMEM;
241                 goto err1;
242         }
243
244         runtime->private_data = prtd;
245         return 0;
246
247  err1:
248         kfree(prtd);
249  out:
250         return ret;
251 }
252
253 static int pxa2xx_pcm_close(struct snd_pcm_substream *substream)
254 {
255         struct snd_pcm_runtime *runtime = substream->runtime;
256         struct pxa2xx_runtime_data *prtd = runtime->private_data;
257
258         dma_free_writecombine(substream->pcm->card->dev, PAGE_SIZE,
259                               prtd->dma_desc_array, prtd->dma_desc_array_phys);
260         kfree(prtd);
261         return 0;
262 }
263
264 static int pxa2xx_pcm_mmap(struct snd_pcm_substream *substream,
265         struct vm_area_struct *vma)
266 {
267         struct snd_pcm_runtime *runtime = substream->runtime;
268         return dma_mmap_writecombine(substream->pcm->card->dev, vma,
269                                      runtime->dma_area,
270                                      runtime->dma_addr,
271                                      runtime->dma_bytes);
272 }
273
274 struct snd_pcm_ops pxa2xx_pcm_ops = {
275         .open           = pxa2xx_pcm_open,
276         .close          = pxa2xx_pcm_close,
277         .ioctl          = snd_pcm_lib_ioctl,
278         .hw_params      = pxa2xx_pcm_hw_params,
279         .hw_free        = pxa2xx_pcm_hw_free,
280         .prepare        = pxa2xx_pcm_prepare,
281         .trigger        = pxa2xx_pcm_trigger,
282         .pointer        = pxa2xx_pcm_pointer,
283         .mmap           = pxa2xx_pcm_mmap,
284 };
285
286 static int pxa2xx_pcm_preallocate_dma_buffer(struct snd_pcm *pcm, int stream)
287 {
288         struct snd_pcm_substream *substream = pcm->streams[stream].substream;
289         struct snd_dma_buffer *buf = &substream->dma_buffer;
290         size_t size = pxa2xx_pcm_hardware.buffer_bytes_max;
291         buf->dev.type = SNDRV_DMA_TYPE_DEV;
292         buf->dev.dev = pcm->card->dev;
293         buf->private_data = NULL;
294         buf->area = dma_alloc_writecombine(pcm->card->dev, size,
295                                            &buf->addr, GFP_KERNEL);
296         if (!buf->area)
297                 return -ENOMEM;
298         buf->bytes = size;
299         return 0;
300 }
301
302 static void pxa2xx_pcm_free_dma_buffers(struct snd_pcm *pcm)
303 {
304         struct snd_pcm_substream *substream;
305         struct snd_dma_buffer *buf;
306         int stream;
307
308         for (stream = 0; stream < 2; stream++) {
309                 substream = pcm->streams[stream].substream;
310                 if (!substream)
311                         continue;
312
313                 buf = &substream->dma_buffer;
314                 if (!buf->area)
315                         continue;
316
317                 dma_free_writecombine(pcm->card->dev, buf->bytes,
318                                       buf->area, buf->addr);
319                 buf->area = NULL;
320         }
321 }
322
323 static u64 pxa2xx_pcm_dmamask = DMA_32BIT_MASK;
324
325 int pxa2xx_pcm_new(struct snd_card *card, struct snd_soc_codec_dai *dai,
326         struct snd_pcm *pcm)
327 {
328         int ret = 0;
329
330         if (!card->dev->dma_mask)
331                 card->dev->dma_mask = &pxa2xx_pcm_dmamask;
332         if (!card->dev->coherent_dma_mask)
333                 card->dev->coherent_dma_mask = DMA_32BIT_MASK;
334
335         if (dai->playback.channels_min) {
336                 ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
337                         SNDRV_PCM_STREAM_PLAYBACK);
338                 if (ret)
339                         goto out;
340         }
341
342         if (dai->capture.channels_min) {
343                 ret = pxa2xx_pcm_preallocate_dma_buffer(pcm,
344                         SNDRV_PCM_STREAM_CAPTURE);
345                 if (ret)
346                         goto out;
347         }
348  out:
349         return ret;
350 }
351
352 struct snd_soc_platform pxa2xx_soc_platform = {
353         .name           = "pxa2xx-audio",
354         .pcm_ops        = &pxa2xx_pcm_ops,
355         .pcm_new        = pxa2xx_pcm_new,
356         .pcm_free       = pxa2xx_pcm_free_dma_buffers,
357 };
358
359 EXPORT_SYMBOL_GPL(pxa2xx_soc_platform);
360
361 MODULE_AUTHOR("Nicolas Pitre");
362 MODULE_DESCRIPTION("Intel PXA2xx PCM DMA module");
363 MODULE_LICENSE("GPL");