Index: apps/recorder/pcm_record.c =================================================================== --- apps/recorder/pcm_record.c (revision 31161) +++ apps/recorder/pcm_record.c (working copy) @@ -290,7 +290,7 @@ static void reset_hardware(void) { /* reset pcm to defaults */ - pcm_set_frequency(REC_SAMPR_DEFAULT | SAMPR_TYPE_REC); + pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC); audio_set_output_source(AUDIO_SRC_PLAYBACK); pcm_apply_settings(); } Index: apps/plugins/pitch_detector.c =================================================================== --- apps/plugins/pitch_detector.c (revision 31161) +++ apps/plugins/pitch_detector.c (working copy) @@ -1078,7 +1078,7 @@ } } rb->pcm_close_recording(); - rb->pcm_set_frequency(REC_SAMPR_DEFAULT | SAMPR_TYPE_REC); + rb->pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC); #ifdef HAVE_SCHEDULER_BOOSTCTRL rb->cancel_cpu_boost(); #endif Index: firmware/export/pcm_sampr.h =================================================================== --- firmware/export/pcm_sampr.h (revision 31161) +++ firmware/export/pcm_sampr.h (working copy) @@ -305,6 +305,8 @@ #define REC_SAMPR_DEFAULT SAMPR_44 #endif +#define HW_SAMPR_RESET 0 + #define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \ REC_HAVE_64_(",64") REC_HAVE_48_(",48") \ REC_HAVE_44_(",44") REC_HAVE_32_(",32") \ @@ -324,7 +326,8 @@ #define SAMPR_TYPE_REC (0x01 << 24) #endif -unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate); +unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate, + unsigned int type); #else /* ndef CONFIG_SAMPR_TYPES */ Index: firmware/export/as3525.h =================================================================== --- firmware/export/as3525.h (revision 31161) +++ firmware/export/as3525.h (working copy) @@ -526,7 +526,6 @@ /* PCM addresses for obtaining buffers will be what DMA is using (physical) */ #define HAVE_PCM_DMA_ADDRESS -#define HAVE_PCM_REC_DMA_ADDRESS /* Timer frequency */ #define TIMER_FREQ (24000000 / 16) Index: firmware/export/config/sansaclipzip.h =================================================================== --- firmware/export/config/sansaclipzip.h (revision 31161) +++ firmware/export/config/sansaclipzip.h (working copy) @@ -21,8 +21,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) Index: firmware/export/config/sansafuzev2.h =================================================================== --- firmware/export/config/sansafuzev2.h (revision 31161) +++ firmware/export/config/sansafuzev2.h (working copy) @@ -12,8 +12,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Default recording levels */ #define DEFAULT_REC_MIC_GAIN 23 #define DEFAULT_REC_LEFT_GAIN 23 Index: firmware/export/config/sansaclip.h =================================================================== --- firmware/export/config/sansaclip.h (revision 31161) +++ firmware/export/config/sansaclip.h (working copy) @@ -14,8 +14,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) Index: firmware/export/config/sansafuze.h =================================================================== --- firmware/export/config/sansafuze.h (revision 31161) +++ firmware/export/config/sansafuze.h (working copy) @@ -12,8 +12,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Default recording levels */ #define DEFAULT_REC_MIC_GAIN 23 #define DEFAULT_REC_LEFT_GAIN 23 Index: firmware/export/config/sansac200v2.h =================================================================== --- firmware/export/config/sansac200v2.h (revision 31161) +++ firmware/export/config/sansac200v2.h (working copy) @@ -14,8 +14,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) Index: firmware/export/config/sansae200v2.h =================================================================== --- firmware/export/config/sansae200v2.h (revision 31161) +++ firmware/export/config/sansae200v2.h (working copy) @@ -12,8 +12,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) Index: firmware/export/config/sansam200v4.h =================================================================== --- firmware/export/config/sansam200v4.h (revision 31161) +++ firmware/export/config/sansam200v4.h (working copy) @@ -16,8 +16,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) Index: firmware/export/config/sansaclipplus.h =================================================================== --- firmware/export/config/sansaclipplus.h (revision 31161) +++ firmware/export/config/sansaclipplus.h (working copy) @@ -21,8 +21,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) Index: firmware/export/config/sansaclipv2.h =================================================================== --- firmware/export/config/sansaclipv2.h (revision 31161) +++ firmware/export/config/sansaclipv2.h (working copy) @@ -14,8 +14,15 @@ /* define this if you have recording possibility */ #define HAVE_RECORDING -#define REC_SAMPR_CAPS SAMPR_CAP_ALL +#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \ + SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \ + SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8) +/* because the samplerates don't match at each point, we must be able to + * tell PCM which set of rates to use. not needed if recording rates are + * a simple subset of playback rates and are equal values. */ +#define CONFIG_SAMPR_TYPES + /* Define bitmask of input sources - recordable bitmask can be defined explicitly if different */ #define INPUT_SRC_CAPS (SRC_CAP_MIC | SRC_CAP_FMRADIO) Index: firmware/target/arm/as3525/pcm-as3525.c =================================================================== --- firmware/target/arm/as3525/pcm-as3525.c (revision 31161) +++ firmware/target/arm/as3525/pcm-as3525.c (working copy) @@ -43,9 +43,14 @@ static size_t play_sub_size; /* size of current subtransfer */ static void dma_callback(void); static int locked = 0; -static bool is_playing = false; +static bool volatile is_playing = false; static bool play_callback_pending = false; +#ifdef HAVE_RECORDING +/* Stopping playback gates clock if not recording */ +static bool volatile is_recording = false; +#endif + /* Mask the DMA interrupt */ void pcm_play_lock(void) { @@ -116,26 +121,27 @@ void pcm_play_dma_start(const void *addr, size_t size) { + is_playing = true; + dma_start_addr = (void*)addr; dma_start_size = size; dma_sub_addr = dma_start_addr; dma_rem_size = size; - bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); - CGU_AUDIO |= (1<<11); - dma_retain(); - is_playing = true; - /* force writeback */ clean_dcache_range(dma_start_addr, dma_start_size); + + bitset32(&CGU_AUDIO, (1<<11)); + play_start_pcm(); } void pcm_play_dma_stop(void) { is_playing = false; + dma_disable_channel(1); /* Ensure byte counts read back 0 */ @@ -146,8 +152,10 @@ dma_release(); - bitclr32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); - CGU_AUDIO &= ~(1<<11); +#ifdef HAVE_RECORDING + if (!is_recording) + bitclr32(&CGU_AUDIO, (1<<11)); +#endif play_callback_pending = false; } @@ -175,10 +183,10 @@ void pcm_play_dma_init(void) { bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); + I2SOUT_CONTROL = (1<<6) | (1<<3); /* enable dma, stereo */ - I2SOUT_CONTROL = (1<<6)|(1<<3) /* enable dma, stereo */; - audiohw_preinit(); + pcm_dma_apply_settings(); } void pcm_play_dma_postinit(void) @@ -209,14 +217,15 @@ void pcm_dma_apply_settings(void) { - int cgu_audio = CGU_AUDIO; /* read register */ - cgu_audio &= ~(3 << 0); /* clear i2sout MCLK_SEL */ - cgu_audio |= (AS3525_MCLK_SEL << 0); /* set i2sout MCLK_SEL */ - cgu_audio &= ~(0x1ff << 2); /* clear i2sout divider */ - cgu_audio |= mclk_divider() << 2; /* set new i2sout divider */ - cgu_audio &= ~(1 << 23); /* clear I2SI_MCLK_EN */ - cgu_audio &= ~(1 << 24); /* clear I2SI_MCLK2PAD_EN */ - CGU_AUDIO = cgu_audio; /* write back register */ + bitmod32(&CGU_AUDIO, + (0<<24) | /* I2SI_MCLK2PAD_EN = disabled */ + (0<<23) | /* I2SI_MCLK_EN = disabled */ + (0<<14) | /* I2SI_MCLK_DIV_SEL = unused */ + (0<<12) | /* I2SI_MCLK_SEL = clk_main */ + /* I2SO_MCLK_EN = unchanged */ + (mclk_divider() << 2) | /* I2SO_MCLK_DIV_SEL */ + (AS3525_MCLK_SEL << 0), /* I2SO_MCLK_SEL */ + 0x01fff7ff); } size_t pcm_get_bytes_waiting(void) @@ -258,220 +267,158 @@ #ifdef HAVE_RECORDING static int rec_locked = 0; -static bool is_recording = false; -static bool rec_callback_pending = false; -static void *rec_dma_start_addr; -static size_t rec_dma_size, rec_dma_transfer_size; -static void rec_dma_callback(void); -#if CONFIG_CPU == AS3525 -/* points to the samples which need to be duplicated into the right channel */ -static int16_t *mono_samples; -#endif +static uint32_t *rec_dma_addr; +static size_t rec_dma_size; - void pcm_rec_lock(void) { - ++rec_locked; -} + int oldlevel = disable_irq_save(); - -void pcm_rec_unlock(void) -{ - if(--rec_locked == 0 && is_recording) + if (++rec_locked == 1) { - int old = disable_irq_save(); - if(rec_callback_pending) - { - rec_callback_pending = false; - rec_dma_callback(); - } - restore_irq(old); + bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE); + VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; + I2SIN_MASK = 0; /* disables all interrupts */ } -} - -static void rec_dma_start(void) -{ - rec_dma_transfer_size = rec_dma_size; - - /* We are limited to 8188 DMA transfers, and the recording core asks for - * 8192 bytes. Avoid splitting 8192 bytes transfers in 8188 + 4 */ - if(rec_dma_transfer_size > 4096) - rec_dma_transfer_size = 4096; - - dma_enable_channel(1, (void*)I2SIN_DATA, rec_dma_start_addr, DMA_PERI_I2SIN, - DMAC_FLOWCTRL_DMAC_PERI_TO_MEM, false, true, - rec_dma_transfer_size >> 2, DMA_S4, rec_dma_callback); + restore_irq(oldlevel); } -#if CONFIG_CPU == AS3525 -/* if needed, duplicate samples of the working channel until the given bound */ -static inline void mono2stereo(int16_t *end) +void pcm_rec_unlock(void) { - if(audio_channels != 1) /* only for microphone */ - return; -#if 0 - /* load pointer in a register and avoid updating it in each loop */ - register int16_t *samples = mono_samples; + int oldlevel = disable_irq_save(); - do { - int16_t left = *samples++; // load 1 sample of the left-channel - *samples++ = left; // copy it in the right-channel - } while(samples != end); + if (--rec_locked == 0 && is_recording) + { + VIC_INT_ENABLE = INTERRUPT_I2SIN; + I2SIN_MASK = (1<<2); /* I2SIN_MASK_POAF */ + } - mono_samples = samples; /* update pointer */ -#else - /* gcc doesn't use pre indexing : let's save 1 cycle */ - int16_t left; - asm ( - "1: ldrh %0, [%1], #2 \n" // load 1 sample of the left-channel - " strh %0, [%1], #2 \n" // copy it in the right-channel - " cmp %1, %2 \n" // are we finished? - " bne 1b \n" - : "=&r"(left), "+r"(mono_samples) - : "r"(end) - : "memory" - ); -#endif /* C / ASM */ + restore_irq(oldlevel); } -#endif /* CONFIG_CPU == AS3525 */ -#if CONFIG_CPU == AS3525v2 -/* scale microphone audio by 2 bits due to 14 bit ADC */ -static inline void scalevolume(int16_t *end, int size) -{ - if(audio_channels != 1) /* only for microphone */ - return; - /* load pointer in a register and avoid updating it in each loop */ - register int16_t *samples = end; - - do { - *samples++ <<=2; - - } while(samples != end+size); - -} -#endif /* CONFIG_CPU == AS3525v2 */ - -static void rec_dma_callback(void) +void INT_I2SIN(void) { - if(rec_dma_transfer_size) +#if CONFIG_CPU == AS3525 + if (audio_channels == 1) { + /* RX is left-channel-only mono */ + while (rec_dma_size > 0) + { + if (I2SIN_RAW_STATUS & (1<<5)) + return; /* empty */ -#if CONFIG_CPU == AS3525v2 - scalevolume(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr), rec_dma_transfer_size); -#endif - rec_dma_size -= rec_dma_transfer_size; - rec_dma_start_addr += rec_dma_transfer_size; + /* Discard every other sample since ADC clock is 1/2 LRCK */ + uint32_t value = *I2SIN_DATA; + *I2SIN_DATA; - /* don't act like we just transferred data when we are called from - * pcm_rec_unlock() */ - rec_dma_transfer_size = 0; + /* Data is in left channel only - copy to right channel + 14-bit => 16-bit samples */ + value = (uint16_t)(value << 2) | (value << 18); -#if CONFIG_CPU == AS3525 - /* the 2nd channel is silent when recording microphone on as3525v1 */ - mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr)); -#endif + if (audio_output_source != AUDIO_SRC_PLAYBACK && !is_playing) + { + /* In this case, loopback is manual so that both output + channels have audio */ + if (I2SOUT_RAW_STATUS & (1<<5)) + { + /* Sync output fifo so it goes empty not before input is + filled */ + for (unsigned i = 0; i < 4; i++) + *I2SOUT_DATA = 0; + } - if(locked) - { - rec_callback_pending = is_recording; - return; + *I2SOUT_DATA = value; + *I2SOUT_DATA = value; + } + + *rec_dma_addr++ = value; + rec_dma_size -= 4; } } - - if(!rec_dma_size) + else +#endif /* CONFIG_CPU == AS3525 */ { - pcm_rec_more_ready_callback(0, &rec_dma_start_addr, - &rec_dma_size); + /* RX is stereo */ + while (rec_dma_size > 0) + { + if (I2SIN_RAW_STATUS & (1<<5)) + return; /* empty */ - if(rec_dma_size == 0) - return; + /* Discard every other sample since ADC clock is 1/2 LRCK */ + uint32_t value = *I2SIN_DATA; + *I2SIN_DATA; - dump_dcache_range(rec_dma_start_addr, rec_dma_size); -#if CONFIG_CPU == AS3525 - mono_samples = AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr); -#endif + /* Loopback is in I2S hardware */ + + /* 14-bit => 16-bit samples */ + *rec_dma_addr++ = (value << 2) & ~0x00030000; + rec_dma_size -= 4; + } } - rec_dma_start(); + pcm_rec_more_ready_callback(0, (void *)&rec_dma_addr, &rec_dma_size); } + void pcm_rec_dma_stop(void) { is_recording = false; - dma_disable_channel(1); - dma_release(); - rec_dma_size = 0; - I2SIN_CONTROL &= ~(1<<11); /* disable dma */ + VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; + I2SIN_MASK = 0; /* disables all interrupts */ - CGU_AUDIO &= ~(1<<11); - bitclr32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE | - CGU_I2SOUT_APB_CLOCK_ENABLE); + rec_dma_addr = NULL; + rec_dma_size = 0; - rec_callback_pending = false; + if (!is_playing) + bitclr32(&CGU_AUDIO, (1<<11)); + + bitclr32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE); } void pcm_rec_dma_start(void *addr, size_t size) { - dump_dcache_range(addr, size); - rec_dma_start_addr = addr; -#if CONFIG_CPU == AS3525 - mono_samples = AS3525_UNCACHED_ADDR(addr); -#endif - rec_dma_size = size; + is_recording = true; - dma_retain(); + bitset32(&CGU_AUDIO, (1<<11)); - bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE | - CGU_I2SOUT_APB_CLOCK_ENABLE); - CGU_AUDIO |= (1<<11); + rec_dma_addr = addr; + rec_dma_size = size; - I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */ + /* ensure empty FIFO */ + while (!(I2SIN_RAW_STATUS & (1<<5))) + *I2SIN_DATA; - is_recording = true; - - rec_dma_start(); + I2SIN_CLEAR = (1<<6) | (1<<0); /* push error, pop error */ } void pcm_rec_dma_close(void) { + bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE); + pcm_rec_dma_stop(); } void pcm_rec_dma_init(void) { - /* i2c clk src = I2SOUTIF, sdata src = AFE, - * data valid at positive edge of SCLK */ - I2SIN_CONTROL = (1<<2); + bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE); + I2SIN_MASK = 0; /* disables all interrupts */ + + /* 14 bits samples, i2c clk src = I2SOUTIF, sdata src = AFE, + * data valid at positive edge of SCLK */ + I2SIN_CONTROL = (1<<5) | (1<<2); } const void * pcm_rec_dma_get_peak_buffer(void) { -#if CONFIG_CPU == AS3525 - /* - * We need to prevent the DMA callback from kicking in while we are - * faking the right channel with data from left channel. - */ - - int old = disable_irq_save(); - int16_t *addr = AS3525_UNCACHED_ADDR((int16_t *)DMAC_CH_DST_ADDR(1)); - mono2stereo(addr); - restore_irq(old); - - return addr; - -#else - /* Microphone recording is stereo on as3525v2 */ - return AS3525_UNCACHED_ADDR((int16_t *)DMAC_CH_DST_ADDR(1)); -#endif + return rec_dma_addr; } #endif /* HAVE_RECORDING */ Index: firmware/target/arm/as3525/audio-as3525.c =================================================================== --- firmware/target/arm/as3525/audio-as3525.c (revision 31161) +++ firmware/target/arm/as3525/audio-as3525.c (working copy) @@ -24,16 +24,33 @@ #include "audio.h" #include "audiohw.h" #include "sound.h" +#include "general.h" int audio_channels = 2; +#if CONFIG_CPU == AS3525 +int audio_output_source = AUDIO_SRC_PLAYBACK; +#endif + void audio_set_output_source(int source) { bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); - if (source == AUDIO_SRC_PLAYBACK) - I2SOUT_CONTROL &= ~(1<<5); + + if ((unsigned)source >= AUDIO_NUM_SOURCES) + source = AUDIO_SRC_PLAYBACK; + + bool loopback = source != AUDIO_SRC_PLAYBACK; + +#if CONFIG_CPU == AS3525 + loopback = loopback && audio_channels > 1; + + audio_output_source = source; +#endif + + if (loopback) + I2SOUT_CONTROL |= (1<<5); /* loopback from i2sin fifo */ else - I2SOUT_CONTROL |= 1<<5; /* source = loopback from i2sin fifo */ + I2SOUT_CONTROL &= ~(1<<5); /* normal i2sout */ } void audio_input_mux(int source, unsigned flags) @@ -108,4 +125,35 @@ } last_source = source; + +#if CONFIG_CPU == AS3525 + /* Sync on behalf of change in number of channels */ + audio_set_output_source(audio_output_source); +#endif } + +#ifdef CONFIG_SAMPR_TYPES +unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate, + unsigned int type) +{ +#ifdef HAVE_RECORDING + if (samplerate == HW_SAMPR_RESET) + return HW_SAMPR_DEFAULT; + + if (type != SAMPR_TYPE_REC) + return samplerate; + + /* Check if the samplerate is in the list of recordable rates. + * Fail to default if not */ + int index = round_value_to_list32(samplerate, rec_freq_sampr, + REC_NUM_FREQ, false); + if (samplerate != rec_freq_sampr[index]) + samplerate = REC_SAMPR_DEFAULT; + + return samplerate * 2; /* Recording rates are 1/2 the codec clock */ +#else + return samplerate; + (void)type; +#endif +} +#endif Index: firmware/target/arm/sandisk/audio-c200_e200.c =================================================================== --- firmware/target/arm/sandisk/audio-c200_e200.c (revision 31161) +++ firmware/target/arm/sandisk/audio-c200_e200.c (working copy) @@ -186,16 +186,28 @@ IISDIV = (IISDIV & ~0xc000003f) | regvals[fsel].iisdiv; } +#ifdef CONFIG_SAMPR_TYPES +unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate, + unsigned int type) +{ #ifdef HAVE_RECORDING -unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate) -{ + if (samplerate == HW_SAMPR_RESET) + return HW_SAMPR_DEFAULT; + + if (type != SAMPR_TYPE_REC) + return samplerate; + /* Check if the samplerate is in the list of recordable rates. * Fail to default if not */ int index = round_value_to_list32(samplerate, rec_freq_sampr, REC_NUM_FREQ, false); if (samplerate != rec_freq_sampr[index]) - return HW_SAMPR_DEFAULT; + samplerate = REC_SAMPR_DEFAULT; return samplerate * 2; /* Recording rates are 1/2 the codec clock */ +#else + return samplerate; +#endif + (void)type; } #endif Index: firmware/pcm.c =================================================================== --- firmware/pcm.c (revision 31161) +++ firmware/pcm.c (working copy) @@ -393,21 +393,14 @@ int index; #ifdef CONFIG_SAMPR_TYPES -#ifdef HAVE_RECORDING unsigned int type = samplerate & SAMPR_TYPE_MASK; -#endif samplerate &= ~SAMPR_TYPE_MASK; -#ifdef HAVE_RECORDING -#if SAMPR_TYPE_REC != 0 /* For now, supported targets have direct conversion when configured with * CONFIG_SAMPR_TYPES. * Some hypothetical target with independent rates would need slightly * different handling throughout this source. */ - if (type == SAMPR_TYPE_REC) - samplerate = pcm_sampr_type_rec_to_play(samplerate); -#endif -#endif /* HAVE_RECORDING */ + samplerate = pcm_sampr_to_hw_sampr(samplerate, type); #endif /* CONFIG_SAMPR_TYPES */ index = round_value_to_list32(samplerate, hw_freq_sampr,