Merge branch 'hwmon-for-linus' of git://jdelvare.pck.nerim.net/jdelvare-2.6
[sfrench/cifs-2.6.git] / sound / soc / at91 / at91-pcm.c
1 /*
2  * at91-pcm.c -- ALSA PCM interface for the Atmel AT91 SoC
3  *
4  * Author:      Frank Mandarino <fmandarino@endrelia.com>
5  *              Endrelia Technologies Inc.
6  * Created:     Mar 3, 2006
7  *
8  * Based on pxa2xx-pcm.c by:
9  *
10  * Author:      Nicolas Pitre
11  * Created:     Nov 30, 2004
12  * Copyright:   (C) 2004 MontaVista Software, Inc.
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License version 2 as
16  * published by the Free Software Foundation.
17  */
18
19 #include <linux/module.h>
20 #include <linux/init.h>
21 #include <linux/platform_device.h>
22 #include <linux/slab.h>
23 #include <linux/dma-mapping.h>
24 #include <linux/atmel_pdc.h>
25
26 #include <sound/driver.h>
27 #include <sound/core.h>
28 #include <sound/pcm.h>
29 #include <sound/pcm_params.h>
30 #include <sound/soc.h>
31
32 #include <asm/arch/hardware.h>
33 #include <asm/arch/at91_ssc.h>
34
35 #include "at91-pcm.h"
36
37 #if 0
38 #define DBG(x...)       printk(KERN_INFO "at91-pcm: " x)
39 #else
40 #define DBG(x...)
41 #endif
42
43 static const struct snd_pcm_hardware at91_pcm_hardware = {
44         .info                   = SNDRV_PCM_INFO_MMAP |
45                                   SNDRV_PCM_INFO_MMAP_VALID |
46                                   SNDRV_PCM_INFO_INTERLEAVED |
47                                   SNDRV_PCM_INFO_PAUSE,
48         .formats                = SNDRV_PCM_FMTBIT_S16_LE,
49         .period_bytes_min       = 32,
50         .period_bytes_max       = 8192,
51         .periods_min            = 2,
52         .periods_max            = 1024,
53         .buffer_bytes_max       = 32 * 1024,
54 };
55
56 struct at91_runtime_data {
57         struct at91_pcm_dma_params *params;
58         dma_addr_t dma_buffer;                  /* physical address of dma buffer */
59         dma_addr_t dma_buffer_end;              /* first address beyond DMA buffer */
60         size_t period_size;
61         dma_addr_t period_ptr;                  /* physical address of next period */
62         u32 pdc_xpr_save;                       /* PDC register save */
63         u32 pdc_xcr_save;
64         u32 pdc_xnpr_save;
65         u32 pdc_xncr_save;
66 };
67
68 static void at91_pcm_dma_irq(u32 ssc_sr,
69         struct snd_pcm_substream *substream)
70 {
71         struct at91_runtime_data *prtd = substream->runtime->private_data;
72         struct at91_pcm_dma_params *params = prtd->params;
73         static int count = 0;
74
75         count++;
76
77         if (ssc_sr & params->mask->ssc_endbuf) {
78
79                 printk(KERN_WARNING
80                         "at91-pcm: buffer %s on %s (SSC_SR=%#x, count=%d)\n",
81                         substream->stream == SNDRV_PCM_STREAM_PLAYBACK
82                                 ? "underrun" : "overrun",
83                         params->name, ssc_sr, count);
84
85                 /* re-start the PDC */
86                 at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
87
88                 prtd->period_ptr += prtd->period_size;
89                 if (prtd->period_ptr >= prtd->dma_buffer_end) {
90                         prtd->period_ptr = prtd->dma_buffer;
91                 }
92
93                 at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
94                 at91_ssc_write(params->ssc_base + params->pdc->xcr,
95                                 prtd->period_size / params->pdc_xfer_size);
96
97                 at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
98         }
99
100         if (ssc_sr & params->mask->ssc_endx) {
101
102                 /* Load the PDC next pointer and counter registers */
103                 prtd->period_ptr += prtd->period_size;
104                 if (prtd->period_ptr >= prtd->dma_buffer_end) {
105                         prtd->period_ptr = prtd->dma_buffer;
106                 }
107                 at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
108                 at91_ssc_write(params->ssc_base + params->pdc->xncr,
109                                 prtd->period_size / params->pdc_xfer_size);
110         }
111
112         snd_pcm_period_elapsed(substream);
113 }
114
115 static int at91_pcm_hw_params(struct snd_pcm_substream *substream,
116         struct snd_pcm_hw_params *params)
117 {
118         struct snd_pcm_runtime *runtime = substream->runtime;
119         struct at91_runtime_data *prtd = runtime->private_data;
120         struct snd_soc_pcm_runtime *rtd = substream->private_data;
121
122         /* this may get called several times by oss emulation
123          * with different params */
124
125         snd_pcm_set_runtime_buffer(substream, &substream->dma_buffer);
126         runtime->dma_bytes = params_buffer_bytes(params);
127
128         prtd->params = rtd->dai->cpu_dai->dma_data;
129         prtd->params->dma_intr_handler = at91_pcm_dma_irq;
130
131         prtd->dma_buffer = runtime->dma_addr;
132         prtd->dma_buffer_end = runtime->dma_addr + runtime->dma_bytes;
133         prtd->period_size = params_period_bytes(params);
134
135         DBG("hw_params: DMA for %s initialized (dma_bytes=%d, period_size=%d)\n",
136                 prtd->params->name, runtime->dma_bytes, prtd->period_size);
137         return 0;
138 }
139
140 static int at91_pcm_hw_free(struct snd_pcm_substream *substream)
141 {
142         struct at91_runtime_data *prtd = substream->runtime->private_data;
143         struct at91_pcm_dma_params *params = prtd->params;
144
145         if (params != NULL) {
146                 at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
147                 prtd->params->dma_intr_handler = NULL;
148         }
149
150         return 0;
151 }
152
153 static int at91_pcm_prepare(struct snd_pcm_substream *substream)
154 {
155         struct at91_runtime_data *prtd = substream->runtime->private_data;
156         struct at91_pcm_dma_params *params = prtd->params;
157
158         at91_ssc_write(params->ssc_base + AT91_SSC_IDR,
159                         params->mask->ssc_endx | params->mask->ssc_endbuf);
160
161         at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
162         return 0;
163 }
164
165 static int at91_pcm_trigger(struct snd_pcm_substream *substream,
166         int cmd)
167 {
168         struct at91_runtime_data *prtd = substream->runtime->private_data;
169         struct at91_pcm_dma_params *params = prtd->params;
170         int ret = 0;
171
172         switch (cmd) {
173         case SNDRV_PCM_TRIGGER_START:
174                 prtd->period_ptr = prtd->dma_buffer;
175
176                 at91_ssc_write(params->ssc_base + params->pdc->xpr, prtd->period_ptr);
177                 at91_ssc_write(params->ssc_base + params->pdc->xcr,
178                                 prtd->period_size / params->pdc_xfer_size);
179
180                 prtd->period_ptr += prtd->period_size;
181                 at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->period_ptr);
182                 at91_ssc_write(params->ssc_base + params->pdc->xncr,
183                                 prtd->period_size / params->pdc_xfer_size);
184
185                 DBG("trigger: period_ptr=%lx, xpr=%lx, xcr=%ld, xnpr=%lx, xncr=%ld\n",
186                         (unsigned long) prtd->period_ptr,
187                         at91_ssc_read(params->ssc_base + params->pdc->xpr),
188                         at91_ssc_read(params->ssc_base + params->pdc->xcr),
189                         at91_ssc_read(params->ssc_base + params->pdc->xnpr),
190                         at91_ssc_read(params->ssc_base + params->pdc->xncr));
191
192                 at91_ssc_write(params->ssc_base + AT91_SSC_IER,
193                         params->mask->ssc_endx | params->mask->ssc_endbuf);
194
195                 at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
196
197                 DBG("sr=%lx imr=%lx\n", at91_ssc_read(params->ssc_base + AT91_SSC_SR),
198                                         at91_ssc_read(params->ssc_base + AT91_SSC_IER));
199                 break;
200
201         case SNDRV_PCM_TRIGGER_STOP:
202         case SNDRV_PCM_TRIGGER_SUSPEND:
203         case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
204                 at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
205                 break;
206
207         case SNDRV_PCM_TRIGGER_RESUME:
208         case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
209                 at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
210                 break;
211
212         default:
213                 ret = -EINVAL;
214         }
215
216         return ret;
217 }
218
219 static snd_pcm_uframes_t at91_pcm_pointer(
220         struct snd_pcm_substream *substream)
221 {
222         struct snd_pcm_runtime *runtime = substream->runtime;
223         struct at91_runtime_data *prtd = runtime->private_data;
224         struct at91_pcm_dma_params *params = prtd->params;
225         dma_addr_t ptr;
226         snd_pcm_uframes_t x;
227
228         ptr = (dma_addr_t) at91_ssc_read(params->ssc_base + params->pdc->xpr);
229         x = bytes_to_frames(runtime, ptr - prtd->dma_buffer);
230
231         if (x == runtime->buffer_size)
232                 x = 0;
233         return x;
234 }
235
236 static int at91_pcm_open(struct snd_pcm_substream *substream)
237 {
238         struct snd_pcm_runtime *runtime = substream->runtime;
239         struct at91_runtime_data *prtd;
240         int ret = 0;
241
242         snd_soc_set_runtime_hwparams(substream, &at91_pcm_hardware);
243
244         /* ensure that buffer size is a multiple of period size */
245         ret = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
246         if (ret < 0)
247                 goto out;
248
249         prtd = kzalloc(sizeof(struct at91_runtime_data), GFP_KERNEL);
250         if (prtd == NULL) {
251                 ret = -ENOMEM;
252                 goto out;
253         }
254         runtime->private_data = prtd;
255
256  out:
257         return ret;
258 }
259
260 static int at91_pcm_close(struct snd_pcm_substream *substream)
261 {
262         struct at91_runtime_data *prtd = substream->runtime->private_data;
263
264         kfree(prtd);
265         return 0;
266 }
267
268 static int at91_pcm_mmap(struct snd_pcm_substream *substream,
269         struct vm_area_struct *vma)
270 {
271         struct snd_pcm_runtime *runtime = substream->runtime;
272
273         return dma_mmap_writecombine(substream->pcm->card->dev, vma,
274                                      runtime->dma_area,
275                                      runtime->dma_addr,
276                                      runtime->dma_bytes);
277 }
278
279 struct snd_pcm_ops at91_pcm_ops = {
280         .open           = at91_pcm_open,
281         .close          = at91_pcm_close,
282         .ioctl          = snd_pcm_lib_ioctl,
283         .hw_params      = at91_pcm_hw_params,
284         .hw_free        = at91_pcm_hw_free,
285         .prepare        = at91_pcm_prepare,
286         .trigger        = at91_pcm_trigger,
287         .pointer        = at91_pcm_pointer,
288         .mmap           = at91_pcm_mmap,
289 };
290
291 static int at91_pcm_preallocate_dma_buffer(struct snd_pcm *pcm,
292         int stream)
293 {
294         struct snd_pcm_substream *substream = pcm->streams[stream].substream;
295         struct snd_dma_buffer *buf = &substream->dma_buffer;
296         size_t size = at91_pcm_hardware.buffer_bytes_max;
297
298         buf->dev.type = SNDRV_DMA_TYPE_DEV;
299         buf->dev.dev = pcm->card->dev;
300         buf->private_data = NULL;
301         buf->area = dma_alloc_writecombine(pcm->card->dev, size,
302                                            &buf->addr, GFP_KERNEL);
303
304         DBG("preallocate_dma_buffer: area=%p, addr=%p, size=%d\n",
305                 (void *) buf->area,
306                 (void *) buf->addr,
307                 size);
308
309         if (!buf->area)
310                 return -ENOMEM;
311
312         buf->bytes = size;
313         return 0;
314 }
315
316 static u64 at91_pcm_dmamask = 0xffffffff;
317
318 static int at91_pcm_new(struct snd_card *card,
319         struct snd_soc_codec_dai *dai, struct snd_pcm *pcm)
320 {
321         int ret = 0;
322
323         if (!card->dev->dma_mask)
324                 card->dev->dma_mask = &at91_pcm_dmamask;
325         if (!card->dev->coherent_dma_mask)
326                 card->dev->coherent_dma_mask = 0xffffffff;
327
328         if (dai->playback.channels_min) {
329                 ret = at91_pcm_preallocate_dma_buffer(pcm,
330                         SNDRV_PCM_STREAM_PLAYBACK);
331                 if (ret)
332                         goto out;
333         }
334
335         if (dai->capture.channels_min) {
336                 ret = at91_pcm_preallocate_dma_buffer(pcm,
337                         SNDRV_PCM_STREAM_CAPTURE);
338                 if (ret)
339                         goto out;
340         }
341  out:
342         return ret;
343 }
344
345 static void at91_pcm_free_dma_buffers(struct snd_pcm *pcm)
346 {
347         struct snd_pcm_substream *substream;
348         struct snd_dma_buffer *buf;
349         int stream;
350
351         for (stream = 0; stream < 2; stream++) {
352                 substream = pcm->streams[stream].substream;
353                 if (!substream)
354                         continue;
355
356                 buf = &substream->dma_buffer;
357                 if (!buf->area)
358                         continue;
359
360                 dma_free_writecombine(pcm->card->dev, buf->bytes,
361                                       buf->area, buf->addr);
362                 buf->area = NULL;
363         }
364 }
365
366 #ifdef CONFIG_PM
367 static int at91_pcm_suspend(struct platform_device *pdev,
368         struct snd_soc_cpu_dai *dai)
369 {
370         struct snd_pcm_runtime *runtime = dai->runtime;
371         struct at91_runtime_data *prtd;
372         struct at91_pcm_dma_params *params;
373
374         if (!runtime)
375                 return 0;
376
377         prtd = runtime->private_data;
378         params = prtd->params;
379
380         /* disable the PDC and save the PDC registers */
381
382         at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_disable);
383
384         prtd->pdc_xpr_save  = at91_ssc_read(params->ssc_base + params->pdc->xpr);
385         prtd->pdc_xcr_save  = at91_ssc_read(params->ssc_base + params->pdc->xcr);
386         prtd->pdc_xnpr_save = at91_ssc_read(params->ssc_base + params->pdc->xnpr);
387         prtd->pdc_xncr_save = at91_ssc_read(params->ssc_base + params->pdc->xncr);
388
389         return 0;
390 }
391
392 static int at91_pcm_resume(struct platform_device *pdev,
393         struct snd_soc_cpu_dai *dai)
394 {
395         struct snd_pcm_runtime *runtime = dai->runtime;
396         struct at91_runtime_data *prtd;
397         struct at91_pcm_dma_params *params;
398
399         if (!runtime)
400                 return 0;
401
402         prtd = runtime->private_data;
403         params = prtd->params;
404
405         /* restore the PDC registers and enable the PDC */
406         at91_ssc_write(params->ssc_base + params->pdc->xpr,  prtd->pdc_xpr_save);
407         at91_ssc_write(params->ssc_base + params->pdc->xcr,  prtd->pdc_xcr_save);
408         at91_ssc_write(params->ssc_base + params->pdc->xnpr, prtd->pdc_xnpr_save);
409         at91_ssc_write(params->ssc_base + params->pdc->xncr, prtd->pdc_xncr_save);
410
411         at91_ssc_write(params->ssc_base + ATMEL_PDC_PTCR, params->mask->pdc_enable);
412         return 0;
413 }
414 #else
415 #define at91_pcm_suspend        NULL
416 #define at91_pcm_resume         NULL
417 #endif
418
419 struct snd_soc_platform at91_soc_platform = {
420         .name           = "at91-audio",
421         .pcm_ops        = &at91_pcm_ops,
422         .pcm_new        = at91_pcm_new,
423         .pcm_free       = at91_pcm_free_dma_buffers,
424         .suspend        = at91_pcm_suspend,
425         .resume         = at91_pcm_resume,
426 };
427
428 EXPORT_SYMBOL_GPL(at91_soc_platform);
429
430 MODULE_AUTHOR("Frank Mandarino <fmandarino@endrelia.com>");
431 MODULE_DESCRIPTION("Atmel AT91 PCM module");
432 MODULE_LICENSE("GPL");