2 * sound/arm/omap-alsa.c
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
10 * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
12 * Based on sa11xx-uda1341.c,
13 * Copyright (C) 2002 Tomas Kasparek <tomas.kasparek@seznam.cz>
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.
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.
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.
37 * 2005-07-29 INdT Kernel Team - Alsa driver for omap osk. Creation of new
40 * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed
45 #include <linux/platform_device.h>
49 #include <sound/core.h>
50 #include <sound/pcm.h>
52 #include <asm/arch/omap-alsa.h>
53 #include "omap-alsa-dma.h"
55 MODULE_AUTHOR("Mika Laitio");
56 MODULE_AUTHOR("Daniel Petrini");
57 MODULE_AUTHOR("David Cohen");
58 MODULE_AUTHOR("Anderson Briglia");
60 MODULE_LICENSE("GPL");
61 MODULE_DESCRIPTION("OMAP driver for ALSA");
62 MODULE_ALIAS("omap_alsa_mcbsp.1");
65 static struct snd_card_omap_codec *alsa_codec;
66 static struct omap_alsa_codec_config *alsa_codec_config;
68 /* FIXME: Please change to use omap asoc framework instead, this can be racy */
69 static dma_addr_t dma_start_pos;
72 * HW interface start and stop helper functions
74 static int audio_ifc_start(void)
76 omap_mcbsp_start(AUDIO_MCBSP);
80 static int audio_ifc_stop(void)
82 omap_mcbsp_stop(AUDIO_MCBSP);
86 static void omap_alsa_audio_init(struct snd_card_omap_codec *omap_alsa)
89 omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].id = "Alsa omap out";
90 omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id =
91 SNDRV_PCM_STREAM_PLAYBACK;
92 omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev =
94 omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_start =
96 omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK].hw_stop =
99 omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].id = "Alsa omap in";
100 omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].stream_id =
101 SNDRV_PCM_STREAM_CAPTURE;
102 omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev =
104 omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_start =
106 omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE].hw_stop =
112 * Depends on omap-alsa-dma.c functions and (omap) dma.c
114 static int audio_dma_request(struct audio_stream *s,
115 void (*callback) (void *))
120 err = omap_request_alsa_sound_dma(s->dma_dev, s->id, s, &s->lch);
122 printk(KERN_ERR "Unable to grab audio dma 0x%x\n", s->dma_dev);
126 static int audio_dma_free(struct audio_stream *s)
131 err = omap_free_alsa_sound_dma(s, &s->lch);
133 printk(KERN_ERR "Unable to free audio dma channels!\n");
138 * This function should calculate the current position of the dma in the
139 * buffer. It will help alsa middle layer to continue update the buffer.
140 * Its correctness is crucial for good functioning.
142 static u_int audio_get_dma_pos(struct audio_stream *s)
144 struct snd_pcm_substream *substream = s->stream;
145 struct snd_pcm_runtime *runtime = substream->runtime;
151 /* this must be called w/ interrupts locked as requested in dma.c */
152 spin_lock_irqsave(&s->dma_lock, flags);
154 /* For the current period let's see where we are */
155 count = omap_get_dma_src_pos(s->lch[s->dma_q_head]) - dma_start_pos;
157 spin_unlock_irqrestore(&s->dma_lock, flags);
159 /* Now, the position related to the end of that period */
160 offset = bytes_to_frames(runtime, s->offset) -
161 bytes_to_frames(runtime, count);
163 if (offset >= runtime->buffer_size)
170 * this stops the dma and clears the dma ptrs
172 static void audio_stop_dma(struct audio_stream *s)
177 spin_lock_irqsave(&s->dma_lock, flags);
182 /* this stops the dma channel and clears the buffer ptrs */
183 omap_stop_alsa_sound_dma(s);
185 omap_clear_alsa_sound_dma(s);
187 spin_unlock_irqrestore(&s->dma_lock, flags);
191 * Main dma routine, requests dma according where you are in main alsa buffer
193 static void audio_process_dma(struct audio_stream *s)
195 struct snd_pcm_substream *substream = s->stream;
196 struct snd_pcm_runtime *runtime;
197 unsigned int dma_size;
202 runtime = substream->runtime;
204 dma_size = frames_to_bytes(runtime, runtime->period_size);
205 offset = dma_size * s->period;
206 snd_assert(dma_size <= DMA_BUF_SIZE, return);
208 * On omap1510 based devices, we need to call the stop_dma
209 * before calling the start_dma or we will not receive the
210 * irq from DMA after the first transfered/played buffer.
211 * (invocation of callback_omap_alsa_sound_dma() method).
213 if (cpu_is_omap1510())
214 omap_stop_alsa_sound_dma(s);
216 dma_start_pos = (dma_addr_t)runtime->dma_area + offset;
217 ret = omap_start_alsa_sound_dma(s, dma_start_pos, dma_size);
219 printk(KERN_ERR "audio_process_dma: cannot"
220 " queue DMA buffer (%i)\n", ret);
225 s->period %= runtime->periods;
232 * This is called when dma IRQ occurs at the end of each transmited block
234 void callback_omap_alsa_sound_dma(void *data)
236 struct audio_stream *s = data;
240 * If we are getting a callback for an active stream then we inform
241 * the PCM middle layer we've finished a period
244 snd_pcm_period_elapsed(s->stream);
246 spin_lock(&s->dma_lock);
250 audio_process_dma(s);
251 spin_unlock(&s->dma_lock);
256 * PCM settings and callbacks
258 static int snd_omap_alsa_trigger(struct snd_pcm_substream *substream, int cmd)
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];
267 /* note local interrupts are already disabled in the midlevel code */
268 spin_lock(&s->dma_lock);
270 case SNDRV_PCM_TRIGGER_START:
271 /* requested stream startup */
273 audio_process_dma(s);
275 case SNDRV_PCM_TRIGGER_STOP:
276 /* requested stream shutdown */
283 spin_unlock(&s->dma_lock);
288 static int snd_omap_alsa_prepare(struct snd_pcm_substream *substream)
290 struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
291 struct snd_pcm_runtime *runtime = substream->runtime;
292 struct audio_stream *s = &chip->s[substream->pstr->stream];
295 /* set requested samplerate */
296 alsa_codec_config->codec_set_samplerate(runtime->rate);
297 chip->samplerate = runtime->rate;
305 static snd_pcm_uframes_t
306 snd_omap_alsa_pointer(struct snd_pcm_substream *substream)
308 struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
311 return audio_get_dma_pos(&chip->s[substream->pstr->stream]);
314 static int snd_card_omap_alsa_open(struct snd_pcm_substream *substream)
316 struct snd_card_omap_codec *chip =
317 snd_pcm_substream_chip(substream);
318 struct snd_pcm_runtime *runtime = substream->runtime;
319 int stream_id = substream->pstr->stream;
323 chip->s[stream_id].stream = substream;
324 alsa_codec_config->codec_clock_on();
325 if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
326 runtime->hw = *(alsa_codec_config->snd_omap_alsa_playback);
328 runtime->hw = *(alsa_codec_config->snd_omap_alsa_capture);
330 err = snd_pcm_hw_constraint_integer(runtime,
331 SNDRV_PCM_HW_PARAM_PERIODS);
335 err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
336 alsa_codec_config->hw_constraints_rates);
343 static int snd_card_omap_alsa_close(struct snd_pcm_substream *substream)
345 struct snd_card_omap_codec *chip = snd_pcm_substream_chip(substream);
348 alsa_codec_config->codec_clock_off();
349 chip->s[substream->pstr->stream].stream = NULL;
354 /* HW params & free */
355 static int snd_omap_alsa_hw_params(struct snd_pcm_substream *substream,
356 struct snd_pcm_hw_params *hw_params)
358 return snd_pcm_lib_malloc_pages(substream,
359 params_buffer_bytes(hw_params));
362 static int snd_omap_alsa_hw_free(struct snd_pcm_substream *substream)
364 return snd_pcm_lib_free_pages(substream);
368 static struct snd_pcm_ops snd_card_omap_alsa_playback_ops = {
369 .open = snd_card_omap_alsa_open,
370 .close = snd_card_omap_alsa_close,
371 .ioctl = snd_pcm_lib_ioctl,
372 .hw_params = snd_omap_alsa_hw_params,
373 .hw_free = snd_omap_alsa_hw_free,
374 .prepare = snd_omap_alsa_prepare,
375 .trigger = snd_omap_alsa_trigger,
376 .pointer = snd_omap_alsa_pointer,
379 static struct snd_pcm_ops snd_card_omap_alsa_capture_ops = {
380 .open = snd_card_omap_alsa_open,
381 .close = snd_card_omap_alsa_close,
382 .ioctl = snd_pcm_lib_ioctl,
383 .hw_params = snd_omap_alsa_hw_params,
384 .hw_free = snd_omap_alsa_hw_free,
385 .prepare = snd_omap_alsa_prepare,
386 .trigger = snd_omap_alsa_trigger,
387 .pointer = snd_omap_alsa_pointer,
391 * Alsa init and exit section
392 * Inits pcm alsa structures, allocate the alsa buffer, suspend, resume
394 static int __init snd_card_omap_alsa_pcm(struct snd_card_omap_codec *omap_alsa,
401 err = snd_pcm_new(omap_alsa->card, "OMAP PCM", device, 1, 1, &pcm);
405 /* sets up initial buffer with continuous allocation */
406 snd_pcm_lib_preallocate_pages_for_all(pcm,
407 SNDRV_DMA_TYPE_CONTINUOUS,
408 snd_dma_continuous_data
410 128 * 1024, 128 * 1024);
412 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
413 &snd_card_omap_alsa_playback_ops);
414 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
415 &snd_card_omap_alsa_capture_ops);
416 pcm->private_data = omap_alsa;
418 strcpy(pcm->name, "omap alsa pcm");
420 omap_alsa_audio_init(omap_alsa);
422 /* setup DMA controller */
423 audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_PLAYBACK],
424 callback_omap_alsa_sound_dma);
425 audio_dma_request(&omap_alsa->s[SNDRV_PCM_STREAM_CAPTURE],
426 callback_omap_alsa_sound_dma);
428 omap_alsa->pcm = pcm;
436 * Driver suspend/resume - calls alsa functions. Some hints from aaci.c
438 int snd_omap_alsa_suspend(struct platform_device *pdev, pm_message_t state)
440 struct snd_card_omap_codec *chip;
441 struct snd_card *card = platform_get_drvdata(pdev);
443 if (card->power_state != SNDRV_CTL_POWER_D3hot) {
444 chip = card->private_data;
445 if (chip->card->power_state != SNDRV_CTL_POWER_D3hot) {
446 snd_power_change_state(chip->card,
447 SNDRV_CTL_POWER_D3hot);
448 snd_pcm_suspend_all(chip->pcm);
449 /* Mutes and turn clock off */
450 alsa_codec_config->codec_clock_off();
451 snd_omap_suspend_mixer();
457 int snd_omap_alsa_resume(struct platform_device *pdev)
459 struct snd_card_omap_codec *chip;
460 struct snd_card *card = platform_get_drvdata(pdev);
462 if (card->power_state != SNDRV_CTL_POWER_D0) {
463 chip = card->private_data;
464 if (chip->card->power_state != SNDRV_CTL_POWER_D0) {
465 snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0);
466 alsa_codec_config->codec_clock_on();
467 snd_omap_resume_mixer();
473 #endif /* CONFIG_PM */
475 void snd_omap_alsa_free(struct snd_card *card)
477 struct snd_card_omap_codec *chip = card->private_data;
481 * Turn off codec after it is done.
482 * Can't do it immediately, since it may still have
485 schedule_timeout_interruptible(2);
487 omap_mcbsp_stop(AUDIO_MCBSP);
488 omap_mcbsp_free(AUDIO_MCBSP);
490 audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]);
491 audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]);
494 /* module init & exit */
497 * Inits alsa soudcard structure.
498 * Called by the probe method in codec after function pointers has been set.
500 int snd_omap_alsa_post_probe(struct platform_device *pdev,
501 struct omap_alsa_codec_config *config)
505 struct snd_card *card;
508 alsa_codec_config = config;
510 alsa_codec_config->codec_clock_setup();
511 alsa_codec_config->codec_clock_on();
513 omap_mcbsp_request(AUDIO_MCBSP);
514 omap_mcbsp_stop(AUDIO_MCBSP);
515 omap_mcbsp_config(AUDIO_MCBSP, alsa_codec_config->mcbsp_regs_alsa);
516 omap_mcbsp_start(AUDIO_MCBSP);
518 if (alsa_codec_config && alsa_codec_config->codec_configure_dev)
519 alsa_codec_config->codec_configure_dev();
521 alsa_codec_config->codec_clock_off();
523 /* register the soundcard */
524 card = snd_card_new(-1, id, THIS_MODULE, sizeof(alsa_codec));
528 alsa_codec = kcalloc(1, sizeof(*alsa_codec), GFP_KERNEL);
529 if (alsa_codec == NULL)
532 card->private_data = (void *)alsa_codec;
533 card->private_free = snd_omap_alsa_free;
535 alsa_codec->card = card;
536 def_rate = alsa_codec_config->get_default_samplerate();
537 alsa_codec->samplerate = def_rate;
539 spin_lock_init(&alsa_codec->s[0].dma_lock);
540 spin_lock_init(&alsa_codec->s[1].dma_lock);
543 err = snd_omap_mixer(alsa_codec);
548 err = snd_card_omap_alsa_pcm(alsa_codec, 0);
552 strcpy(card->driver, "OMAP_ALSA");
553 strcpy(card->shortname, alsa_codec_config->name);
554 sprintf(card->longname, alsa_codec_config->name);
556 snd_omap_init_mixer();
557 snd_card_set_dev(card, &pdev->dev);
559 err = snd_card_register(card);
561 printk(KERN_INFO "audio support initialized\n");
562 platform_set_drvdata(pdev, card);
571 omap_mcbsp_stop(AUDIO_MCBSP);
572 omap_mcbsp_free(AUDIO_MCBSP);
577 int snd_omap_alsa_remove(struct platform_device *pdev)
579 struct snd_card *card = platform_get_drvdata(pdev);
580 struct snd_card_omap_codec *chip = card->private_data;
585 card->private_data = NULL;
588 platform_set_drvdata(pdev, NULL);