2 * sound/arm/omap/omap-alsa-dma.c
4 * Common audio DMA handling for the OMAP processors
6 * Copyright (C) 2006 Mika Laitio <lamikr@cc.jyu.fi>
8 * Copyright (C) 2005 Instituto Nokia de Tecnologia - INdT - Manaus Brazil
10 * Copyright (C) 2004 Texas Instruments, Inc.
12 * Copyright (C) 2000, 2001 Nicolas Pitre <nico@cam.org>
14 * This package 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.
18 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
20 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
24 * 2004-06-07 Sriram Kannan - Created new file from omap_audio_dma_intfc.c.
25 * This file will contain only the DMA interface
26 * and buffer handling of OMAP audio driver.
28 * 2004-06-22 Sriram Kannan - removed legacy code (auto-init). Self-linking
29 * of DMA logical channel.
31 * 2004-08-12 Nishanth Menon - Modified to integrate Audio requirements on
32 * 1610, 1710 platforms
34 * 2004-11-01 Nishanth Menon - 16xx platform code base modified to support
35 * multi channel chaining.
37 * 2004-12-15 Nishanth Menon - Improved 16xx platform channel logic
38 * introduced - tasklets, queue handling updated
40 * 2005-07-19 INdT Kernel Team - Alsa port. Creation of new file
41 * omap-alsa-dma.c based in omap-audio-dma-intfc.c
42 * oss file. Support for aic23 codec. Removal of
43 * buffer handling (Alsa does that), modifications
44 * in dma handling and port to alsa structures.
46 * 2005-12-18 Dirk Behme - Added L/R Channel Interchange fix as proposed
50 #include <linux/module.h>
51 #include <linux/init.h>
52 #include <linux/types.h>
55 #include <linux/slab.h>
56 #include <linux/sched.h>
57 #include <linux/poll.h>
59 #include <linux/errno.h>
60 #include <linux/sound.h>
61 #include <linux/soundcard.h>
62 #include <linux/sysrq.h>
63 #include <linux/interrupt.h>
64 #include <linux/dma-mapping.h>
66 #include <linux/uaccess.h>
68 #include <asm/hardware.h>
69 #include <asm/semaphore.h>
70 #include <asm/arch/dma.h>
71 #include <asm/arch/mcbsp.h>
72 #include <asm/arch/omap-alsa.h>
74 #include "omap-alsa-dma.h"
79 * Channel Queue Handling macros
80 * tail always points to the current free entry
81 * Head always points to the current entry being used
82 * end is either head or tail
85 #define AUDIO_QUEUE_INIT(s) s->dma_q_head = s->dma_q_tail = s->dma_q_count = 0;
86 #define AUDIO_QUEUE_FULL(s) (nr_linked_channels == s->dma_q_count)
87 #define AUDIO_QUEUE_LAST(s) (1 == s->dma_q_count)
88 #define AUDIO_QUEUE_EMPTY(s) (0 == s->dma_q_count)
89 #define __AUDIO_INCREMENT_QUEUE(end) ((end) = ((end)+1) % nr_linked_channels)
90 #define AUDIO_INCREMENT_HEAD(s) \
92 __AUDIO_INCREMENT_QUEUE(s->dma_q_head); \
95 #define AUDIO_INCREMENT_TAIL(s) \
97 __AUDIO_INCREMENT_QUEUE(s->dma_q_tail); \
101 /* DMA buffer fragmentation sizes */
102 #define MAX_DMA_SIZE 0x1000000 /* todo: sync with alsa */
103 /* #define CUT_DMA_SIZE 0x1000 */
104 /* TODO: To be moved to more appropriate location */
105 #define DCSR_ERROR 0x3
106 #define DCSR_END_BLOCK (1 << 5)
107 #define DCSR_SYNC_SET (1 << 6)
109 #define DCCR_FS (1 << 5)
110 #define DCCR_PRIO (1 << 6)
111 #define DCCR_EN (1 << 7)
112 #define DCCR_AI (1 << 8)
113 #define DCCR_REPEAT (1 << 9)
114 /* if 0 the channel works in 3.1 compatible mode */
115 #define DCCR_N31COMP (1 << 10)
116 #define DCCR_EP (1 << 11)
117 #define DCCR_SRC_AMODE_BIT 12
118 #define DCCR_SRC_AMODE_MASK (0x3<<12)
119 #define DCCR_DST_AMODE_BIT 14
120 #define DCCR_DST_AMODE_MASK (0x3<<14)
121 #define AMODE_CONST 0x0
122 #define AMODE_POST_INC 0x1
123 #define AMODE_SINGLE_INDEX 0x2
124 #define AMODE_DOUBLE_INDEX 0x3
126 /* Data structures */
127 DEFINE_SPINLOCK(dma_list_lock);
128 static char nr_linked_channels = 1;
130 /* Module specific functions */
132 static void sound_dma_irq_handler(int lch, u16 ch_status, void *data);
133 static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
135 static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
137 static int audio_start_dma_chain(struct audio_stream *s);
140 * DMA channel requests
142 static void omap_sound_dma_link_lch(void *data)
145 struct audio_stream *s = (struct audio_stream *) data;
154 for (i = 0; i < nr_linked_channels; i++) {
155 int cur_chan = chan[i];
157 ((nr_linked_channels - 1 ==
158 i) ? chan[0] : chan[i + 1]);
159 omap_dma_link_lch(cur_chan, nex_chan);
165 int omap_request_alsa_sound_dma(int device_id, const char *device_name,
166 void *data, int **channels)
171 if (unlikely((NULL == channels) || (NULL == device_name))) {
175 /* Try allocate memory for the num channels */
176 *channels = kmalloc(sizeof(int) * nr_linked_channels, GFP_KERNEL);
179 ERR("No Memory for channel allocs!\n");
183 spin_lock(&dma_list_lock);
184 for (i = 0; i < nr_linked_channels; i++) {
185 err = omap_request_dma(device_id,
187 sound_dma_irq_handler,
191 /* Handle Failure condition here */
195 for (j = 0; j < i; j++)
196 omap_free_dma(chan[j]);
198 spin_unlock(&dma_list_lock);
201 ERR("Error in requesting channel %d=0x%x\n", i,
208 /* Chain the channels together */
209 if (!cpu_is_omap15xx())
210 omap_sound_dma_link_lch(data);
212 spin_unlock(&dma_list_lock);
216 EXPORT_SYMBOL(omap_request_alsa_sound_dma);
219 * DMA channel requests Freeing
221 static void omap_sound_dma_unlink_lch(void *data)
223 struct audio_stream *s = (struct audio_stream *)data;
232 for (i = 0; i < nr_linked_channels; i++) {
233 int cur_chan = chan[i];
235 ((nr_linked_channels - 1 ==
236 i) ? chan[0] : chan[i + 1]);
237 omap_dma_unlink_lch(cur_chan, nex_chan);
243 int omap_free_alsa_sound_dma(void *data, int **channels)
249 if (unlikely(NULL == channels)) {
253 if (unlikely(NULL == *channels)) {
259 if (!cpu_is_omap15xx())
260 omap_sound_dma_unlink_lch(data);
261 for (i = 0; i < nr_linked_channels; i++) {
262 int cur_chan = chan[i];
263 omap_stop_dma(cur_chan);
264 omap_free_dma(cur_chan);
271 EXPORT_SYMBOL(omap_free_alsa_sound_dma);
274 * Stop all the DMA channels of the stream
276 void omap_stop_alsa_sound_dma(struct audio_stream *s)
282 if (unlikely(NULL == chan)) {
286 for (i = 0; i < nr_linked_channels; i++) {
287 int cur_chan = chan[i];
288 omap_stop_dma(cur_chan);
294 EXPORT_SYMBOL(omap_stop_alsa_sound_dma);
297 * Clear any pending transfers
299 void omap_clear_alsa_sound_dma(struct audio_stream *s)
302 omap_clear_dma(s->lch[s->dma_q_head]);
306 EXPORT_SYMBOL(omap_clear_alsa_sound_dma);
309 * DMA related functions
311 static int audio_set_dma_params_play(int channel, dma_addr_t dma_ptr,
314 int dt = 0x1; /* data type 16 */
315 int cen = 32; /* Stereo */
316 int cfn = dma_size / (2 * cen);
319 omap_set_dma_dest_params(channel, 0x05, 0x00,
320 (OMAP1510_MCBSP1_BASE + 0x06),
322 omap_set_dma_src_params(channel, 0x00, 0x01, dma_ptr,
324 omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
329 static int audio_set_dma_params_capture(int channel, dma_addr_t dma_ptr,
332 int dt = 0x1; /* data type 16 */
333 int cen = 32; /* stereo */
334 int cfn = dma_size / (2 * cen);
337 omap_set_dma_src_params(channel, 0x05, 0x00,
338 (OMAP1510_MCBSP1_BASE + 0x02),
340 omap_set_dma_dest_params(channel, 0x00, 0x01, dma_ptr, 0, 0);
341 omap_set_dma_transfer_params(channel, dt, cen, cfn, 0x00, 0, 0);
346 static int audio_start_dma_chain(struct audio_stream *s)
348 int channel = s->lch[s->dma_q_head];
351 s->hw_stop(); /* stops McBSP Interface */
352 omap_start_dma(channel);
354 s->hw_start(); /* start McBSP interface */
355 } else if (cpu_is_omap310())
356 omap_start_dma(channel);
357 /* else the dma itself will progress forward with out our help */
364 * Do the initial set of work to initialize all the channels as required.
365 * We shall then initate a transfer
367 int omap_start_alsa_sound_dma(struct audio_stream *s,
375 if (unlikely(dma_size > MAX_DMA_SIZE)) {
376 ERR("DmaSoundDma: Start: overflowed %d-%d\n", dma_size,
381 if (s->stream_id == SNDRV_PCM_STREAM_PLAYBACK) {
384 audio_set_dma_params_play(s->lch[s->dma_q_tail],
388 audio_set_dma_params_capture(s->lch[s->dma_q_tail],
392 ret = -3; /* indicate queue full */
395 AUDIO_INCREMENT_TAIL(s);
396 ret = audio_start_dma_chain(s);
398 ERR("dma start failed");
405 EXPORT_SYMBOL(omap_start_alsa_sound_dma);
408 * ISRs have to be short and smart..
409 * Here we call alsa handling, after some error checking
411 static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status,
414 int dma_status = ch_status;
415 struct audio_stream *s = (struct audio_stream *) data;
418 /* some register checking */
419 DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n",
420 sound_curr_lch, ch_status, dma_status, data);
422 if (dma_status & (DCSR_ERROR)) {
423 OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
424 ERR("DCSR_ERROR!\n");
429 if (ch_status & DCSR_END_BLOCK)
430 callback_omap_alsa_sound_dma(s);
435 MODULE_AUTHOR("Texas Instruments");
436 MODULE_DESCRIPTION("Common DMA handling for Audio driver on OMAP processors");
437 MODULE_LICENSE("GPL");