Index: firmware/export/config-fuze.h =================================================================== --- firmware/export/config-fuze.h (revision 23655) +++ firmware/export/config-fuze.h (working copy) @@ -10,7 +10,7 @@ #define HW_SAMPR_CAPS SAMPR_CAP_ALL /* define this if you have recording possibility */ -//#define HAVE_RECORDING +#define HAVE_RECORDING #define REC_SAMPR_CAPS SAMPR_CAP_ALL Index: firmware/export/as3525.h =================================================================== --- firmware/export/as3525.h (revision 23655) +++ firmware/export/as3525.h (working copy) @@ -517,5 +517,14 @@ #define I2SIN_DATA (volatile unsigned long*)(I2SIN_BASE+0x14) #define I2SIN_SPDIF_STATUS (*(volatile unsigned long*)(I2SIN_BASE+0x18)) +/* I2SIN_MASK */ +#define I2SIN_MASK_PUER ( 1<<6 ) /* push error */ +#define I2SIN_MASK_POE ( 1<<5 ) /* empty */ +#define I2SIN_MASK_POAE ( 1<<4 ) /* almost empty */ +#define I2SIN_MASK_POHF ( 1<<3 ) /* half full */ +#define I2SIN_MASK_POAF ( 1<<2 ) /* almost full */ +#define I2SIN_MASK_POF ( 1<<1 ) /* full */ +#define I2SIN_MASK_POER ( 1<<0 ) /* pop error */ + #endif /*__AS3525_H__*/ Index: firmware/target/arm/as3525/pcm-as3525.c =================================================================== --- firmware/target/arm/as3525/pcm-as3525.c (revision 23655) +++ firmware/target/arm/as3525/pcm-as3525.c (working copy) @@ -51,7 +51,7 @@ void pcm_play_unlock(void) { if(--locked == 0) - VIC_INT_ENABLE |= INTERRUPT_DMAC; + VIC_INT_ENABLE = INTERRUPT_DMAC; } static void play_start_pcm(void) @@ -64,6 +64,10 @@ dma_size -= size; dma_start_addr += size; + /* FIXME: move these two lines out of play_start_pcm */ + CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; + CGU_AUDIO |= (1<<11); + clean_dcache_range((void*)addr, size); /* force write back */ dma_enable_channel(1, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT, DMAC_FLOWCTRL_DMAC_MEM_TO_PERI, true, false, size >> 2, DMA_S1, @@ -95,11 +99,6 @@ dma_retain(); - I2SOUT_CONTROL |= 1<<6; /* dma */ - - CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; - CGU_AUDIO |= (1<<11); - play_start_pcm(); } @@ -126,10 +125,8 @@ { CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; - CGU_AUDIO = (CGU_AUDIO & ~(3<<0)) | (1<<0); /* clock source PLLA */ + I2SOUT_CONTROL = (1<<6)|(1<<3) /* enable dma, stereo */; - I2SOUT_CONTROL = (1<<3) /* stereo */; - audiohw_preinit(); } @@ -148,10 +145,6 @@ int cgu_audio = CGU_AUDIO; /* read register */ cgu_audio &= ~(511 << 2); /* clear i2sout divider */ cgu_audio |= divider << 2; /* set new i2sout divider */ -#ifdef HAVE_RECORDING - cgu_audio &= ~(511 << 14); /* clear i2sin divider */ - cgu_audio |= divider << 14; /* set new i2sin divider */ -#endif CGU_AUDIO = cgu_audio; /* write back register */ } @@ -180,26 +173,34 @@ ** Recording DMA transfer **/ #ifdef HAVE_RECORDING +#define I2SIN_RECORDING_MASK ( I2SIN_MASK_POER | I2SIN_MASK_PUER | \ + I2SIN_MASK_POHF | I2SIN_MASK_POAF | I2SIN_MASK_POF ) static int rec_locked = 0; static unsigned int *rec_start_addr; static size_t rec_size; - void pcm_rec_lock(void) { - if(++rec_locked == 1) + if(++rec_locked == 1) { + int vic_state = disable_irq_save(); VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; + I2SIN_MASK = 0; + restore_irq( vic_state ); + } } - void pcm_rec_unlock(void) { - if(--rec_locked == 0) - VIC_INT_ENABLE |= INTERRUPT_I2SIN; + if(--rec_locked == 0) { + int vic_state = disable_irq_save(); + VIC_INT_ENABLE = INTERRUPT_I2SIN; + I2SIN_MASK = I2SIN_RECORDING_MASK; + restore_irq( vic_state ); + } } + - void pcm_record_more(void *start, size_t size) { rec_start_addr = start; @@ -209,11 +210,14 @@ void pcm_rec_dma_stop(void) { + int vic_state = disable_irq_save(); VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; - + I2SIN_MASK = 0; + restore_irq( vic_state ); I2SOUT_CONTROL &= ~(1<<5); /* source = i2soutif fifo */ CGU_AUDIO &= ~((1<<23)|(1<<11)); CGU_PERI &= ~(CGU_I2SIN_APB_CLOCK_ENABLE|CGU_I2SOUT_APB_CLOCK_ENABLE); + pcm_rec_unlock(); } @@ -222,16 +226,46 @@ register int status; register pcm_more_callback_type2 more_ready; + /* register *tmp will coax gcc into reading */ + /* I2SIN_DATA and writing in two instructions */ + register unsigned int *tmp; + status = I2SIN_STATUS; -#if 0 /* FIXME */ if ( status & ((1<<6)|(1<<0)) ) /* errors */ panicf("i2sin error: 0x%x = %s %s", status, (status & (1<<6)) ? "push" : "", (status & (1<<0)) ? "pop" : "" ); -#endif + /* called at half full so it's safe to */ + /* pull 16 FIFO reads in one chunk */ + if ( rec_size >= (16*4) ) { + tmp = rec_start_addr; + *tmp = *I2SIN_DATA; + *(tmp+1) = *I2SIN_DATA; + *(tmp+2) = *I2SIN_DATA; + *(tmp+3) = *I2SIN_DATA; + + *(tmp+4) = *I2SIN_DATA; + *(tmp+5) = *I2SIN_DATA; + *(tmp+6) = *I2SIN_DATA; + *(tmp+7) = *I2SIN_DATA; + + *(tmp+8) = *I2SIN_DATA; + *(tmp+9) = *I2SIN_DATA; + *(tmp+10)= *I2SIN_DATA; + *(tmp+11)= *I2SIN_DATA; + + *(tmp+12)= *I2SIN_DATA; + *(tmp+13)= *I2SIN_DATA; + *(tmp+14)= *I2SIN_DATA; + *(tmp+15)= *I2SIN_DATA; + rec_start_addr += 16; /* in 32bit words */ + rec_size -= 64; /* 16x4byte reads */ + } + + /* read out any odd samples left */ while (((I2SIN_RAW_STATUS & (1<<5)) == 0) && rec_size) { /* 14 bits per sample = 1 32 bits word */ @@ -272,10 +306,9 @@ while ( ( I2SIN_RAW_STATUS & ( 1<<5 ) ) == 0 ) tmp = *I2SIN_DATA; /* FLUSH FIFO */ I2SIN_CLEAR = (1<<6)|(1<<0); /* push error, pop error */ - I2SIN_MASK = (1<<6) | (1<<0) | - (1<<3) | (1<<2) | (1<<1); /* half full, almost full, full */ + I2SIN_MASK = I2SIN_RECORDING_MASK; - VIC_INT_ENABLE |= INTERRUPT_I2SIN; + VIC_INT_ENABLE = INTERRUPT_I2SIN; } @@ -287,8 +320,17 @@ void pcm_rec_dma_init(void) { - CGU_AUDIO = (CGU_AUDIO & ~(3<<12)) | (1<<12); /* clock source = PLLA */ - pcm_dma_apply_settings(); + unsigned long frequency = pcm_sampr; + + /* TODO : use a table ? */ + const int divider = (((AS3525_PLLA_FREQ/128) + (frequency/2)) / frequency) - 1; + + int cgu_audio = CGU_AUDIO; /* read register */ + cgu_audio &= ~(3 << 12); /* clear i2sin clocksource */ + cgu_audio |= (1 << 12); /* set to PLLA */ + cgu_audio &= ~(511 << 14); /* clear i2sin divider */ + cgu_audio |= divider << 14; /* set new i2sin divider */ + CGU_AUDIO = cgu_audio; /* write back register */ }