]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - sound/arm/omap/omap-alsa.c
h63xx: tsc2101 alsa sound support
[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/driver.h>
50 #include <sound/core.h>
51
52 #include <asm/arch/omap-alsa.h>
53 #include "omap-alsa-dma.h"
54
55 MODULE_AUTHOR("Mika Laitio, Daniel Petrini, David Cohen, Anderson Briglia - INdT");
56 MODULE_LICENSE("GPL");
57 MODULE_DESCRIPTION("OMAP driver for ALSA");
58 MODULE_ALIAS("omap_alsa_mcbsp.1");
59
60 static char *id = NULL; 
61 static struct snd_card_omap_codec       *alsa_codec             = NULL;
62 static struct omap_alsa_codec_config    *alsa_codec_config      = NULL;
63
64 /*
65  * HW interface start and stop helper functions
66  */
67 static int audio_ifc_start(void)
68 {
69         omap_mcbsp_start(AUDIO_MCBSP);
70         return 0;
71 }
72
73 static int audio_ifc_stop(void)
74 {
75         omap_mcbsp_stop(AUDIO_MCBSP);
76         return 0;
77 }
78
79 static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
80 {
81         /* Setup DMA stuff */
82         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
83         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
84             SNDRV_PCM_STREAM_PLAYBACK;
85         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
86             OMAP_DMA_MCBSP1_TX;
87         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
88             audio_ifc_start;
89         omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
90             audio_ifc_stop;
91
92         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
93         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
94             SNDRV_PCM_STREAM_CAPTURE;
95         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
96             OMAP_DMA_MCBSP1_RX;
97         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
98             audio_ifc_start;
99         omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
100             audio_ifc_stop;
101 }
102
103 /* 
104  * DMA functions 
105  * Depends on omap-alsa-dma.c functions and (omap) dma.c
106  * 
107  */
108 static int audio_dma_request(struct audio_stream *s,
109                              void (*callback) (void *))
110 {
111         int err;
112         ADEBUG();
113
114         err = omap_request_alsa_sound_dma(s->dma_dev, s->id, s, &s->lch);
115         if (err < 0)
116                 printk(KERN_ERR "Unable to grab audio dma 0x%x\n", s->dma_dev);
117         return err;
118 }
119
120 static int audio_dma_free(struct audio_stream *s)
121 {
122         int err = 0;
123         ADEBUG();
124
125         err = omap_free_alsa_sound_dma(s, &s->lch);
126         if (err < 0)
127                 printk(KERN_ERR "Unable to free audio dma channels!\n");
128         return err;
129 }
130
131 /*
132  *  This function should calculate the current position of the dma in the
133  *  buffer. It will help alsa middle layer to continue update the buffer.
134  *  Its correctness is crucial for good functioning.
135  */
136 static u_int audio_get_dma_pos(struct audio_stream *s)
137 {
138         snd_pcm_substream_t *substream = s->stream;
139         snd_pcm_runtime_t *runtime = substream->runtime;
140         unsigned int offset;
141         unsigned long flags;
142         dma_addr_t count;
143         ADEBUG();
144
145         /* this must be called w/ interrupts locked as requested in dma.c */
146         spin_lock_irqsave(&s->dma_lock, flags);
147
148         /* For the current period let's see where we are */
149         count = omap_get_dma_src_addr_counter(s->lch[s->dma_q_head]);
150
151         spin_unlock_irqrestore(&s->dma_lock, flags);
152
153         /* Now, the position related to the end of that period */
154         offset = bytes_to_frames(runtime, s->offset) - bytes_to_frames(runtime, count);
155
156         if (offset >= runtime->buffer_size)
157                 offset = 0;
158
159         return offset;
160 }
161
162 /*
163  * this stops the dma and clears the dma ptrs
164  */
165 static void audio_stop_dma(struct audio_stream *s)
166 {
167         unsigned long flags;
168         ADEBUG();
169
170         spin_lock_irqsave(&s->dma_lock, flags);
171         s->active = 0;
172         s->period = 0;
173         s->periods = 0;
174
175         /* this stops the dma channel and clears the buffer ptrs */
176         omap_stop_alsa_sound_dma(s);
177
178         omap_clear_alsa_sound_dma(s);
179
180         spin_unlock_irqrestore(&s->dma_lock, flags);
181 }
182
183 /*
184  *  Main dma routine, requests dma according where you are in main alsa buffer
185  */
186 static void audio_process_dma(struct audio_stream *s)
187 {
188         snd_pcm_substream_t *substream = s->stream;
189         snd_pcm_runtime_t *runtime;
190         unsigned int dma_size;
191         unsigned int offset;
192         int ret;
193 #ifdef CONFIG_ARCH_OMAP15XX
194         unsigned long flags;
195 #endif
196         
197         ADEBUG();
198         runtime = substream->runtime;
199         if (s->active) {
200                 dma_size = frames_to_bytes(runtime, runtime->period_size);
201                 offset = dma_size * s->period;
202                 snd_assert(dma_size <= DMA_BUF_SIZE,);
203 #ifdef CONFIG_ARCH_OMAP15XX
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                 spin_lock_irqsave(&s->dma_lock, flags);
211                 omap_stop_alsa_sound_dma(s);
212                 spin_unlock_irqrestore(&s->dma_lock, flags);
213 #endif
214                 ret = omap_start_alsa_sound_dma(s,
215                                          (dma_addr_t) runtime->dma_area +
216                                          offset, dma_size);
217                 if (ret) {
218                         printk(KERN_ERR
219                                "audio_process_dma: cannot queue DMA buffer (%i)\n",
220                                ret);
221                         return;
222                 }
223
224                 s->period++;
225                 s->period %= runtime->periods;
226                 s->periods++;
227                 s->offset = offset;
228         }
229 }
230
231 /* 
232  *  This is called when dma IRQ occurs at the end of each transmited block
233  */
234 void callback_omap_alsa_sound_dma(void *data)
235 {
236         struct audio_stream *s = data;
237         
238         ADEBUG();
239         /* 
240          * If we are getting a callback for an active stream then we inform
241          * the PCM middle layer we've finished a period
242          */
243         if (s->active)
244                 snd_pcm_period_elapsed(s->stream);
245
246         spin_lock(&s->dma_lock);
247         if (s->periods > 0) 
248                 s->periods--;
249         
250         audio_process_dma(s);
251         spin_unlock(&s->dma_lock);
252 }
253
254 /* 
255  * Alsa section
256  * PCM settings and callbacks
257  */
258 static int snd_omap_alsa_trigger(snd_pcm_substream_t * substream, int cmd)
259 {
260         struct snd_card_omap_codec *chip =
261             snd_pcm_substream_chip(substream);
262         int stream_id = substream->pstr->stream;
263         struct audio_stream *s = &chip->s[stream_id];
264         int err = 0;
265         
266         ADEBUG();
267         /* note local interrupts are already disabled in the midlevel code */
268         spin_lock(&s->dma_lock);
269         switch (cmd) {
270         case SNDRV_PCM_TRIGGER_START:
271                 /* requested stream startup */
272                 s->active = 1;
273                 audio_process_dma(s);
274                 break;
275         case SNDRV_PCM_TRIGGER_STOP:
276                 /* requested stream shutdown */
277                 audio_stop_dma(s);
278                 break;
279         default:
280                 err = -EINVAL;
281                 break;
282         }
283         spin_unlock(&s->dma_lock);
284         
285         return err;
286 }
287
288 static int snd_omap_alsa_prepare(snd_pcm_substream_t * substream)
289 {
290         struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
291         snd_pcm_runtime_t *runtime = substream->runtime;
292         struct audio_stream *s = &chip->s[substream->pstr->stream];
293         
294         ADEBUG();
295         /* set requested samplerate */
296         alsa_codec_config->codec_set_samplerate(runtime->rate);
297         chip->samplerate = runtime->rate;
298
299         s->period = 0;
300         s->periods = 0;
301
302         return 0;
303 }
304
305 static snd_pcm_uframes_t snd_omap_alsa_pointer(snd_pcm_substream_t *substream)
306 {
307         struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
308
309         ADEBUG();       
310         return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
311 }
312
313 static int snd_card_omap_alsa_open(snd_pcm_substream_t * substream)
314 {
315         struct snd_card_omap_codec *chip =
316             snd_pcm_substream_chip(substream);
317         snd_pcm_runtime_t *runtime = substream->runtime;
318         int stream_id = substream->pstr->stream;
319         int err;
320         
321         ADEBUG();
322         chip->s[stream_id].stream = substream;
323         alsa_codec_config->codec_clock_on();
324         if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) 
325                 runtime->hw = *(alsa_codec_config->snd_omap_alsa_playback);
326         else 
327                 runtime->hw = *(alsa_codec_config->snd_omap_alsa_capture);
328         
329         if ((err = snd_pcm_hw_constraint_integer(runtime,
330                                            SNDRV_PCM_HW_PARAM_PERIODS)) < 0) 
331                 return err;
332         
333         if ((err = snd_pcm_hw_constraint_list(runtime,
334                                         0,
335                                         SNDRV_PCM_HW_PARAM_RATE,
336                                         alsa_codec_config->hw_constraints_rates)) < 0) 
337                 return err;
338         
339         return 0;
340 }
341
342 static int snd_card_omap_alsa_close(snd_pcm_substream_t * substream)
343 {
344         struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
345         
346         ADEBUG();
347         alsa_codec_config->codec_clock_off();
348         chip->s[substream->pstr->stream].stream = NULL;
349         
350         return 0;
351 }
352
353 /* HW params & free */
354 static int snd_omap_alsa_hw_params(snd_pcm_substream_t * substream,
355                                     snd_pcm_hw_params_t * hw_params)
356 {
357         return snd_pcm_lib_malloc_pages(substream,
358                                         params_buffer_bytes(hw_params));
359 }
360
361 static int snd_omap_alsa_hw_free(snd_pcm_substream_t * substream)
362 {
363         return snd_pcm_lib_free_pages(substream);
364 }
365
366 /* pcm operations */
367 static snd_pcm_ops_t snd_card_omap_alsa_playback_ops = {
368         .open =         snd_card_omap_alsa_open,
369         .close =        snd_card_omap_alsa_close,
370         .ioctl =        snd_pcm_lib_ioctl,
371         .hw_params =    snd_omap_alsa_hw_params,
372         .hw_free =      snd_omap_alsa_hw_free,
373         .prepare =      snd_omap_alsa_prepare,
374         .trigger =      snd_omap_alsa_trigger,
375         .pointer =      snd_omap_alsa_pointer,
376 };
377
378 static snd_pcm_ops_t snd_card_omap_alsa_capture_ops = {
379         .open =         snd_card_omap_alsa_open,
380         .close =        snd_card_omap_alsa_close,
381         .ioctl =        snd_pcm_lib_ioctl,
382         .hw_params =    snd_omap_alsa_hw_params,
383         .hw_free =      snd_omap_alsa_hw_free,
384         .prepare =      snd_omap_alsa_prepare,
385         .trigger =      snd_omap_alsa_trigger,
386         .pointer =      snd_omap_alsa_pointer,
387 };
388
389 /*
390  *  Alsa init and exit section
391  *  
392  *  Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
393  */
394 static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec *omap_alsa, 
395                                         int device)
396 {
397         snd_pcm_t *pcm;
398         int err;
399         
400         ADEBUG();
401         if ((err = snd_pcm_new(omap_alsa->card, "OMAP PCM", device, 1, 1, &pcm)) < 0)
402                 return err;
403
404         /* sets up initial buffer with continuous allocation */
405         snd_pcm_lib_preallocate_pages_for_all(pcm,
406                                               SNDRV_DMA_TYPE_CONTINUOUS,
407                                               snd_dma_continuous_data
408                                               (GFP_KERNEL),
409                                               128 * 1024, 128 * 1024);
410
411         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
412                         &snd_card_omap_alsa_playback_ops);
413         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
414                         &snd_card_omap_alsa_capture_ops);
415         pcm->private_data = omap_alsa;
416         pcm->info_flags = 0;
417         strcpy(pcm->name, "omap alsa pcm");
418
419         omap_alsa_audio_init(omap_alsa);
420
421         /* setup DMA controller */
422         audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
423                           callback_omap_alsa_sound_dma);
424         audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
425                           callback_omap_alsa_sound_dma);
426
427         omap_alsa->pcm = pcm;
428
429         return 0;
430 }
431
432
433 #ifdef CONFIG_PM
434 /*
435  * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
436  */
437 int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
438 {
439         struct snd_card_omap_codec *chip;
440         snd_card_t *card = platform_get_drvdata(pdev);
441         
442         if (card->power_state != SNDRV_CTL_POWER_D3hot) {
443                 chip = card->private_data;
444                 if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
445                         snd_power_change_state(chip->card, 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         snd_card_t *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(snd_card_t * 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, struct omap_alsa_codec_config *config)
499 {
500         int err = 0;
501         int def_rate;
502         snd_card_t *card;
503         
504         ADEBUG();
505         alsa_codec_config       = config;
506
507         alsa_codec_config->codec_clock_setup();
508         alsa_codec_config->codec_clock_on(); 
509
510         omap_mcbsp_request(AUDIO_MCBSP);
511         omap_mcbsp_stop(AUDIO_MCBSP);
512         omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
513         omap_mcbsp_start(AUDIO_MCBSP);
514         
515         if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
516                 alsa_codec_config->codec_configure_dev();
517
518         alsa_codec_config->codec_clock_off();
519
520         /* register the soundcard */
521         card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
522         if (card == NULL)
523                 goto nodev1;
524
525         alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
526         if (alsa_codec == NULL)
527                 goto nodev2;
528
529         card->private_data = (void *)alsa_codec;
530         card->private_free = snd_omap_alsa_free;
531
532         alsa_codec->card        = card;
533         def_rate                = alsa_codec_config->get_default_samplerate(); 
534         alsa_codec->samplerate  = def_rate;
535
536         spin_lock_init(&alsa_codec->s[0].dma_lock);
537         spin_lock_init(&alsa_codec->s[1].dma_lock);
538
539         /* mixer */
540         if ((err = snd_omap_mixer(alsa_codec)) < 0)
541                 goto nodev3;
542
543         /* PCM */
544         if ((err = snd_card_omap_alsa_pcm(alsa_codec, 0)) < 0)
545                 goto nodev3;
546
547         strcpy(card->driver, "OMAP_ALSA");
548         strcpy(card->shortname, alsa_codec_config->name);
549         sprintf(card->longname, alsa_codec_config->name);
550
551         snd_omap_init_mixer();
552         snd_card_set_dev(card, &pdev->dev);
553         
554         if ((err = snd_card_register(card)) == 0) {
555                 printk(KERN_INFO "audio support initialized\n");
556                 platform_set_drvdata(pdev, card);
557                 return 0;
558         }
559         
560 nodev3:
561         kfree(alsa_codec);      
562 nodev2: 
563         snd_card_free(card);
564 nodev1:
565         omap_mcbsp_stop(AUDIO_MCBSP);
566         omap_mcbsp_free(AUDIO_MCBSP);
567
568         return err;
569 }
570
571 int snd_omap_alsa_remove(struct platform_device *pdev)
572 {
573         snd_card_t *card = platform_get_drvdata(pdev);
574         struct snd_card_omap_codec *chip = card->private_data;
575         
576         snd_card_free(card);
577
578         alsa_codec = NULL;
579         card->private_data = NULL;
580         kfree(chip);
581         
582         platform_set_drvdata(pdev, NULL);
583         
584         return 0;
585 }