summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2011-12-08 19:20:00 +0000
committerMichael Sevakis <jethead71@rockbox.org>2011-12-08 19:20:00 +0000
commite42a3194de3b4fb9cd3e7cbd2e0ff17fea804b72 (patch)
tree71ddb9c8a927ac4b4a2ba962cd92f935eb1ba445
parent2c7379757cb20ac9731c98847c6f6309d32607f3 (diff)
downloadrockbox-e42a3194de3b4fb9cd3e7cbd2e0ff17fea804b72.tar.gz
rockbox-e42a3194de3b4fb9cd3e7cbd2e0ff17fea804b72.zip
AS3525v1/v2:
Fix problems with volume of recorded material by converting 14-bit samples to 16-bit. Remove duplicate samples from recorded data and support proper samplerate since ADC runs 1/2 the codec clock. Support monitoring mono on both output channels by feeding data manually to I2SOUT under the right conditions. DMA is no longer used for recording since frames must be processed as described above but it does allow full-duplex audio. Miscellaneous change includes a proper constant (HW_SAMPR_DEFAULT) to reset the hardware samplerate when recording is closed. PP5024 and AS3525 have different default recording rates (22kHz and 44kHz respectively) but both have half-speed ADC. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31180 a1c6a512-1295-4272-9138-f99709370657
-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)
1078 } 1078 }
1079 } 1079 }
1080 rb->pcm_close_recording(); 1080 rb->pcm_close_recording();
1081 rb->pcm_set_frequency(REC_SAMPR_DEFAULT | SAMPR_TYPE_REC); 1081 rb->pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC);
1082#ifdef HAVE_SCHEDULER_BOOSTCTRL 1082#ifdef HAVE_SCHEDULER_BOOSTCTRL
1083 rb->cancel_cpu_boost(); 1083 rb->cancel_cpu_boost();
1084#endif 1084#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)
290static void reset_hardware(void) 290static void reset_hardware(void)
291{ 291{
292 /* reset pcm to defaults */ 292 /* reset pcm to defaults */
293 pcm_set_frequency(REC_SAMPR_DEFAULT | SAMPR_TYPE_REC); 293 pcm_set_frequency(HW_SAMPR_RESET | SAMPR_TYPE_REC);
294 audio_set_output_source(AUDIO_SRC_PLAYBACK); 294 audio_set_output_source(AUDIO_SRC_PLAYBACK);
295 pcm_apply_settings(); 295 pcm_apply_settings();
296} 296}
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
526 526
527/* PCM addresses for obtaining buffers will be what DMA is using (physical) */ 527/* PCM addresses for obtaining buffers will be what DMA is using (physical) */
528#define HAVE_PCM_DMA_ADDRESS 528#define HAVE_PCM_DMA_ADDRESS
529#define HAVE_PCM_REC_DMA_ADDRESS
530 529
531/* Timer frequency */ 530/* Timer frequency */
532#define TIMER_FREQ (24000000 / 16) 531#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 @@
14/* define this if you have recording possibility */ 14/* define this if you have recording possibility */
15#define HAVE_RECORDING 15#define HAVE_RECORDING
16 16
17#define REC_SAMPR_CAPS SAMPR_CAP_ALL 17#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
18 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
19 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
20
21/* because the samplerates don't match at each point, we must be able to
22 * tell PCM which set of rates to use. not needed if recording rates are
23 * a simple subset of playback rates and are equal values. */
24#define CONFIG_SAMPR_TYPES
18 25
19/* Define bitmask of input sources - recordable bitmask can be defined 26/* Define bitmask of input sources - recordable bitmask can be defined
20 explicitly if different */ 27 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 @@
14/* define this if you have recording possibility */ 14/* define this if you have recording possibility */
15#define HAVE_RECORDING 15#define HAVE_RECORDING
16 16
17#define REC_SAMPR_CAPS SAMPR_CAP_ALL 17#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
18 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
19 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
20
21/* because the samplerates don't match at each point, we must be able to
22 * tell PCM which set of rates to use. not needed if recording rates are
23 * a simple subset of playback rates and are equal values. */
24#define CONFIG_SAMPR_TYPES
18 25
19/* Define bitmask of input sources - recordable bitmask can be defined 26/* Define bitmask of input sources - recordable bitmask can be defined
20 explicitly if different */ 27 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 @@
21/* define this if you have recording possibility */ 21/* define this if you have recording possibility */
22#define HAVE_RECORDING 22#define HAVE_RECORDING
23 23
24#define REC_SAMPR_CAPS SAMPR_CAP_ALL 24#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
25 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
26 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
27
28/* because the samplerates don't match at each point, we must be able to
29 * tell PCM which set of rates to use. not needed if recording rates are
30 * a simple subset of playback rates and are equal values. */
31#define CONFIG_SAMPR_TYPES
25 32
26/* Define bitmask of input sources - recordable bitmask can be defined 33/* Define bitmask of input sources - recordable bitmask can be defined
27 explicitly if different */ 34 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 @@
14/* define this if you have recording possibility */ 14/* define this if you have recording possibility */
15#define HAVE_RECORDING 15#define HAVE_RECORDING
16 16
17#define REC_SAMPR_CAPS SAMPR_CAP_ALL 17#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
18 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
19 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
20
21/* because the samplerates don't match at each point, we must be able to
22 * tell PCM which set of rates to use. not needed if recording rates are
23 * a simple subset of playback rates and are equal values. */
24#define CONFIG_SAMPR_TYPES
18 25
19/* Define bitmask of input sources - recordable bitmask can be defined 26/* Define bitmask of input sources - recordable bitmask can be defined
20 explicitly if different */ 27 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 @@
21/* define this if you have recording possibility */ 21/* define this if you have recording possibility */
22#define HAVE_RECORDING 22#define HAVE_RECORDING
23 23
24#define REC_SAMPR_CAPS SAMPR_CAP_ALL 24#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
25 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
26 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
27
28/* because the samplerates don't match at each point, we must be able to
29 * tell PCM which set of rates to use. not needed if recording rates are
30 * a simple subset of playback rates and are equal values. */
31#define CONFIG_SAMPR_TYPES
25 32
26/* Define bitmask of input sources - recordable bitmask can be defined 33/* Define bitmask of input sources - recordable bitmask can be defined
27 explicitly if different */ 34 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 @@
12/* define this if you have recording possibility */ 12/* define this if you have recording possibility */
13#define HAVE_RECORDING 13#define HAVE_RECORDING
14 14
15#define REC_SAMPR_CAPS SAMPR_CAP_ALL 15#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
16 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
17 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
18
19/* because the samplerates don't match at each point, we must be able to
20 * tell PCM which set of rates to use. not needed if recording rates are
21 * a simple subset of playback rates and are equal values. */
22#define CONFIG_SAMPR_TYPES
16 23
17/* Define bitmask of input sources - recordable bitmask can be defined 24/* Define bitmask of input sources - recordable bitmask can be defined
18 explicitly if different */ 25 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 @@
12/* define this if you have recording possibility */ 12/* define this if you have recording possibility */
13#define HAVE_RECORDING 13#define HAVE_RECORDING
14 14
15#define REC_SAMPR_CAPS SAMPR_CAP_ALL 15#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
16 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
17 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
18
19/* because the samplerates don't match at each point, we must be able to
20 * tell PCM which set of rates to use. not needed if recording rates are
21 * a simple subset of playback rates and are equal values. */
22#define CONFIG_SAMPR_TYPES
16 23
17/* Default recording levels */ 24/* Default recording levels */
18#define DEFAULT_REC_MIC_GAIN 23 25#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 @@
12/* define this if you have recording possibility */ 12/* define this if you have recording possibility */
13#define HAVE_RECORDING 13#define HAVE_RECORDING
14 14
15#define REC_SAMPR_CAPS SAMPR_CAP_ALL 15#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
16 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
17 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
18
19/* because the samplerates don't match at each point, we must be able to
20 * tell PCM which set of rates to use. not needed if recording rates are
21 * a simple subset of playback rates and are equal values. */
22#define CONFIG_SAMPR_TYPES
16 23
17/* Default recording levels */ 24/* Default recording levels */
18#define DEFAULT_REC_MIC_GAIN 23 25#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 @@
16/* define this if you have recording possibility */ 16/* define this if you have recording possibility */
17#define HAVE_RECORDING 17#define HAVE_RECORDING
18 18
19#define REC_SAMPR_CAPS SAMPR_CAP_ALL 19#define REC_SAMPR_CAPS (SAMPR_CAP_48 | SAMPR_CAP_44 | SAMPR_CAP_32 | \
20 SAMPR_CAP_24 | SAMPR_CAP_22 | SAMPR_CAP_16 | \
21 SAMPR_CAP_12 | SAMPR_CAP_11 | SAMPR_CAP_8)
22
23/* because the samplerates don't match at each point, we must be able to
24 * tell PCM which set of rates to use. not needed if recording rates are
25 * a simple subset of playback rates and are equal values. */
26#define CONFIG_SAMPR_TYPES
20 27
21/* Define bitmask of input sources - recordable bitmask can be defined 28/* Define bitmask of input sources - recordable bitmask can be defined
22 explicitly if different */ 29 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
305#define REC_SAMPR_DEFAULT SAMPR_44 305#define REC_SAMPR_DEFAULT SAMPR_44
306#endif 306#endif
307 307
308#define HW_SAMPR_RESET 0
309
308#define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \ 310#define REC_FREQ_CFG_VAL_LIST &REC_HAVE_96_(",96") REC_HAVE_88_(",88") \
309 REC_HAVE_64_(",64") REC_HAVE_48_(",48") \ 311 REC_HAVE_64_(",64") REC_HAVE_48_(",48") \
310 REC_HAVE_44_(",44") REC_HAVE_32_(",32") \ 312 REC_HAVE_44_(",44") REC_HAVE_32_(",32") \
@@ -324,7 +326,8 @@ extern const unsigned long rec_freq_sampr[REC_NUM_FREQ];
324#define SAMPR_TYPE_REC (0x01 << 24) 326#define SAMPR_TYPE_REC (0x01 << 24)
325#endif 327#endif
326 328
327unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate); 329unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate,
330 unsigned int type);
328 331
329#else /* ndef CONFIG_SAMPR_TYPES */ 332#else /* ndef CONFIG_SAMPR_TYPES */
330 333
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)
393 int index; 393 int index;
394 394
395#ifdef CONFIG_SAMPR_TYPES 395#ifdef CONFIG_SAMPR_TYPES
396#ifdef HAVE_RECORDING
397 unsigned int type = samplerate & SAMPR_TYPE_MASK; 396 unsigned int type = samplerate & SAMPR_TYPE_MASK;
398#endif
399 samplerate &= ~SAMPR_TYPE_MASK; 397 samplerate &= ~SAMPR_TYPE_MASK;
400 398
401#ifdef HAVE_RECORDING
402#if SAMPR_TYPE_REC != 0
403 /* For now, supported targets have direct conversion when configured with 399 /* For now, supported targets have direct conversion when configured with
404 * CONFIG_SAMPR_TYPES. 400 * CONFIG_SAMPR_TYPES.
405 * Some hypothetical target with independent rates would need slightly 401 * Some hypothetical target with independent rates would need slightly
406 * different handling throughout this source. */ 402 * different handling throughout this source. */
407 if (type == SAMPR_TYPE_REC) 403 samplerate = pcm_sampr_to_hw_sampr(samplerate, type);
408 samplerate = pcm_sampr_type_rec_to_play(samplerate);
409#endif
410#endif /* HAVE_RECORDING */
411#endif /* CONFIG_SAMPR_TYPES */ 404#endif /* CONFIG_SAMPR_TYPES */
412 405
413 index = round_value_to_list32(samplerate, hw_freq_sampr, 406 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 @@
24#include "audio.h" 24#include "audio.h"
25#include "audiohw.h" 25#include "audiohw.h"
26#include "sound.h" 26#include "sound.h"
27#include "general.h"
27 28
28int audio_channels = 2; 29int audio_channels = 2;
29 30
31#if CONFIG_CPU == AS3525
32int audio_output_source = AUDIO_SRC_PLAYBACK;
33#endif
34
30void audio_set_output_source(int source) 35void audio_set_output_source(int source)
31{ 36{
32 bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); 37 bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE);
33 if (source == AUDIO_SRC_PLAYBACK) 38
34 I2SOUT_CONTROL &= ~(1<<5); 39 if ((unsigned)source >= AUDIO_NUM_SOURCES)
40 source = AUDIO_SRC_PLAYBACK;
41
42 bool loopback = source != AUDIO_SRC_PLAYBACK;
43
44#if CONFIG_CPU == AS3525
45 loopback = loopback && audio_channels > 1;
46
47 audio_output_source = source;
48#endif
49
50 if (loopback)
51 I2SOUT_CONTROL |= (1<<5); /* loopback from i2sin fifo */
35 else 52 else
36 I2SOUT_CONTROL |= 1<<5; /* source = loopback from i2sin fifo */ 53 I2SOUT_CONTROL &= ~(1<<5); /* normal i2sout */
37} 54}
38 55
39void audio_input_mux(int source, unsigned flags) 56void audio_input_mux(int source, unsigned flags)
@@ -108,4 +125,33 @@ void audio_input_mux(int source, unsigned flags)
108 } 125 }
109 126
110 last_source = source; 127 last_source = source;
128
129#if CONFIG_CPU == AS3525
130 /* Sync on behalf of change in number of channels */
131 audio_set_output_source(audio_output_source);
132#endif
111} 133}
134
135#ifdef CONFIG_SAMPR_TYPES
136unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate,
137 unsigned int type)
138{
139#ifdef HAVE_RECORDING
140 if (samplerate != HW_SAMPR_RESET && type == SAMPR_TYPE_REC)
141 {
142 /* Check if the samplerate is in the list of recordable rates.
143 * Fail to default if not */
144 int index = round_value_to_list32(samplerate, rec_freq_sampr,
145 REC_NUM_FREQ, false);
146 if (samplerate != rec_freq_sampr[index])
147 samplerate = REC_SAMPR_DEFAULT;
148
149 samplerate *= 2; /* Recording rates are 1/2 the codec clock */
150 }
151#endif /* HAVE_RECORDING */
152
153 return samplerate;
154 (void)type;
155}
156#endif /* CONFIG_SAMPR_TYPES */
157
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 */
43static size_t play_sub_size; /* size of current subtransfer */ 43static size_t play_sub_size; /* size of current subtransfer */
44static void dma_callback(void); 44static void dma_callback(void);
45static int locked = 0; 45static int locked = 0;
46static bool is_playing = false; 46static bool volatile is_playing = false;
47static bool play_callback_pending = false; 47static bool play_callback_pending = false;
48 48
49#ifdef HAVE_RECORDING
50/* Stopping playback gates clock if not recording */
51static bool volatile is_recording = false;
52#endif
53
49/* Mask the DMA interrupt */ 54/* Mask the DMA interrupt */
50void pcm_play_lock(void) 55void pcm_play_lock(void)
51{ 56{
@@ -116,26 +121,27 @@ static void dma_callback(void)
116 121
117void pcm_play_dma_start(const void *addr, size_t size) 122void pcm_play_dma_start(const void *addr, size_t size)
118{ 123{
124 is_playing = true;
125
119 dma_start_addr = (void*)addr; 126 dma_start_addr = (void*)addr;
120 dma_start_size = size; 127 dma_start_size = size;
121 dma_sub_addr = dma_start_addr; 128 dma_sub_addr = dma_start_addr;
122 dma_rem_size = size; 129 dma_rem_size = size;
123 130
124 bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE);
125 CGU_AUDIO |= (1<<11);
126
127 dma_retain(); 131 dma_retain();
128 132
129 is_playing = true;
130
131 /* force writeback */ 133 /* force writeback */
132 clean_dcache_range(dma_start_addr, dma_start_size); 134 clean_dcache_range(dma_start_addr, dma_start_size);
135
136 bitset32(&CGU_AUDIO, (1<<11));
137
133 play_start_pcm(); 138 play_start_pcm();
134} 139}
135 140
136void pcm_play_dma_stop(void) 141void pcm_play_dma_stop(void)
137{ 142{
138 is_playing = false; 143 is_playing = false;
144
139 dma_disable_channel(1); 145 dma_disable_channel(1);
140 146
141 /* Ensure byte counts read back 0 */ 147 /* Ensure byte counts read back 0 */
@@ -146,8 +152,10 @@ void pcm_play_dma_stop(void)
146 152
147 dma_release(); 153 dma_release();
148 154
149 bitclr32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); 155#ifdef HAVE_RECORDING
150 CGU_AUDIO &= ~(1<<11); 156 if (!is_recording)
157 bitclr32(&CGU_AUDIO, (1<<11));
158#endif
151 159
152 play_callback_pending = false; 160 play_callback_pending = false;
153} 161}
@@ -175,10 +183,10 @@ void pcm_play_dma_pause(bool pause)
175void pcm_play_dma_init(void) 183void pcm_play_dma_init(void)
176{ 184{
177 bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE); 185 bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE);
178 186 I2SOUT_CONTROL = (1<<6) | (1<<3); /* enable dma, stereo */
179 I2SOUT_CONTROL = (1<<6)|(1<<3) /* enable dma, stereo */;
180 187
181 audiohw_preinit(); 188 audiohw_preinit();
189 pcm_dma_apply_settings();
182} 190}
183 191
184void pcm_play_dma_postinit(void) 192void pcm_play_dma_postinit(void)
@@ -209,14 +217,15 @@ static inline unsigned char mclk_divider(void)
209 217
210void pcm_dma_apply_settings(void) 218void pcm_dma_apply_settings(void)
211{ 219{
212 int cgu_audio = CGU_AUDIO; /* read register */ 220 bitmod32(&CGU_AUDIO,
213 cgu_audio &= ~(3 << 0); /* clear i2sout MCLK_SEL */ 221 (0<<24) | /* I2SI_MCLK2PAD_EN = disabled */
214 cgu_audio |= (AS3525_MCLK_SEL << 0); /* set i2sout MCLK_SEL */ 222 (0<<23) | /* I2SI_MCLK_EN = disabled */
215 cgu_audio &= ~(0x1ff << 2); /* clear i2sout divider */ 223 (0<<14) | /* I2SI_MCLK_DIV_SEL = unused */
216 cgu_audio |= mclk_divider() << 2; /* set new i2sout divider */ 224 (0<<12) | /* I2SI_MCLK_SEL = clk_main */
217 cgu_audio &= ~(1 << 23); /* clear I2SI_MCLK_EN */ 225 /* I2SO_MCLK_EN = unchanged */
218 cgu_audio &= ~(1 << 24); /* clear I2SI_MCLK2PAD_EN */ 226 (mclk_divider() << 2) | /* I2SO_MCLK_DIV_SEL */
219 CGU_AUDIO = cgu_audio; /* write back register */ 227 (AS3525_MCLK_SEL << 0), /* I2SO_MCLK_SEL */
228 0x01fff7ff);
220} 229}
221 230
222size_t pcm_get_bytes_waiting(void) 231size_t pcm_get_bytes_waiting(void)
@@ -258,220 +267,158 @@ void * pcm_dma_addr(void *addr)
258#ifdef HAVE_RECORDING 267#ifdef HAVE_RECORDING
259 268
260static int rec_locked = 0; 269static int rec_locked = 0;
261static bool is_recording = false; 270static uint32_t *rec_dma_addr;
262static bool rec_callback_pending = false; 271static size_t rec_dma_size;
263static void *rec_dma_start_addr;
264static size_t rec_dma_size, rec_dma_transfer_size;
265static void rec_dma_callback(void);
266#if CONFIG_CPU == AS3525
267/* points to the samples which need to be duplicated into the right channel */
268static int16_t *mono_samples;
269#endif
270
271 272
272void pcm_rec_lock(void) 273void pcm_rec_lock(void)
273{ 274{
274 ++rec_locked; 275 int oldlevel = disable_irq_save();
275}
276
277 276
278void pcm_rec_unlock(void) 277 if (++rec_locked == 1)
279{
280 if(--rec_locked == 0 && is_recording)
281 { 278 {
282 int old = disable_irq_save(); 279 bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE);
283 if(rec_callback_pending) 280 VIC_INT_EN_CLEAR = INTERRUPT_I2SIN;
284 { 281 I2SIN_MASK = 0; /* disables all interrupts */
285 rec_callback_pending = false;
286 rec_dma_callback();
287 }
288 restore_irq(old);
289 } 282 }
290}
291
292 283
293static void rec_dma_start(void) 284 restore_irq(oldlevel);
294{
295 rec_dma_transfer_size = rec_dma_size;
296
297 /* We are limited to 8188 DMA transfers, and the recording core asks for
298 * 8192 bytes. Avoid splitting 8192 bytes transfers in 8188 + 4 */
299 if(rec_dma_transfer_size > 4096)
300 rec_dma_transfer_size = 4096;
301
302 dma_enable_channel(1, (void*)I2SIN_DATA, rec_dma_start_addr, DMA_PERI_I2SIN,
303 DMAC_FLOWCTRL_DMAC_PERI_TO_MEM, false, true,
304 rec_dma_transfer_size >> 2, DMA_S4, rec_dma_callback);
305} 285}
306 286
307 287
308#if CONFIG_CPU == AS3525 288void pcm_rec_unlock(void)
309/* if needed, duplicate samples of the working channel until the given bound */
310static inline void mono2stereo(int16_t *end)
311{
312 if(audio_channels != 1) /* only for microphone */
313 return;
314#if 0
315 /* load pointer in a register and avoid updating it in each loop */
316 register int16_t *samples = mono_samples;
317
318 do {
319 int16_t left = *samples++; // load 1 sample of the left-channel
320 *samples++ = left; // copy it in the right-channel
321 } while(samples != end);
322
323 mono_samples = samples; /* update pointer */
324#else
325 /* gcc doesn't use pre indexing : let's save 1 cycle */
326 int16_t left;
327 asm (
328 "1: ldrh %0, [%1], #2 \n" // load 1 sample of the left-channel
329 " strh %0, [%1], #2 \n" // copy it in the right-channel
330 " cmp %1, %2 \n" // are we finished?
331 " bne 1b \n"
332 : "=&r"(left), "+r"(mono_samples)
333 : "r"(end)
334 : "memory"
335 );
336#endif /* C / ASM */
337}
338#endif /* CONFIG_CPU == AS3525 */
339
340#if CONFIG_CPU == AS3525v2
341/* scale microphone audio by 2 bits due to 14 bit ADC */
342static inline void scalevolume(int16_t *end, int size)
343{ 289{
344 if(audio_channels != 1) /* only for microphone */ 290 int oldlevel = disable_irq_save();
345 return;
346
347 /* load pointer in a register and avoid updating it in each loop */
348 register int16_t *samples = end;
349
350 do {
351 *samples++ <<=2;
352
353 } while(samples != end+size);
354
355}
356#endif /* CONFIG_CPU == AS3525v2 */
357 291
358static void rec_dma_callback(void) 292 if (--rec_locked == 0 && is_recording)
359{
360 if(rec_dma_transfer_size)
361 { 293 {
294 VIC_INT_ENABLE = INTERRUPT_I2SIN;
295 I2SIN_MASK = (1<<2); /* I2SIN_MASK_POAF */
296 }
362 297
363#if CONFIG_CPU == AS3525v2 298 restore_irq(oldlevel);
364 scalevolume(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr), rec_dma_transfer_size); 299}
365#endif
366 rec_dma_size -= rec_dma_transfer_size;
367 rec_dma_start_addr += rec_dma_transfer_size;
368 300
369 /* don't act like we just transferred data when we are called from
370 * pcm_rec_unlock() */
371 rec_dma_transfer_size = 0;
372 301
302void INT_I2SIN(void)
303{
373#if CONFIG_CPU == AS3525 304#if CONFIG_CPU == AS3525
374 /* the 2nd channel is silent when recording microphone on as3525v1 */ 305 if (audio_channels == 1)
375 mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr)); 306 {
376#endif 307 /* RX is left-channel-only mono */
377 308 while (rec_dma_size > 0)
378 if(locked)
379 { 309 {
380 rec_callback_pending = is_recording; 310 if (I2SIN_RAW_STATUS & (1<<5))
381 return; 311 return; /* empty */
312
313 /* Discard every other sample since ADC clock is 1/2 LRCK */
314 uint32_t value = *I2SIN_DATA;
315 *I2SIN_DATA;
316
317 /* Data is in left channel only - copy to right channel
318 14-bit => 16-bit samples */
319 value = (uint16_t)(value << 2) | (value << 18);
320
321 if (audio_output_source != AUDIO_SRC_PLAYBACK && !is_playing)
322 {
323 /* In this case, loopback is manual so that both output
324 channels have audio */
325 if (I2SOUT_RAW_STATUS & (1<<5))
326 {
327 /* Sync output fifo so it goes empty not before input is
328 filled */
329 for (unsigned i = 0; i < 4; i++)
330 *I2SOUT_DATA = 0;
331 }
332
333 *I2SOUT_DATA = value;
334 *I2SOUT_DATA = value;
335 }
336
337 *rec_dma_addr++ = value;
338 rec_dma_size -= 4;
382 } 339 }
383 } 340 }
384 341 else
385 if(!rec_dma_size) 342#endif /* CONFIG_CPU == AS3525 */
386 { 343 {
387 pcm_rec_more_ready_callback(0, &rec_dma_start_addr, 344 /* RX is stereo */
388 &rec_dma_size); 345 while (rec_dma_size > 0)
346 {
347 if (I2SIN_RAW_STATUS & (1<<5))
348 return; /* empty */
389 349
390 if(rec_dma_size == 0) 350 /* Discard every other sample since ADC clock is 1/2 LRCK */
391 return; 351 uint32_t value = *I2SIN_DATA;
352 *I2SIN_DATA;
392 353
393 dump_dcache_range(rec_dma_start_addr, rec_dma_size); 354 /* Loopback is in I2S hardware */
394#if CONFIG_CPU == AS3525 355
395 mono_samples = AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr); 356 /* 14-bit => 16-bit samples */
396#endif 357 *rec_dma_addr++ = (value << 2) & ~0x00030000;
358 rec_dma_size -= 4;
359 }
397 } 360 }
398 361
399 rec_dma_start(); 362 pcm_rec_more_ready_callback(0, (void *)&rec_dma_addr, &rec_dma_size);
400} 363}
401 364
365
402void pcm_rec_dma_stop(void) 366void pcm_rec_dma_stop(void)
403{ 367{
404 is_recording = false; 368 is_recording = false;
405 dma_disable_channel(1);
406 dma_release();
407 rec_dma_size = 0;
408 369
409 I2SIN_CONTROL &= ~(1<<11); /* disable dma */ 370 VIC_INT_EN_CLEAR = INTERRUPT_I2SIN;
371 I2SIN_MASK = 0; /* disables all interrupts */
372
373 rec_dma_addr = NULL;
374 rec_dma_size = 0;
410 375
411 CGU_AUDIO &= ~(1<<11); 376 if (!is_playing)
412 bitclr32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE | 377 bitclr32(&CGU_AUDIO, (1<<11));
413 CGU_I2SOUT_APB_CLOCK_ENABLE);
414 378
415 rec_callback_pending = false; 379 bitclr32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE);
416} 380}
417 381
418 382
419void pcm_rec_dma_start(void *addr, size_t size) 383void pcm_rec_dma_start(void *addr, size_t size)
420{ 384{
421 dump_dcache_range(addr, size); 385 is_recording = true;
422 rec_dma_start_addr = addr;
423#if CONFIG_CPU == AS3525
424 mono_samples = AS3525_UNCACHED_ADDR(addr);
425#endif
426 rec_dma_size = size;
427
428 dma_retain();
429 386
430 bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE | 387 bitset32(&CGU_AUDIO, (1<<11));
431 CGU_I2SOUT_APB_CLOCK_ENABLE);
432 CGU_AUDIO |= (1<<11);
433 388
434 I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */ 389 rec_dma_addr = addr;
390 rec_dma_size = size;
435 391
436 is_recording = true; 392 /* ensure empty FIFO */
393 while (!(I2SIN_RAW_STATUS & (1<<5)))
394 *I2SIN_DATA;
437 395
438 rec_dma_start(); 396 I2SIN_CLEAR = (1<<6) | (1<<0); /* push error, pop error */
439} 397}
440 398
441 399
442void pcm_rec_dma_close(void) 400void pcm_rec_dma_close(void)
443{ 401{
402 bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE);
403 pcm_rec_dma_stop();
444} 404}
445 405
446 406
447void pcm_rec_dma_init(void) 407void pcm_rec_dma_init(void)
448{ 408{
449 /* i2c clk src = I2SOUTIF, sdata src = AFE, 409 bitset32(&CGU_PERI, CGU_I2SIN_APB_CLOCK_ENABLE);
450 * data valid at positive edge of SCLK */ 410
451 I2SIN_CONTROL = (1<<2);
452 I2SIN_MASK = 0; /* disables all interrupts */ 411 I2SIN_MASK = 0; /* disables all interrupts */
412
413 /* 14 bits samples, i2c clk src = I2SOUTIF, sdata src = AFE,
414 * data valid at positive edge of SCLK */
415 I2SIN_CONTROL = (1<<5) | (1<<2);
453} 416}
454 417
455 418
456const void * pcm_rec_dma_get_peak_buffer(void) 419const void * pcm_rec_dma_get_peak_buffer(void)
457{ 420{
458#if CONFIG_CPU == AS3525 421 return rec_dma_addr;
459 /*
460 * We need to prevent the DMA callback from kicking in while we are
461 * faking the right channel with data from left channel.
462 */
463
464 int old = disable_irq_save();
465 int16_t *addr = AS3525_UNCACHED_ADDR((int16_t *)DMAC_CH_DST_ADDR(1));
466 mono2stereo(addr);
467 restore_irq(old);
468
469 return addr;
470
471#else
472 /* Microphone recording is stereo on as3525v2 */
473 return AS3525_UNCACHED_ADDR((int16_t *)DMAC_CH_DST_ADDR(1));
474#endif
475} 422}
476 423
477#endif /* HAVE_RECORDING */ 424#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)
186 IISDIV = (IISDIV & ~0xc000003f) | regvals[fsel].iisdiv; 186 IISDIV = (IISDIV & ~0xc000003f) | regvals[fsel].iisdiv;
187} 187}
188 188
189#ifdef HAVE_RECORDING 189#ifdef CONFIG_SAMPR_TYPES
190unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate) 190unsigned int pcm_sampr_to_hw_sampr(unsigned int samplerate,
191 unsigned int type)
191{ 192{
192 /* Check if the samplerate is in the list of recordable rates. 193#ifdef HAVE_RECORDING
193 * Fail to default if not */ 194 if (samplerate != HW_SAMPR_RESET && type == SAMPR_TYPE_REC)
194 int index = round_value_to_list32(samplerate, rec_freq_sampr, 195 {
195 REC_NUM_FREQ, false); 196 /* Check if the samplerate is in the list of recordable rates.
196 if (samplerate != rec_freq_sampr[index]) 197 * Fail to default if not */
197 return HW_SAMPR_DEFAULT; 198 int index = round_value_to_list32(samplerate, rec_freq_sampr,
198 199 REC_NUM_FREQ, false);
199 return samplerate * 2; /* Recording rates are 1/2 the codec clock */ 200 if (samplerate != rec_freq_sampr[index])
201 samplerate = REC_SAMPR_DEFAULT;
202
203 samplerate *= 2; /* Recording rates are 1/2 the codec clock */
204 }
205#endif /* HAVE_RECORDING */
206
207 return samplerate;
208 (void)type;
200} 209}
201#endif 210#endif /* CONFIG_SAMPR_TYPES */