]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa.c
Merge current mainline tree into linux-omap tree
[linux-2.6-omap-h63xx.git] / sound / arm / omap / omap-alsa.c
1 /*
2  * sound/arm/omap-alsa.c
3  *
4  * Alsa Driver for OMAP
5  *
6  * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
7  * Written by Daniel Petrini, David Cohen, Anderson Briglia
8  *            {daniel.petrini, david.cohen, anderson.briglia}@indt.org.br
9  *
10  * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
11  *
12  * Based on sa11xx-uda1341.c,
13  * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
14  *
15  * This program is free software; you can redistribute it and/or modify it
16  * under the terms of the GNU General Public License as published by the
17  * Free Software Foundation; either version 2 of the License, or (at your
18  * option) any later version.
19  *
20  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
21  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
23  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
26  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
27  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * You should have received a copy of the  GNU General Public License along
32  * with this program; if not, write  to the Free Software Foundation, Inc.,
33  * 675 Mass Ave, Cambridge, MA 02139, USA.
34  *
35  * History:
36  *
37  * 2005-07-29   INdT Kernel Team - Alsa driver for omap osk. Creation of new
38  *                                 file omap-aic23.c
39  *
40  * 2005-12-18   Dirk Behme       - Added L/R Channel Interchange fix as proposed
41  *                                 by Ajaya Babu
42  *
43  */
44
45 #include <linux/platform_device.h>
46 #ifdef CONFIG_PM
47 #include <linux/pm.h>
48 #endif
49 #include <sound/core.h>
50 #include <sound/pcm.h>
51
52 #include <asm/arch/omap-alsa.h>
53 #include "omap-alsa-dma.h"
54
55 MODULE_AUTHOR("Mika Laitio");
56 MODULE_AUTHOR("Daniel Petrini");
57 MODULE_AUTHOR("David Cohen");
58 MODULE_AUTHOR("Anderson Briglia");
59
60 MODULE_LICENSE("GPL");
61 MODULE_DESCRIPTION("OMAP driver for ALSA");
62 MODULE_ALIAS("omap_alsa_mcbsp.1");
63
64 static char *id;
65 static struct snd_card_omap_codec       *alsa_codec;
66 static struct omap_alsa_codec_config    *alsa_codec_config;
67
68 /*
69  * HW interface start and stop helper functions
70  */
71 static int audio_ifc_start(void)
72 {
73         omap_mcbsp_start(AUDIO_MCBSP);
74         return 0;
75 }
76
77 static int audio_ifc_stop(void)
78 {
79         omap_mcbsp_stop(AUDIO_MCBSP);
80         return 0;
81 }
82
83 static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
84 {
85         /* Setup DMA stuff */
86         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
87         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
88             SNDRV_PCM_STREAM_PLAYBACK;
89         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
90             OMAP_DMA_MCBSP1_TX;
91         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
92             audio_ifc_start;
93         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
94             audio_ifc_stop;
95
96         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
97         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
98             SNDRV_PCM_STREAM_CAPTURE;
99         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
100             OMAP_DMA_MCBSP1_RX;
101         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
102             audio_ifc_start;
103         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
104             audio_ifc_stop;
105 }
106
107 /*
108  * DMA functions
109  * Depends on omap-alsa-dma.c functions and (omap) dma.c
110  */
111 static int audio_dma_request(struct audio_stream *s,
112                              void (*callback) (void *))
113 {
114         int err;
115         ADEBUG();
116
117         err = omap_request_alsa_sound_dma(s->dma_dev, s->id, s, &s->lch);
118         if (err < 0)
119                 printk(KERN_ERR "Unable to grab audio dma 0x%x\n", s->dma_dev);
120         return err;
121 }
122
123 static int audio_dma_free(struct audio_stream *s)
124 {
125         int err = 0;
126         ADEBUG();
127
128         err = omap_free_alsa_sound_dma(s, &s->lch);
129         if (err < 0)
130                 printk(KERN_ERR "Unable to free audio dma channels!\n");
131         return err;
132 }
133
134 /*
135  *  This function should calculate the current position of the dma in the
136  *  buffer. It will help alsa middle layer to continue update the buffer.
137  *  Its correctness is crucial for good functioning.
138  */
139 static u_int audio_get_dma_pos(struct audio_stream *s)
140 {
141         struct snd_pcm_substream *substream = s->stream;
142         struct snd_pcm_runtime *runtime = substream->runtime;
143         unsigned int offset;
144         unsigned long flags;
145         dma_addr_t count;
146         ADEBUG();
147
148         /* this must be called w/ interrupts locked as requested in dma.c */
149         spin_lock_irqsave(&s->dma_lock, flags);
150
151         /* For the current period let's see where we are */
152         count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
153
154         spin_unlock_irqrestore(&s->dma_lock, flags);
155
156         /* Now, the position related to the end of that period */
157         offset = bytes_to_frames(runtime, s->offset) -
158                         bytes_to_frames(runtime, count);
159
160         if (offset >= runtime->buffer_size)
161                 offset = 0;
162
163         return offset;
164 }
165
166 /*
167  * this stops the dma and clears the dma ptrs
168  */
169 static void audio_stop_dma(struct audio_stream *s)
170 {
171         unsigned long flags;
172         ADEBUG();
173
174         spin_lock_irqsave(&s->dma_lock, flags);
175         s->active = 0;
176         s->period = 0;
177         s->periods = 0;
178
179         /* this stops the dma channel and clears the buffer ptrs */
180         omap_stop_alsa_sound_dma(s);
181
182         omap_clear_alsa_sound_dma(s);
183
184         spin_unlock_irqrestore(&s->dma_lock, flags);
185 }
186
187 /*
188  *  Main dma routine, requests dma according where you are in main alsa buffer
189  */
190 static void audio_process_dma(struct audio_stream *s)
191 {
192         struct snd_pcm_substream *substream = s->stream;
193         struct snd_pcm_runtime *runtime;
194         unsigned int dma_size;
195         unsigned int offset;
196         int ret;
197
198         ADEBUG();
199         runtime = substream->runtime;
200         if (s->active) {
201                 dma_size = frames_to_bytes(runtime, runtime->period_size);
202                 offset = dma_size * s->period;
203                 snd_assert(dma_size <= DMA_BUF_SIZE, return);
204                 /*
205                  * On omap1510 based devices, we need to call the stop_dma
206                  * before calling the start_dma or we will not receive the
207                  * irq from DMA after the first transfered/played buffer.
208                  * (invocation of callback_omap_alsa_sound_dma() method).
209                  */
210                 if (cpu_is_omap1510())
211                         omap_stop_alsa_sound_dma(s);
212
213                 ret = omap_start_alsa_sound_dma(s,
214                                 (dma_addr_t)runtime->dma_area + offset,
215                                 dma_size);
216                 if (ret) {
217                         printk(KERN_ERR "audio_process_dma: cannot"
218                                         " queue DMA buffer (%i)\n", ret);
219                         return;
220                 }
221
222                 s->period++;
223                 s->period %= runtime->periods;
224                 s->periods++;
225                 s->offset = offset;
226         }
227 }
228
229 /*
230  *  This is called when dma IRQ occurs at the end of each transmited block
231  */
232 void callback_omap_alsa_sound_dma(void *data)
233 {
234         struct audio_stream *s = data;
235
236         ADEBUG();
237         /*
238          * If we are getting a callback for an active stream then we inform
239          * the PCM middle layer we've finished a period
240          */
241         if (s->active)
242                 snd_pcm_period_elapsed(s->stream);
243
244         spin_lock(&s->dma_lock);
245         if (s->periods > 0)
246                 s->periods--;
247
248         audio_process_dma(s);
249         spin_unlock(&s->dma_lock);
250 }
251
252 /*
253  * Alsa section
254  * PCM settings and callbacks
255  */
256 static int snd_omap_alsa_trigger(struct snd_pcm_substream *substream, int cmd)
257 {
258         struct snd_card_omap_codec *chip =
259             snd_pcm_substream_chip(substream);
260         int stream_id = substream->pstr->stream;
261         struct audio_stream *s = &chip->s[stream_id];
262         int err = 0;
263
264         ADEBUG();
265         /* note local interrupts are already disabled in the midlevel code */
266         spin_lock(&s->dma_lock);
267         switch (cmd) {
268         case SNDRV_PCM_TRIGGER_START:
269                 /* requested stream startup */
270                 s->active = 1;
271                 audio_process_dma(s);
272                 break;
273         case SNDRV_PCM_TRIGGER_STOP:
274                 /* requested stream shutdown */
275                 audio_stop_dma(s);
276                 break;
277         default:
278                 err = -EINVAL;
279                 break;
280         }
281         spin_unlock(&s->dma_lock);
282
283         return err;
284 }
285
286 static int snd_omap_alsa_prepare(struct snd_pcm_substream *substream)
287 {
288         struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
289         struct snd_pcm_runtime *runtime = substream->runtime;
290         struct audio_stream *s = &chip->s[substream->pstr->stream];
291
292         ADEBUG();
293         /* set requested samplerate */
294         alsa_codec_config->codec_set_samplerate(runtime->rate);
295         chip->samplerate = runtime->rate;
296
297         s->period = 0;
298         s->periods = 0;
299
300         return 0;
301 }
302
303 static snd_pcm_uframes_t
304 snd_omap_alsa_pointer(struct snd_pcm_substream *substream)
305 {
306         struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
307
308         ADEBUG();
309         return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
310 }
311
312 static int snd_card_omap_alsa_open(struct snd_pcm_substream *substream)
313 {
314         struct snd_card_omap_codec *chip =
315             snd_pcm_substream_chip(substream);
316         struct snd_pcm_runtime *runtime = substream->runtime;
317         int stream_id = substream->pstr->stream;
318         int err;
319
320         ADEBUG();
321         chip->s[stream_id].stream = substream;
322         alsa_codec_config->codec_clock_on();
323         if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
324                 runtime->hw = *(alsa_codec_config->snd_omap_alsa_playback);
325         else
326                 runtime->hw = *(alsa_codec_config->snd_omap_alsa_capture);
327
328         err = snd_pcm_hw_constraint_integer(runtime,
329                                                 SNDRV_PCM_HW_PARAM_PERIODS);
330         if (err < 0)
331                 return err;
332
333         err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
334                                 alsa_codec_config->hw_constraints_rates);
335         if (err < 0)
336                 return err;
337
338         return 0;
339 }
340
341 static int snd_card_omap_alsa_close(struct snd_pcm_substream *substream)
342 {
343         struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
344
345         ADEBUG();
346         alsa_codec_config->codec_clock_off();
347         chip->s[substream->pstr->stream].stream = NULL;
348
349         return 0;
350 }
351
352 /* HW params & free */
353 static int snd_omap_alsa_hw_params(struct snd_pcm_substream *substream,
354                                         struct snd_pcm_hw_params *hw_params)
355 {
356         return snd_pcm_lib_malloc_pages(substream,
357                                         params_buffer_bytes(hw_params));
358 }
359
360 static int snd_omap_alsa_hw_free(struct snd_pcm_substream *substream)
361 {
362         return snd_pcm_lib_free_pages(substream);
363 }
364
365 /* pcm operations */
366 static struct snd_pcm_ops snd_card_omap_alsa_playback_ops = {
367         .open =         snd_card_omap_alsa_open,
368         .close =        snd_card_omap_alsa_close,
369         .ioctl =        snd_pcm_lib_ioctl,
370         .hw_params =    snd_omap_alsa_hw_params,
371         .hw_free =      snd_omap_alsa_hw_free,
372         .prepare =      snd_omap_alsa_prepare,
373         .trigger =      snd_omap_alsa_trigger,
374         .pointer =      snd_omap_alsa_pointer,
375 };
376
377 static struct snd_pcm_ops snd_card_omap_alsa_capture_ops = {
378         .open =         snd_card_omap_alsa_open,
379         .close =        snd_card_omap_alsa_close,
380         .ioctl =        snd_pcm_lib_ioctl,
381         .hw_params =    snd_omap_alsa_hw_params,
382         .hw_free =      snd_omap_alsa_hw_free,
383         .prepare =      snd_omap_alsa_prepare,
384         .trigger =      snd_omap_alsa_trigger,
385         .pointer =      snd_omap_alsa_pointer,
386 };
387
388 /*
389  *  Alsa init and exit section
390  *  Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
391  */
392 static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec *omap_alsa,
393                                         int device)
394 {
395         struct snd_pcm *pcm;
396         int err;
397
398         ADEBUG();
399         err = snd_pcm_new(omap_alsa->card, "OMAP PCM", device, 1, 1, &pcm);
400         if (err < 0)
401                 return err;
402
403         /* sets up initial buffer with continuous allocation */
404         snd_pcm_lib_preallocate_pages_for_all(pcm,
405                                               SNDRV_DMA_TYPE_CONTINUOUS,
406                                               snd_dma_continuous_data
407                                               (GFP_KERNEL),
408                                               128 * 1024, 128 * 1024);
409
410         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
411                         &snd_card_omap_alsa_playback_ops);
412         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
413                         &snd_card_omap_alsa_capture_ops);
414         pcm->private_data = omap_alsa;
415         pcm->info_flags = 0;
416         strcpy(pcm->name, "omap alsa pcm");
417
418         omap_alsa_audio_init(omap_alsa);
419
420         /* setup DMA controller */
421         audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
422                           callback_omap_alsa_sound_dma);
423         audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
424                           callback_omap_alsa_sound_dma);
425
426         omap_alsa->pcm = pcm;
427
428         return 0;
429 }
430
431
432 #ifdef CONFIG_PM
433 /*
434  * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
435  */
436 int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
437 {
438         struct snd_card_omap_codec *chip;
439         struct snd_card *card = platform_get_drvdata(pdev);
440
441         if (card->power_state != SNDRV_CTL_POWER_D3hot) {
442                 chip = card->private_data;
443                 if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
444                         snd_power_change_state(chip->card,
445                                                 SNDRV_CTL_POWER_D3hot);
446                         snd_pcm_suspend_all(chip->pcm);
447                         /* Mutes and turn clock off */
448                         alsa_codec_config->codec_clock_off();
449                         snd_omap_suspend_mixer();
450                 }
451         }
452         return 0;
453 }
454
455 int snd_omap_alsa_resume(struct platform_device *pdev)
456 {
457         struct snd_card_omap_codec *chip;
458         struct snd_card *card = platform_get_drvdata(pdev);
459
460         if (card->power_state != SNDRV_CTL_POWER_D0) {
461                 chip = card->private_data;
462                 if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
463                         snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
464                         alsa_codec_config->codec_clock_on();
465                         snd_omap_resume_mixer();
466                 }
467         }
468         return 0;
469 }
470
471 #endif  /* CONFIG_PM */
472
473 void snd_omap_alsa_free(struct snd_card *card)
474 {
475         struct snd_card_omap_codec *chip = card->private_data;
476         ADEBUG();
477
478         /*
479          * Turn off codec after it is done.
480          * Can't do it immediately, since it may still have
481          * buffered data.
482          */
483         schedule_timeout_interruptible(2);
484
485         omap_mcbsp_stop(AUDIO_MCBSP);
486         omap_mcbsp_free(AUDIO_MCBSP);
487
488         audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
489         audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
490 }
491
492 /* module init & exit */
493
494 /*
495  * Inits alsa soudcard structure.
496  * Called by the probe method in codec after function pointers has been set.
497  */
498 int snd_omap_alsa_post_probe(struct platform_device *pdev,
499                                 struct omap_alsa_codec_config *config)
500 {
501         int err = 0;
502         int def_rate;
503         struct snd_card *card;
504
505         ADEBUG();
506         alsa_codec_config       = config;
507
508         alsa_codec_config->codec_clock_setup();
509         alsa_codec_config->codec_clock_on();
510
511         omap_mcbsp_request(AUDIO_MCBSP);
512         omap_mcbsp_stop(AUDIO_MCBSP);
513         omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
514         omap_mcbsp_start(AUDIO_MCBSP);
515
516         if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
517                 alsa_codec_config->codec_configure_dev();
518
519         alsa_codec_config->codec_clock_off();
520
521         /* register the soundcard */
522         card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
523         if (card == NULL)
524                 goto nodev1;
525
526         alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
527         if (alsa_codec == NULL)
528                 goto nodev2;
529
530         card->private_data = (void *)alsa_codec;
531         card->private_free = snd_omap_alsa_free;
532
533         alsa_codec->card        = card;
534         def_rate                = alsa_codec_config->get_default_samplerate();
535         alsa_codec->samplerate  = def_rate;
536
537         spin_lock_init(&alsa_codec->s[0].dma_lock);
538         spin_lock_init(&alsa_codec->s[1].dma_lock);
539
540         /* mixer */
541         err = snd_omap_mixer(alsa_codec);
542         if (err < 0)
543                 goto nodev3;
544
545         /* PCM */
546         err = snd_card_omap_alsa_pcm(alsa_codec, 0);
547         if (err < 0)
548                 goto nodev3;
549
550         strcpy(card->driver, "OMAP_ALSA");
551         strcpy(card->shortname, alsa_codec_config->name);
552         sprintf(card->longname, alsa_codec_config->name);
553
554         snd_omap_init_mixer();
555         snd_card_set_dev(card, &pdev->dev);
556
557         err = snd_card_register(card);
558         if (err == 0) {
559                 printk(KERN_INFO "audio support initialized\n");
560                 platform_set_drvdata(pdev, card);
561                 return 0;
562         }
563
564 nodev3:
565         kfree(alsa_codec);
566 nodev2:
567         snd_card_free(card);
568 nodev1:
569         omap_mcbsp_stop(AUDIO_MCBSP);
570         omap_mcbsp_free(AUDIO_MCBSP);
571
572         return err;
573 }
574
575 int snd_omap_alsa_remove(struct platform_device *pdev)
576 {
577         struct snd_card *card = platform_get_drvdata(pdev);
578         struct snd_card_omap_codec *chip = card->private_data;
579
580         snd_card_free(card);
581
582         alsa_codec = NULL;
583         card->private_data = NULL;
584         kfree(chip);
585
586         platform_set_drvdata(pdev, NULL);
587
588         return 0;
589 }