Fuzev2: Preliminary button support. Scrollwheel does not work yet.
[kugel-rb.git] / firmware / target / arm / pcm-pp.c
blobbd12b13032cafbc2a7d11fa72cff6729839bde57
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 "ldr pc, [pc, #-4] \n"
78 "fiq_function: \n"
79 ".word 0 \n"
83 #ifdef HAVE_PCM_DMA_ADDRESS
84 void * pcm_dma_addr(void *addr)
86 if (addr != NULL && (unsigned long)addr < UNCACHED_BASE_ADDR)
87 addr = UNCACHED_ADDR(addr);
88 return addr;
90 #endif
92 /* TODO: Get simultaneous recording and playback to work. Just needs some tweaking */
94 /****************************************************************************
95 ** Playback DMA transfer
96 **/
97 static struct dma_data dma_play_data IBSS_ATTR =
99 /* Initialize to a locked, stopped state */
100 { .addr = 0 },
101 .size = 0,
102 #if NUM_CORES > 1
103 .core = 0x00,
104 #endif
105 .locked = 0,
106 .state = 0
109 void pcm_dma_apply_settings(void)
111 audiohw_set_frequency(pcm_fsel);
114 #if defined(CPU_PP502x)
115 /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
116 void ICODE_ATTR __attribute__((interrupt("FIQ"))) fiq_playback(void)
118 register pcm_more_callback_type get_more;
119 register size_t size;
121 DMA0_STATUS; /* Clear any pending interrupt */
123 size = (DMA0_CMD & 0xffff) + 4; /* Get size of trasfer that caused this
124 interrupt */
125 dma_play_data.addr += size;
126 dma_play_data.size -= size;
128 while (1)
130 if (dma_play_data.size > 0) {
131 size = MAX_DMA_CHUNK_SIZE;
132 /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less
133 * than a FIFO's worth of data after this transfer? */
134 if (size + 16*4 > dma_play_data.size)
135 size = dma_play_data.size;
137 /* Set the new DMA values and activate channel */
138 DMA0_RAM_ADDR = dma_play_data.addr;
139 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
140 return;
143 /* Buffer empty. Try to get more. */
144 get_more = pcm_callback_for_more;
145 if (get_more) {
146 get_more((unsigned char **)&dma_play_data.addr, &dma_play_data.size);
147 dma_play_data.addr = (dma_play_data.addr + 2) & ~3;
148 dma_play_data.size &= ~3;
151 if (dma_play_data.size == 0) {
152 break;
155 if (dma_play_data.addr < UNCACHED_BASE_ADDR) {
156 /* Flush any pending cache writes */
157 dma_play_data.addr = UNCACHED_ADDR(dma_play_data.addr);
158 cpucache_flush();
162 /* Callback missing or no more DMA to do */
163 pcm_play_dma_stop();
164 pcm_play_dma_stopped_callback();
166 #else
167 /* ASM optimised FIQ handler. Checks for the minimum allowed loop cycles by
168 * evalutation of free IISFIFO-slots against available source buffer words.
169 * Through this it is possible to move the check for IIS_TX_FREE_COUNT outside
170 * the loop and do some further optimization. Right after the loops (source
171 * buffer -> IISFIFO) are done we need to check whether we have to exit FIQ
172 * handler (this must be done, if all free FIFO slots were filled) or we will
173 * have to get some new source data. Important information kept from former
174 * ASM implementation (not used anymore): GCC fails to make use of the fact
175 * that FIQ mode has registers r8-r14 banked, and so does not need to be saved.
176 * This routine uses only these registers, and so will never touch the stack
177 * unless it actually needs to do so when calling pcm_callback_for_more.
178 * C version is still included below for reference and testing.
180 #if 1
181 void fiq_playback(void) ICODE_ATTR __attribute__((naked));
182 void fiq_playback(void)
184 /* r10 contains IISCONFIG address (set in crt0.S to minimise code in actual
185 * FIQ handler. r11 contains address of p (also set in crt0.S). Most other
186 * addresses we need are generated by using offsets with these two.
187 * r10 + 0x40 is IISFIFO_WR, and r10 + 0x0c is IISFIFO_CFG.
188 * r8 and r9 contains local copies of p and size respectively.
189 * r0-r3 and r12 is a working register.
191 asm volatile (
192 "stmfd sp!, { r0-r3, lr } \n" /* stack scratch regs and lr */
194 #if CONFIG_CPU == PP5002
195 "ldr r12, =0xcf001040 \n" /* Some magic from iPodLinux */
196 "ldr r12, [r12] \n"
197 #endif
198 "ldmia r11, { r8-r9 } \n" /* r8 = p, r9 = size */
199 "cmp r9, #0 \n" /* is size 0? */
200 "beq .more_data \n" /* if so, ask pcmbuf for more data */
202 #if SAMPLE_SIZE == 16
203 ".check_fifo: \n"
204 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
205 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 16 (PP502x) */
207 "mov r1, r0, lsr #16 \n" /* number of free FIFO slots */
208 "cmp r1, r9, lsr #2 \n" /* number of words from source */
209 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
210 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
212 "subs r1, r1, #2 \n"
213 ".fifo_loop_2: \n"
214 "ldmgeia r8!, {r2, r12} \n" /* load four samples */
215 "strge r2 , [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
216 "strge r12, [r10, %[wr]] \n" /* write sample 2-3 to IISFIFO_WR */
217 "subges r1, r1, #2 \n" /* one more loop? */
218 "bge .fifo_loop_2 \n" /* yes, continue */
220 "tst r1, #1 \n" /* two samples (one word) left? */
221 "ldrne r12, [r8], #4 \n" /* load two samples */
222 "strne r12, [r10, %[wr]] \n" /* write sample 0-1 to IISFIFO_WR */
224 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
225 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
226 #elif SAMPLE_SIZE == 32
227 ".check_fifo: \n"
228 "ldr r0, [r10, %[cfg]] \n" /* read IISFIFO_CFG to check FIFO status */
229 "and r0, r0, %[mask] \n" /* r0 = IIS_TX_FREE_COUNT << 23 (PP5002) */
231 "movs r1, r0, lsr #24 \n" /* number of free pairs of FIFO slots */
232 "beq .exit \n" /* no complete pair? -> exit */
233 "cmp r1, r9, lsr #2 \n" /* number of words from source */
234 "movgt r1, r9, lsr #2 \n" /* r1 = amount of allowed loops */
235 "sub r9, r9, r1, lsl #2 \n" /* r1 words will be written in following loop */
237 ".fifo_loop: \n"
238 "ldr r12, [r8], #4 \n" /* load two samples */
239 "mov r2 , r12, lsl #16 \n" /* put left sample at the top bits */
240 "str r2 , [r10, %[wr]] \n" /* write top sample to IISFIFO_WR */
241 "str r12, [r10, %[wr]] \n" /* write low sample to IISFIFO_WR*/
242 "subs r1, r1, #1 \n" /* one more loop? */
243 "bgt .fifo_loop \n" /* yes, continue */
245 "cmp r9, #0 \n" /* either FIFO is full or source buffer is empty */
246 "bgt .exit \n" /* if source buffer is not empty, FIFO must be full */
247 #endif
249 ".more_data: \n"
250 "ldr r2, =pcm_callback_for_more \n"
251 "ldr r2, [r2] \n" /* get callback address */
252 "cmp r2, #0 \n" /* check for null pointer */
253 "beq .stop \n" /* callback removed, stop */
254 "stmia r11, { r8-r9 } \n" /* save internal copies of variables back */
255 "mov r0, r11 \n" /* r0 = &p */
256 "add r1, r11, #4 \n" /* r1 = &size */
257 "mov lr, pc \n" /* call pcm_callback_for_more */
258 "bx r2 \n"
259 "ldmia r11, { r8-r9 } \n" /* reload p and size */
260 "cmp r9, #0 \n" /* did we actually get more data? */
261 "bne .check_fifo \n"
263 ".stop: \n" /* call termination routines */
264 "ldr r12, =pcm_play_dma_stop \n"
265 "mov lr, pc \n"
266 "bx r12 \n"
267 "ldr r12, =pcm_play_dma_stopped_callback \n"
268 "mov lr, pc \n"
269 "bx r12 \n"
271 ".exit: \n" /* (r8=0 if stopping, look above) */
272 "stmia r11, { r8-r9 } \n" /* save p and size */
273 "ldmfd sp!, { r0-r3, lr } \n"
274 "subs pc, lr, #4 \n" /* FIQ specific return sequence */
275 ".ltorg \n"
276 : /* These must only be integers! No regs */
277 : [mask]"i"(IIS_TX_FREE_MASK),
278 [cfg]"i"((int)&IISFIFO_CFG - (int)&IISCONFIG),
279 [wr]"i"((int)&IISFIFO_WR - (int)&IISCONFIG)
282 #else /* C version for reference */
283 void fiq_playback(void) __attribute__((interrupt ("FIQ"))) ICODE_ATTR;
284 /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
285 void fiq_playback(void)
287 register pcm_more_callback_type get_more;
289 #if CONFIG_CPU == PP5002
290 inl(0xcf001040);
291 #endif
293 do {
294 while (dma_play_data.size > 0) {
295 if (IIS_TX_FREE_COUNT < 2) {
296 return;
298 #if SAMPLE_SIZE == 16
299 IISFIFO_WR = *dma_play_data.p16++;
300 #elif SAMPLE_SIZE == 32
301 IISFIFO_WR = *dma_play_data.p32++ << 16;
302 IISFIFO_WR = *dma_play_data.p32++ << 16;
303 #endif
304 dma_play_data.size -= 4;
307 /* p is empty, get some more data */
308 get_more = pcm_callback_for_more;
309 if (get_more) {
310 get_more((unsigned char**)&dma_play_data.addr,
311 &dma_play_data.size);
313 } while (dma_play_data.size);
315 /* No more data, so disable the FIFO/interrupt */
316 pcm_play_dma_stop();
317 pcm_play_dma_stopped_callback();
319 #endif /* ASM / C selection */
320 #endif /* CPU_PP502x */
322 /* For the locks, FIQ must be disabled because the handler manipulates
323 IISCONFIG and the operation is not atomic - dual core support
324 will require other measures */
325 void pcm_play_lock(void)
327 int status = disable_fiq_save();
329 if (++dma_play_data.locked == 1) {
330 #ifdef CPU_PP502x
331 CPU_INT_DIS = DMA_MASK;
332 #else
333 IIS_IRQTX_REG &= ~IIS_IRQTX;
334 #endif
337 restore_fiq(status);
340 void pcm_play_unlock(void)
342 int status = disable_fiq_save();
344 if (--dma_play_data.locked == 0 && dma_play_data.state != 0) {
345 #ifdef CPU_PP502x
346 CPU_INT_EN = DMA_MASK;
347 #else
348 IIS_IRQTX_REG |= IIS_IRQTX;
349 #endif
352 restore_fiq(status);
355 static void play_start_pcm(void)
357 fiq_function = fiq_playback;
359 #ifdef CPU_PP502x
360 /* Not at least MAX_DMA_CHUNK_SIZE left or there would be less than a
361 * FIFO's worth of data after this transfer? */
362 size_t size = MAX_DMA_CHUNK_SIZE;
363 if (size + 16*4 > dma_play_data.size)
364 size = dma_play_data.size;
366 DMA0_RAM_ADDR = dma_play_data.addr;
367 DMA0_CMD = DMA_PLAY_CONFIG | (size - 4) | DMA_CMD_START;
368 dma_play_data.state = 1;
369 #else
370 IISCONFIG &= ~IIS_TXFIFOEN; /* Stop transmitting */
372 /* Fill the FIFO or start when data is used up */
373 while (1) {
374 if (IIS_TX_FREE_COUNT < 2 || dma_play_data.size == 0) {
375 IISCONFIG |= IIS_TXFIFOEN; /* Start transmitting */
376 dma_play_data.state = 1;
377 return;
380 #if SAMPLE_SIZE == 16
381 IISFIFO_WR = *dma_play_data.p16++;
382 #elif SAMPLE_SIZE == 32
383 IISFIFO_WR = *dma_play_data.p32++ << 16;
384 IISFIFO_WR = *dma_play_data.p32++ << 16;
385 #endif
386 dma_play_data.size -= 4;
388 #endif
391 static void play_stop_pcm(void)
393 #ifdef CPU_PP502x
394 unsigned long status = DMA0_STATUS; /* Snapshot- resume from this point */
395 unsigned long cmd = DMA0_CMD;
396 size_t size = 0;
398 /* Stop transfer */
399 DMA0_CMD = cmd & ~(DMA_CMD_START | DMA_CMD_INTR);
401 /* Wait for not busy + clear int */
402 while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR));
404 if (status & DMA_STATUS_BUSY) {
405 /* Transfer was interrupted - leave what's left */
406 size = (cmd & 0xfffc) - (status & 0xfffc);
408 else if (status & DMA_STATUS_INTR) {
409 /* Transfer was finished - DMA0_STATUS will have been reloaded
410 * automatically with size in DMA0_CMD. Setup to restart on next
411 * segment. */
412 size = (cmd & 0xfffc) + 4;
414 /* else not an active state - size = 0 */
416 dma_play_data.addr += size;
417 dma_play_data.size -= size;
419 if (dma_play_data.size == 0)
420 dma_play_data.addr = 0; /* Entire buffer has completed. */
421 #else
422 /* Disable TX interrupt */
423 IIS_IRQTX_REG &= ~IIS_IRQTX;
424 #endif
426 /* Wait for FIFO to empty */
427 while (!IIS_TX_IS_EMPTY);
429 dma_play_data.state = 0;
432 void pcm_play_dma_start(const void *addr, size_t size)
434 addr = (void *)(((long)addr + 2) & ~3);
435 size &= ~3;
437 #if NUM_CORES > 1
438 /* This will become more important later - and different ! */
439 dma_play_data.core = processor_id(); /* save initiating core */
440 #endif
442 pcm_play_dma_stop();
444 if (size == 0)
445 return;
447 #ifdef CPU_PP502x
448 if ((unsigned long)addr < UNCACHED_BASE_ADDR) {
449 /* Flush any pending cache writes */
450 addr = UNCACHED_ADDR(addr);
451 cpucache_flush();
454 dma_play_data.addr = (unsigned long)addr;
455 dma_play_data.size = size;
456 DMA0_PER_ADDR = (unsigned long)&IISFIFO_WR;
457 DMA0_FLAGS = DMA_FLAGS_UNK26;
458 DMA0_INCR = DMA_INCR_RANGE_FIXED | DMA_INCR_WIDTH_32BIT;
459 #endif
461 play_start_pcm();
464 /* Stops the DMA transfer and interrupt */
465 void pcm_play_dma_stop(void)
467 play_stop_pcm();
468 dma_play_data.addr = 0;
469 dma_play_data.size = 0;
470 #if NUM_CORES > 1
471 dma_play_data.core = 0; /* no core in control */
472 #endif
475 void pcm_play_dma_pause(bool pause)
477 if (pause) {
478 play_stop_pcm();
479 } else {
480 play_start_pcm();
484 size_t pcm_get_bytes_waiting(void)
486 return dma_play_data.size & ~3;
489 void pcm_play_dma_init(void)
491 /* Initialize default register values. */
492 audiohw_init();
494 #ifdef CPU_PP502x
495 /* Enable DMA controller */
496 DMA_MASTER_CONTROL |= DMA_MASTER_CONTROL_EN;
497 /* FIQ priority for DMA */
498 CPU_INT_PRIORITY |= DMA_MASK;
499 /* Enable request?? Not setting or clearing everything doesn't seem to
500 * prevent it operating. Perhaps important for reliability (how requests
501 * are handled). */
502 DMA_REQ_STATUS |= 1ul << DMA_REQ_IIS;
503 DMA0_STATUS;
504 #else
505 /* Set up banked registers for FIQ mode */
507 /* Use non-banked registers for scratch. */
508 register volatile void *iiscfg asm("r0") = &IISCONFIG;
509 register volatile void *dmapd asm("r1") = &dma_play_data;
511 asm volatile (
512 "mrs r2, cpsr \n" /* Save mode and interrupt status */
513 "msr cpsr_c, #0xd1 \n" /* Switch to FIQ mode */
514 "mov r8, #0 \n"
515 "mov r9, #0 \n"
516 "mov r10, %[iiscfg] \n"
517 "mov r11, %[dmapd] \n"
518 "msr cpsr_c, r2 \n"
520 : [iiscfg]"r"(iiscfg), [dmapd]"r"(dmapd)
521 : "r2");
523 /* FIQ priority for I2S */
524 CPU_INT_PRIORITY |= IIS_MASK;
525 CPU_INT_EN = IIS_MASK;
526 #endif
528 IISCONFIG |= IIS_TXFIFOEN;
531 void pcm_postinit(void)
533 audiohw_postinit();
536 const void * pcm_play_dma_get_peak_buffer(int *count)
538 unsigned long addr, size;
540 int status = disable_fiq_save();
541 addr = dma_play_data.addr;
542 size = dma_play_data.size;
543 restore_fiq(status);
545 *count = size >> 2;
546 return (void *)((addr + 2) & ~3);
549 /****************************************************************************
550 ** Recording DMA transfer
552 #ifdef HAVE_RECORDING
553 /* PCM recording interrupt routine lockout */
554 static struct dma_data dma_rec_data IBSS_ATTR =
556 /* Initialize to a locked, stopped state */
557 { .addr = 0 },
558 .size = 0,
559 #if NUM_CORES > 1
560 .core = 0x00,
561 #endif
562 .locked = 0,
563 .state = 0
566 /* For the locks, FIQ must be disabled because the handler manipulates
567 IISCONFIG and the operation is not atomic - dual core support
568 will require other measures */
569 void pcm_rec_lock(void)
571 int status = disable_fiq_save();
573 if (++dma_rec_data.locked == 1)
574 IIS_IRQRX_REG &= ~IIS_IRQRX;
576 restore_fiq(status);
579 void pcm_rec_unlock(void)
581 int status = disable_fiq_save();
583 if (--dma_rec_data.locked == 0 && dma_rec_data.state != 0)
584 IIS_IRQRX_REG |= IIS_IRQRX;
586 restore_fiq(status);
589 /* NOTE: direct stack use forbidden by GCC stack handling bug for FIQ */
590 void fiq_record(void) ICODE_ATTR __attribute__((interrupt ("FIQ")));
592 #if defined(SANSA_C200) || defined(SANSA_E200)
593 void fiq_record(void)
595 register pcm_more_callback_type2 more_ready;
596 register int32_t value;
598 if (audio_channels == 2) {
599 /* RX is stereo */
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 *dma_rec_data.p16++ = value;
610 dma_rec_data.size -= 4;
612 /* TODO: Figure out how to do IIS loopback */
613 if (audio_output_source != AUDIO_SRC_PLAYBACK) {
614 if (IIS_TX_FREE_COUNT >= 16) {
615 /* Resync the output FIFO - it ran dry */
616 IISFIFO_WR = 0;
617 IISFIFO_WR = 0;
619 IISFIFO_WR = value;
620 IISFIFO_WR = value;
624 else {
625 /* RX is left channel mono */
626 while (dma_rec_data.size > 0) {
627 if (IIS_RX_FULL_COUNT < 2) {
628 return;
631 /* Discard every other sample since ADC clock is 1/2 LRCK */
632 value = IISFIFO_RD;
633 IISFIFO_RD;
635 value = (uint16_t)value | (value << 16);
637 *dma_rec_data.p16++ = value;
638 dma_rec_data.size -= 4;
640 if (audio_output_source != AUDIO_SRC_PLAYBACK) {
641 if (IIS_TX_FREE_COUNT >= 16) {
642 /* Resync the output FIFO - it ran dry */
643 IISFIFO_WR = 0;
644 IISFIFO_WR = 0;
647 value = *((int32_t *)dma_rec_data.p16 - 1);
648 IISFIFO_WR = value;
649 IISFIFO_WR = value;
654 more_ready = pcm_callback_more_ready;
656 if (more_ready == NULL || more_ready(0) < 0) {
657 /* Finished recording */
658 pcm_rec_dma_stop();
659 pcm_rec_dma_stopped_callback();
663 #else
664 void fiq_record(void)
666 register pcm_more_callback_type2 more_ready;
668 while (dma_rec_data.size > 0) {
669 if (IIS_RX_FULL_COUNT < 2) {
670 return;
673 #if SAMPLE_SIZE == 16
674 *dma_rec_data.p16++ = IISFIFO_RD;
675 #elif SAMPLE_SIZE == 32
676 *dma_rec_data.p32++ = IISFIFO_RD >> 16;
677 *dma_rec_data.p32++ = IISFIFO_RD >> 16;
678 #endif
679 dma_rec_data.size -= 4;
682 more_ready = pcm_callback_more_ready;
684 if (more_ready == NULL || more_ready(0) < 0) {
685 /* Finished recording */
686 pcm_rec_dma_stop();
687 pcm_rec_dma_stopped_callback();
691 #endif /* SANSA_E200 */
693 /* Continue transferring data in */
694 void pcm_record_more(void *start, size_t size)
696 pcm_rec_peak_addr = start; /* Start peaking at dest */
697 dma_rec_data.addr = (unsigned long)start; /* Start of RX buffer */
698 dma_rec_data.size = size; /* Bytes to transfer */
701 void pcm_rec_dma_stop(void)
703 /* disable interrupt */
704 IIS_IRQRX_REG &= ~IIS_IRQRX;
706 dma_rec_data.state = 0;
707 dma_rec_data.size = 0;
708 #if NUM_CORES > 1
709 dma_rec_data.core = 0x00;
710 #endif
712 /* disable fifo */
713 IISCONFIG &= ~IIS_RXFIFOEN;
714 IISFIFO_CFG |= IIS_RXCLR;
717 void pcm_rec_dma_start(void *addr, size_t size)
719 pcm_rec_dma_stop();
721 pcm_rec_peak_addr = addr;
722 dma_rec_data.addr = (unsigned long)addr;
723 dma_rec_data.size = size;
724 #if NUM_CORES > 1
725 /* This will become more important later - and different ! */
726 dma_rec_data.core = processor_id(); /* save initiating core */
727 #endif
728 /* setup FIQ handler */
729 fiq_function = fiq_record;
731 /* interrupt on full fifo, enable record fifo interrupt */
732 dma_rec_data.state = 1;
734 /* enable RX FIFO */
735 IISCONFIG |= IIS_RXFIFOEN;
737 /* enable IIS interrupt as FIQ */
738 CPU_INT_PRIORITY |= IIS_MASK;
739 CPU_INT_EN = IIS_MASK;
742 void pcm_rec_dma_close(void)
744 pcm_rec_dma_stop();
745 } /* pcm_close_recording */
747 void pcm_rec_dma_init(void)
749 pcm_rec_dma_stop();
750 } /* pcm_init */
752 const void * pcm_rec_dma_get_peak_buffer(int *count)
754 unsigned long addr, end;
756 int status = disable_fiq_save();
757 addr = (unsigned long)pcm_rec_peak_addr;
758 end = dma_rec_data.addr;
759 restore_fiq(status);
761 *count = (end >> 2) - (addr >> 2);
762 return (void *)(addr & ~3);
763 } /* pcm_rec_dma_get_peak_buffer */
765 #endif /* HAVE_RECORDING */