FS#11335 by me: make ARM assembly functions thumb-friendly
[kugel-rb.git] / firmware / target / arm / pcm-pp.c
blobbffc69f771a4d099dd37151187929c8e5a5ebbe0
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Michael Sevakis
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include <stdlib.h>
22 #include "system.h"
23 #include "kernel.h"
24 #include "logf.h"
25 #include "audio.h"
26 #include "sound.h"
27 #include "pcm.h"
28 #include "pcm_sampr.h"
30 /** DMA **/
32 #ifdef CPU_PP502x
33 /* 16-bit, L-R packed into 32 bits with left in the least significant halfword */
34 #define SAMPLE_SIZE 16
35 /* DMA Requests from IIS, Memory to peripheral, single transfer,
36 wait for DMA request, interrupt on complete */
37 #define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \
38 DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
39 DMA_CMD_WAIT_REQ | DMA_CMD_INTR)
40 /* DMA status cannot be viewed from outside code in control because that can
41 * clear the interrupt from outside the handler and prevent the handler from
42 * from being called. Split up transfers to a reasonable size that is good as
43 * a timer, obtaining a keyclick position and peaking yet still keeps the
44 * FIQ count low.
46 #define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */
47 #else
48 /* 32-bit, one left 32-bit sample followed by one right 32-bit sample */
49 #define SAMPLE_SIZE 32
50 #endif
52 struct dma_data
54 /* NOTE: The order of size and p is important if you use assembler
55 optimised fiq handler, so don't change it. */
56 union
58 unsigned long addr;
59 uint32_t *p16; /* For packed 16-16 stereo pairs */
60 uint16_t *p32; /* For individual samples converted to 32-bit */
62 size_t size;
63 #if NUM_CORES > 1
64 unsigned core;
65 #endif
66 int locked;
67 int state;
70 extern void *fiq_function;
72 /* Dispatch to the proper handler and leave the main vector table alone */
73 void fiq_handler(void) ICODE_ATTR __attribute__((naked));
74 void fiq_handler(void)
76 asm volatile (
77 #if ARM_ARCH == 4 && defined(USE_THUMB)
78 "ldr r12, [pc, #-4] \n"
79 "bx r12 \n"
80 #else
81 "ldr pc, [pc, #-4] \n"
82 #endif
83 "fiq_function: \n"
84 ".word 0 \n"
88 #ifdef HAVE_PCM_DMA_ADDRESS
89 void * pcm_dma_addr(void *addr)
91 if (addr != NULL && (unsigned long)addr < UNCACHED_BASE_ADDR)
92 addr = UNCACHED_ADDR(addr);
93 return addr;
95 #endif
97 /* TODO: Get simultaneous recording and playback to work. Just needs some tweaking */
99 /****************************************************************************
100 ** Playback DMA transfer
102 static struct dma_data dma_play_data IBSS_ATTR =
104 /* Initialize to a locked, stopped state */
105 { .addr = 0 },
106 .size = 0,
107 #if NUM_CORES > 1
108 .core = 0x00,
109 #endif
110 .locked = 0,
111 .state = 0
114 void pcm_dma_apply_settings(void)
116 audiohw_set_frequency(pcm_fsel);
119 #if defined(CPU_PP502x)
120 /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
121 void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
123 register size_t size;
125 DMA0_STATUS; /* Clear any pending interrupt */
127 size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this
128 interrupt */
129 dma_play_data.addr += size;
130 dma_play_data.size -= size;
132 while (1)
134 if (dma_play_data.size > 0) {
135 size = MAX_DMA_CHUNK_SIZE;
136 /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less
137 * than a FIFO's worth of data after this transfer? */
138 if (size + 16*4 > dma_play_data.size)
139 size = dma_play_data.size;
141 /* Set the new DMA values and activate channel */
142 DMA0_RAM_ADDR = dma_play_data.addr;
143 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
144 return;
147 /* Buffer empty. Try to get more. */
148 pcm_play_get_more_callback((void **)&dma_play_data.addr,
149 &dma_play_data.size);
151 if (dma_play_data.size == 0) {
152 /* No more data */
153 return;
156 if (dma_play_data.addr < UNCACHED_BASE_ADDR) {
157 /* Flush any pending cache writes */
158 dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr);
159 cpucache_flush();
163 #else
164 /* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by
165 * evalutation of free IISFIFO-slots against available source buffer words.
166 * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside
167 * the loop and do some further optimization. Right after the loops (source
168 * buffer -> IISFIFO) are done we need to check whether we have to exit FIQ
169 * handler (this must be done, if all free FIFO slots were filled) or we will
170 * have to get some new source data. Important information kept from former
171 * ASM implementation (not used anymore): GCC fails to make use of the fact
172 * that FIQ mode has registers r8-r14 banked, and so does not need to be saved.
173 * This routine uses only these registers, and so will never touch the stack
174 * unless it actually needs to do so when calling pcm_callback_for_more.
175 * C version is still included below for reference and testing.
177 #if 1
178 void fiq_playback(void) ICODE_ATTR __attribute__((naked));
179 void fiq_playback(void)
181 /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual
182 * FIQ handler. r11 contains address of p (also set in crt0.S). Most other
183 * addresses we need are generated by using offsets with these two.
184 * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG.
185 * r8 and r9 contains local copies of p and size respectively.
186 * r0-r3 and r12 is a working register.
188 asm volatile (
189 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */
191 #if CONFIG_CPU == PP5002
192 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */
193 "ldr r12, [r12] \n"
194 #endif
195 "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */
196 "cmp r9, #0 \n" /* is size 0? */
197 "beq .more_data \n" /* if so, ask pcmbuf for more data */
199 #if SAMPLE_SIZE == 16
200 ".check_fifo: \n"
201 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
202 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 16 (PP502x) */
204 "mov r1, r0, lsr #16 \n" /* number of free FIFO slots */
205 "cmp r1, r9, lsr #2 \n" /* number of words from source */
206 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
207 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
209 "subs r1, r1, #2 \n"
210 ".fifo_loop_2: \n"
211 "ldmgeia r8!, {r2, r12} \n" /* load four samples */
212 "strge r2 , [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
213 "strge r12, [r10, %[wr]] \n" /* write sample 2-3 to IISFIFO_WR */
214 "subges r1, r1, #2 \n" /* one more loop? */
215 "bge .fifo_loop_2 \n" /* yes, continue */
217 "tst r1, #1 \n" /* two samples (one word) left? */
218 "ldrne r12, [r8], #4 \n" /* load two samples */
219 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
221 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
222 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
223 #elif SAMPLE_SIZE == 32
224 ".check_fifo: \n"
225 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
226 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */
228 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */
229 "beq .exit \n" /* no complete pair? -> exit */
230 "cmp r1, r9, lsr #2 \n" /* number of words from source */
231 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
232 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
234 ".fifo_loop: \n"
235 "ldr r12, [r8], #4 \n" /* load two samples */
236 "mov r2 , r12, lsl #16 \n" /* put left sample at the top bits */
237 "str r2 , [r10, %[wr]] \n" /* write top sample to IISFIFO_WR */
238 "str r12, [r10, %[wr]] \n" /* write low sample to IISFIFO_WR*/
239 "subs r1, r1, #1 \n" /* one more loop? */
240 "bgt .fifo_loop \n" /* yes, continue */
242 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
243 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
244 #endif
246 ".more_data: \n"
247 "ldr r2, =pcm_play_get_more_callback \n"
248 "mov r0, r11 \n" /* r0 = &p */
249 "add r1, r11, #4 \n" /* r1 = &size */
250 "mov lr, pc \n" /* call pcm_play_get_more_callback */
251 "bx r2 \n"
252 "ldmia r11, { r8-r9 } \n" /* load new p and size */
253 "cmp r9, #0 \n"
254 "bne .check_fifo \n" /* size != 0? refill */
256 ".exit: \n" /* (r9=0 if stopping, look above) */
257 "stmia r11, { r8-r9 } \n" /* save p and size */
258 "ldmfd sp!, { r0-r3, lr } \n"
259 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
260 ".ltorg \n"
261 : /* These must only be integers! No regs */
262 : [mask]"i"(IIS_TX_FREE_MASK),
263 [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG),
264 [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG)
267 #else /* C version for reference */
268 void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR;
269 /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
270 void fiq_playback(void)
272 #if CONFIG_CPU == PP5002
273 inl(0xcf001040);
274 #endif
276 do {
277 while (dma_play_data.size > 0) {
278 if (IIS_TX_FREE_COUNT < 2) {
279 return;
281 #if SAMPLE_SIZE == 16
282 IISFIFO_WR = *dma_play_data.p16++;
283 #elif SAMPLE_SIZE == 32
284 IISFIFO_WR = *dma_play_data.p32++ << 16;
285 IISFIFO_WR = *dma_play_data.p32++ << 16;
286 #endif
287 dma_play_data.size -= 4;
290 /* p is empty, get some more data */
291 pcm_play_get_more_callback((void **)&dma_play_data.addr,
292 &dma_play_data.size);
293 } while (dma_play_data.size);
295 /* No more data */
297 #endif /* ASM / C selection */
298 #endif /* CPU_PP502x */
300 /* For the locks, FIQ must be disabled because the handler manipulates
301 IISCONFIG and the operation is not atomic - dual core support
302 will require other measures */
303 void pcm_play_lock(void)
305 int status = disable_fiq_save();
307 if (++dma_play_data.locked == 1) {
308 #ifdef CPU_PP502x
309 CPU_INT_DIS = DMA_MASK;
310 #else
311 IIS_IRQTX_REG &= ~IIS_IRQTX;
312 #endif
315 restore_fiq(status);
318 void pcm_play_unlock(void)
320 int status = disable_fiq_save();
322 if (--dma_play_data.locked == 0 && dma_play_data.state != 0) {
323 #ifdef CPU_PP502x
324 CPU_INT_EN = DMA_MASK;
325 #else
326 IIS_IRQTX_REG |= IIS_IRQTX;
327 #endif
330 restore_fiq(status);
333 static void play_start_pcm(void)
335 fiq_function = fiq_playback;
337 #ifdef CPU_PP502x
338 /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less than a
339 * FIFO's worth of data after this transfer? */
340 size_t size = MAX_DMA_CHUNK_SIZE;
341 if (size + 16*4 > dma_play_data.size)
342 size = dma_play_data.size;
344 DMA0_RAM_ADDR = dma_play_data.addr;
345 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
346 dma_play_data.state = 1;
347 #else
348 IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */
350 /* Fill the FIFO or start when data is used up */
351 while (1) {
352 if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) {
353 IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */
354 dma_play_data.state = 1;
355 return;
358 #if SAMPLE_SIZE == 16
359 IISFIFO_WR = *dma_play_data.p16++;
360 #elif SAMPLE_SIZE == 32
361 IISFIFO_WR = *dma_play_data.p32++ << 16;
362 IISFIFO_WR = *dma_play_data.p32++ << 16;
363 #endif
364 dma_play_data.size -= 4;
366 #endif
369 static void play_stop_pcm(void)
371 #ifdef CPU_PP502x
372 unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */
373 unsigned long cmd = DMA0_CMD;
374 size_t size = 0;
376 /* Stop transfer */
377 DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR);
379 /* Wait for not busy + clear int */
380 while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR));
382 if (status & DMA_STATUS_BUSY) {
383 /* Transfer was interrupted - leave what's left */
384 size = (cmd & 0xfffc) - (status & 0xfffc);
386 else if (status & DMA_STATUS_INTR) {
387 /* Transfer was finished - DMA0_STATUS will have been reloaded
388 * automatically with size in DMA0_CMD. Setup to restart on next
389 * segment. */
390 size = (cmd & 0xfffc) + 4;
392 /* else not an active state - size = 0 */
394 dma_play_data.addr += size;
395 dma_play_data.size -= size;
397 if (dma_play_data.size == 0)
398 dma_play_data.addr = 0; /* Entire buffer has completed. */
399 #else
400 /* Disable TX interrupt */
401 IIS_IRQTX_REG &= ~IIS_IRQTX;
402 #endif
404 /* Wait for FIFO to empty */
405 while (!IIS_TX_IS_EMPTY);
407 dma_play_data.state = 0;
410 void pcm_play_dma_start(const void *addr, size_t size)
412 #if NUM_CORES > 1
413 /* This will become more important later - and different ! */
414 dma_play_data.core = processor_id(); /* save initiating core */
415 #endif
417 pcm_play_dma_stop();
419 #ifdef CPU_PP502x
420 if ((unsigned long)addr < UNCACHED_BASE_ADDR) {
421 /* Flush any pending cache writes */
422 addr = UNCACHED_ADDR(addr);
423 cpucache_flush();
426 dma_play_data.addr = (unsigned long)addr;
427 dma_play_data.size = size;
428 DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR;
429 DMA0_FLAGS = DMA_FLAGS_UNK26;
430 DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT;
431 #else
432 dma_play_data.addr = (unsigned long)addr;
433 dma_play_data.size = size;
434 #endif
436 play_start_pcm();
439 /* Stops the DMA transfer and interrupt */
440 void pcm_play_dma_stop(void)
442 play_stop_pcm();
443 dma_play_data.addr = 0;
444 dma_play_data.size = 0;
445 #if NUM_CORES > 1
446 dma_play_data.core = 0; /* no core in control */
447 #endif
450 void pcm_play_dma_pause(bool pause)
452 if (pause) {
453 play_stop_pcm();
454 } else {
455 play_start_pcm();
459 size_t pcm_get_bytes_waiting(void)
461 return dma_play_data.size & ~3;
464 void pcm_play_dma_init(void)
466 /* Initialize default register values. */
467 audiohw_init();
469 #ifdef CPU_PP502x
470 /* Enable DMA controller */
471 DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN;
472 /* FIQ priority for DMA */
473 CPU_INT_PRIORITY |= DMA_MASK;
474 /* Enable request?? Not setting or clearing everything doesn't seem to
475 * prevent it operating. Perhaps important for reliability (how requests
476 * are handled). */
477 DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS;
478 DMA0_STATUS;
479 #else
480 /* Set up banked registers for FIQ mode */
482 /* Use non-banked registers for scratch. */
483 register volatile void *iiscfg asm("r0") = &IISCONFIG;
484 register volatile void *dmapd asm("r1") = &dma_play_data;
486 asm volatile (
487 "mrs r2, cpsr \n" /* Save mode and interrupt status */
488 "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */
489 "mov r8, #0 \n"
490 "mov r9, #0 \n"
491 "mov r10, %[iiscfg] \n"
492 "mov r11, %[dmapd] \n"
493 "msr cpsr_c, r2 \n"
495 : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd)
496 : "r2");
498 /* FIQ priority for I2S */
499 CPU_INT_PRIORITY |= IIS_MASK;
500 CPU_INT_EN = IIS_MASK;
501 #endif
503 IISCONFIG |= IIS_TXFIFOEN;
506 void pcm_postinit(void)
508 audiohw_postinit();
511 const void * pcm_play_dma_get_peak_buffer(int *count)
513 unsigned long addr, size;
515 int status = disable_fiq_save();
516 addr = dma_play_data.addr;
517 size = dma_play_data.size;
518 restore_fiq(status);
520 *count = size >> 2;
521 return (void *)((addr + 2) & ~3);
524 /****************************************************************************
525 ** Recording DMA transfer
527 #ifdef HAVE_RECORDING
528 /* PCM recording interrupt routine lockout */
529 static struct dma_data dma_rec_data IBSS_ATTR =
531 /* Initialize to a locked, stopped state */
532 { .addr = 0 },
533 .size = 0,
534 #if NUM_CORES > 1
535 .core = 0x00,
536 #endif
537 .locked = 0,
538 .state = 0
541 /* For the locks, FIQ must be disabled because the handler manipulates
542 IISCONFIG and the operation is not atomic - dual core support
543 will require other measures */
544 void pcm_rec_lock(void)
546 int status = disable_fiq_save();
548 if (++dma_rec_data.locked == 1)
549 IIS_IRQRX_REG &= ~IIS_IRQRX;
551 restore_fiq(status);
554 void pcm_rec_unlock(void)
556 int status = disable_fiq_save();
558 if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0)
559 IIS_IRQRX_REG |= IIS_IRQRX;
561 restore_fiq(status);
564 /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
565 void fiq_record(void) ICODE_ATTR __attribute__((interrupt ("FIQ")));
567 #if defined(SANSA_C200) || defined(SANSA_E200)
568 void fiq_record(void)
570 register int32_t value;
572 if (audio_channels == 2) {
573 /* RX is stereo */
574 while (dma_rec_data.size > 0) {
575 if (IIS_RX_FULL_COUNT < 2) {
576 return;
579 /* Discard every other sample since ADC clock is 1/2 LRCK */
580 value = IISFIFO_RD;
581 IISFIFO_RD;
583 *dma_rec_data.p16++ = value;
584 dma_rec_data.size -= 4;
586 /* TODO: Figure out how to do IIS loopback */
587 if (audio_output_source != AUDIO_SRC_PLAYBACK) {
588 if (IIS_TX_FREE_COUNT >= 16) {
589 /* Resync the output FIFO - it ran dry */
590 IISFIFO_WR = 0;
591 IISFIFO_WR = 0;
593 IISFIFO_WR = value;
594 IISFIFO_WR = value;
598 else {
599 /* RX is left channel mono */
600 while (dma_rec_data.size > 0) {
601 if (IIS_RX_FULL_COUNT < 2) {
602 return;
605 /* Discard every other sample since ADC clock is 1/2 LRCK */
606 value = IISFIFO_RD;
607 IISFIFO_RD;
609 value = (uint16_t)value | (value << 16);
611 *dma_rec_data.p16++ = value;
612 dma_rec_data.size -= 4;
614 if (audio_output_source != AUDIO_SRC_PLAYBACK) {
615 if (IIS_TX_FREE_COUNT >= 16) {
616 /* Resync the output FIFO - it ran dry */
617 IISFIFO_WR = 0;
618 IISFIFO_WR = 0;
621 value = *((int32_t *)dma_rec_data.p16 - 1);
622 IISFIFO_WR = value;
623 IISFIFO_WR = value;
628 pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr,
629 &dma_rec_data.size);
632 #else
633 void fiq_record(void)
635 while (dma_rec_data.size > 0) {
636 if (IIS_RX_FULL_COUNT < 2) {
637 return;
640 #if SAMPLE_SIZE == 16
641 *dma_rec_data.p16++ = IISFIFO_RD;
642 #elif SAMPLE_SIZE == 32
643 *dma_rec_data.p32++ = IISFIFO_RD >> 16;
644 *dma_rec_data.p32++ = IISFIFO_RD >> 16;
645 #endif
646 dma_rec_data.size -= 4;
649 pcm_rec_more_ready_callback(0, (void *)&dma_rec_data.addr,
650 &dma_rec_data.size);
653 #endif /* SANSA_E200 */
655 void pcm_rec_dma_stop(void)
657 /* disable interrupt */
658 IIS_IRQRX_REG &= ~IIS_IRQRX;
660 dma_rec_data.state = 0;
661 dma_rec_data.size = 0;
662 #if NUM_CORES > 1
663 dma_rec_data.core = 0x00;
664 #endif
666 /* disable fifo */
667 IISCONFIG &= ~IIS_RXFIFOEN;
668 IISFIFO_CFG |= IIS_RXCLR;
671 void pcm_rec_dma_start(void *addr, size_t size)
673 pcm_rec_dma_stop();
675 dma_rec_data.addr = (unsigned long)addr;
676 dma_rec_data.size = size;
677 #if NUM_CORES > 1
678 /* This will become more important later - and different ! */
679 dma_rec_data.core = processor_id(); /* save initiating core */
680 #endif
681 /* setup FIQ handler */
682 fiq_function = fiq_record;
684 /* interrupt on full fifo, enable record fifo interrupt */
685 dma_rec_data.state = 1;
687 /* enable RX FIFO */
688 IISCONFIG |= IIS_RXFIFOEN;
690 /* enable IIS interrupt as FIQ */
691 CPU_INT_PRIORITY |= IIS_MASK;
692 CPU_INT_EN = IIS_MASK;
695 void pcm_rec_dma_close(void)
697 pcm_rec_dma_stop();
698 } /* pcm_close_recording */
700 void pcm_rec_dma_init(void)
702 pcm_rec_dma_stop();
703 } /* pcm_init */
705 const void * pcm_rec_dma_get_peak_buffer(void)
707 return (void *)((unsigned long)dma_rec_data.addr & ~3);
708 } /* pcm_rec_dma_get_peak_buffer */
710 #endif /* HAVE_RECORDING */