summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/plugins/pitch_detector.c2
-rw-r--r--apps/recorder/pcm_record.c2
-rw-r--r--firmware/export/as3525.h1
-rw-r--r--firmware/export/config/sansac200v2.h9
-rw-r--r--firmware/export/config/sansaclip.h9
-rw-r--r--firmware/export/config/sansaclipplus.h9
-rw-r--r--firmware/export/config/sansaclipv2.h9
-rw-r--r--firmware/export/config/sansaclipzip.h9
-rw-r--r--firmware/export/config/sansae200v2.h9
-rw-r--r--firmware/export/config/sansafuze.h9
-rw-r--r--firmware/export/config/sansafuzev2.h9
-rw-r--r--firmware/export/config/sansam200v4.h9
-rw-r--r--firmware/export/pcm_sampr.h5
-rw-r--r--firmware/pcm.c9
-rw-r--r--firmware/target/arm/as3525/audio-as3525.c52
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c295
-rw-r--r--firmware/target/arm/sandisk/audio-c200_e200.c31
17 files changed, 269 insertions, 209 deletions
diff --git a/apps/plugins/pitch_detector.c b/apps/plugins/pitch_detector.c
index ec208268ab..c30d48a025 100644
--- a/apps/plugins/pitch_detector.c
+++ b/apps/plugins/pitch_detector.c
@@ -1078,7 +1078,7 @@ static void record_and_get_pitch(void)
}
}
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
diff --git a/apps/recorder/pcm_record.c b/apps/recorder/pcm_record.c
index e83db0f418..30b681ab45 100644
--- a/apps/recorder/pcm_record.c
+++ b/apps/recorder/pcm_record.c
@@ -290,7 +290,7 @@ static void pcm_rec_have_more(int status, void **start, size_t *size)
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();
}
diff --git a/firmware/export/as3525.h b/firmware/export/as3525.h
index 87e3fc43d7..c5e01d5bc8 100644
--- a/firmware/export/as3525.h
+++ b/firmware/export/as3525.h
@@ -526,7 +526,6 @@ CE lines
/* 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)
diff --git a/firmware/export/config/sansac200v2.h b/firmware/export/config/sansac200v2.h
index 4223d41b92..a5b857fe81 100644
--- a/firmware/export/config/sansac200v2.h
+++ b/firmware/export/config/sansac200v2.h
@@ -14,7 +14,14 @@
/* 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 */
diff --git a/firmware/export/config/sansaclip.h b/firmware/export/config/sansaclip.h
index 7427d623fb..4e214669b1 100644
--- a/firmware/export/config/sansaclip.h
+++ b/firmware/export/config/sansaclip.h
@@ -14,7 +14,14 @@
/* 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 */
diff --git a/firmware/export/config/sansaclipplus.h b/firmware/export/config/sansaclipplus.h
index 8a0a0403f3..0ae67b70d0 100644
--- a/firmware/export/config/sansaclipplus.h
+++ b/firmware/export/config/sansaclipplus.h
@@ -21,7 +21,14 @@
/* 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 */
diff --git a/firmware/export/config/sansaclipv2.h b/firmware/export/config/sansaclipv2.h
index a39fe3e12c..d7a50afa20 100644
--- a/firmware/export/config/sansaclipv2.h
+++ b/firmware/export/config/sansaclipv2.h
@@ -14,7 +14,14 @@
/* 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 */
diff --git a/firmware/export/config/sansaclipzip.h b/firmware/export/config/sansaclipzip.h
index 3df9ed57fd..e0f39afcf1 100644
--- a/firmware/export/config/sansaclipzip.h
+++ b/firmware/export/config/sansaclipzip.h
@@ -21,7 +21,14 @@
/* 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 */
diff --git a/firmware/export/config/sansae200v2.h b/firmware/export/config/sansae200v2.h
index 34c2cd98ad..a03dfe05a6 100644
--- a/firmware/export/config/sansae200v2.h
+++ b/firmware/export/config/sansae200v2.h
@@ -12,7 +12,14 @@
/* 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 */
diff --git a/firmware/export/config/sansafuze.h b/firmware/export/config/sansafuze.h
index 8563664cb8..2e9c261a04 100644
--- a/firmware/export/config/sansafuze.h
+++ b/firmware/export/config/sansafuze.h
@@ -12,7 +12,14 @@
/* 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
diff --git a/firmware/export/config/sansafuzev2.h b/firmware/export/config/sansafuzev2.h
index 1c0f8a99dc..7465010166 100644
--- a/firmware/export/config/sansafuzev2.h
+++ b/firmware/export/config/sansafuzev2.h
@@ -12,7 +12,14 @@
/* 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
diff --git a/firmware/export/config/sansam200v4.h b/firmware/export/config/sansam200v4.h
index 88679c1a78..52b10a4431 100644
--- a/firmware/export/config/sansam200v4.h
+++ b/firmware/export/config/sansam200v4.h
@@ -16,7 +16,14 @@
/* 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 */
diff --git a/firmware/export/pcm_sampr.h b/firmware/export/pcm_sampr.h
index 62bfd0068b..01a8ed428e 100644
--- a/firmware/export/pcm_sampr.h
+++ b/firmware/export/pcm_sampr.h
@@ -305,6 +305,8 @@ enum rec_freq_indexes
#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 @@ extern const unsigned long rec_freq_sampr[REC_NUM_FREQ];
#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 */
diff --git a/firmware/pcm.c b/firmware/pcm.c
index f5efb4f84e..d1a897dcab 100644
--- a/firmware/pcm.c
+++ b/firmware/pcm.c
@@ -393,21 +393,14 @@ void pcm_set_frequency(unsigned int samplerate)
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,
diff --git a/firmware/target/arm/as3525/audio-as3525.c b/firmware/target/arm/as3525/audio-as3525.c
index 10c6161881..e4bb39b406 100644
--- a/firmware/target/arm/as3525/audio-as3525.c
+++ b/firmware/target/arm/as3525/audio-as3525.c
@@ -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,33 @@ void audio_input_mux(int source, unsigned flags)
}
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 && type == SAMPR_TYPE_REC)
+ {
+ /* 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;
+
+ samplerate *= 2; /* Recording rates are 1/2 the codec clock */
+ }
+#endif /* HAVE_RECORDING */
+
+ return samplerate;
+ (void)type;
+}
+#endif /* CONFIG_SAMPR_TYPES */
+
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c
index f82b373ade..8b42bbd5b2 100644
--- a/firmware/target/arm/as3525/pcm-as3525.c
+++ b/firmware/target/arm/as3525/pcm-as3525.c
@@ -43,9 +43,14 @@ static size_t dma_rem_size; /* Remaining size - in 4*32 bits */
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 @@ static void dma_callback(void)
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 @@ void pcm_play_dma_stop(void)
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_pause(bool pause)
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 @@ static inline unsigned char mclk_divider(void)
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 @@ void * pcm_dma_addr(void *addr)
#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)
-{
- 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;
-
- do {
- int16_t left = *samples++; // load 1 sample of the left-channel
- *samples++ = left; // copy it in the right-channel
- } while(samples != end);
-
- 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 */
-}
-#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)
+void pcm_rec_unlock(void)
{
- 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 */
+ int oldlevel = disable_irq_save();
-static void rec_dma_callback(void)
-{
- if(rec_dma_transfer_size)
+ if (--rec_locked == 0 && is_recording)
{
+ VIC_INT_ENABLE = INTERRUPT_I2SIN;
+ I2SIN_MASK = (1<<2); /* I2SIN_MASK_POAF */
+ }
-#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;
+ restore_irq(oldlevel);
+}
- /* don't act like we just transferred data when we are called from
- * pcm_rec_unlock() */
- rec_dma_transfer_size = 0;
+void INT_I2SIN(void)
+{
#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(locked)
+ if (audio_channels == 1)
+ {
+ /* RX is left-channel-only mono */
+ while (rec_dma_size > 0)
{
- rec_callback_pending = is_recording;
- return;
+ if (I2SIN_RAW_STATUS & (1<<5))
+ return; /* empty */
+
+ /* Discard every other sample since ADC clock is 1/2 LRCK */
+ uint32_t value = *I2SIN_DATA;
+ *I2SIN_DATA;
+
+ /* Data is in left channel only - copy to right channel
+ 14-bit => 16-bit samples */
+ value = (uint16_t)(value << 2) | (value << 18);
+
+ 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;
+ }
+
+ *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 */
+
+ rec_dma_addr = NULL;
+ rec_dma_size = 0;
- CGU_AUDIO &= ~(1<<11);
- bitclr32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE |
- CGU_I2SOUT_APB_CLOCK_ENABLE);
+ if (!is_playing)
+ bitclr32(&CGU_AUDIO, (1<<11));
- rec_callback_pending = false;
+ 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;
-
- dma_retain();
+ is_recording = true;
- bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE |
- CGU_I2SOUT_APB_CLOCK_ENABLE);
- CGU_AUDIO |= (1<<11);
+ bitset32(&CGU_AUDIO, (1<<11));
- I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */
+ rec_dma_addr = addr;
+ rec_dma_size = size;
- is_recording = true;
+ /* ensure empty FIFO */
+ while (!(I2SIN_RAW_STATUS & (1<<5)))
+ *I2SIN_DATA;
- 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 */
diff --git a/firmware/target/arm/sandisk/audio-c200_e200.c b/firmware/target/arm/sandisk/audio-c200_e200.c
index 2f6bde1b98..4de7aa62c3 100644
--- a/firmware/target/arm/sandisk/audio-c200_e200.c
+++ b/firmware/target/arm/sandisk/audio-c200_e200.c
@@ -186,16 +186,25 @@ void audiohw_set_sampr_dividers(int fsel)
IISDIV = (IISDIV & ~0xc000003f) | regvals[fsel].iisdiv;
}
-#ifdef HAVE_RECORDING
-unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate)
+#ifdef CONFIG_SAMPR_TYPES
+unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate,
+ unsigned int type)
{
- /* 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;
-
- return samplerate * 2; /* Recording rates are 1/2 the codec clock */
+#ifdef HAVE_RECORDING
+ if (samplerate != HW_SAMPR_RESET && type == SAMPR_TYPE_REC)
+ {
+ /* 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;
+
+ samplerate *= 2; /* Recording rates are 1/2 the codec clock */
+ }
+#endif /* HAVE_RECORDING */
+
+ return samplerate;
+ (void)type;
}
-#endif
+#endif /* CONFIG_SAMPR_TYPES */