diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/as3525.h | 1 | ||||
-rw-r--r-- | firmware/export/config/sansac200v2.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansaclip.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansaclipplus.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansaclipv2.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansaclipzip.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansae200v2.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansafuze.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansafuzev2.h | 9 | ||||
-rw-r--r-- | firmware/export/config/sansam200v4.h | 9 | ||||
-rw-r--r-- | firmware/export/pcm_sampr.h | 5 | ||||
-rw-r--r-- | firmware/pcm.c | 9 | ||||
-rw-r--r-- | firmware/target/arm/as3525/audio-as3525.c | 52 | ||||
-rw-r--r-- | firmware/target/arm/as3525/pcm-as3525.c | 295 | ||||
-rw-r--r-- | firmware/target/arm/sandisk/audio-c200_e200.c | 31 |
15 files changed, 267 insertions, 207 deletions
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 | ||
327 | unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate); | 329 | unsigned 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 | ||
28 | int audio_channels = 2; | 29 | int audio_channels = 2; |
29 | 30 | ||
31 | #if CONFIG_CPU == AS3525 | ||
32 | int audio_output_source = AUDIO_SRC_PLAYBACK; | ||
33 | #endif | ||
34 | |||
30 | void audio_set_output_source(int source) | 35 | void 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 | ||
39 | void audio_input_mux(int source, unsigned flags) | 56 | void 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 | ||
136 | unsigned 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 */ | |||
43 | static size_t play_sub_size; /* size of current subtransfer */ | 43 | static size_t play_sub_size; /* size of current subtransfer */ |
44 | static void dma_callback(void); | 44 | static void dma_callback(void); |
45 | static int locked = 0; | 45 | static int locked = 0; |
46 | static bool is_playing = false; | 46 | static bool volatile is_playing = false; |
47 | static bool play_callback_pending = false; | 47 | static bool play_callback_pending = false; |
48 | 48 | ||
49 | #ifdef HAVE_RECORDING | ||
50 | /* Stopping playback gates clock if not recording */ | ||
51 | static bool volatile is_recording = false; | ||
52 | #endif | ||
53 | |||
49 | /* Mask the DMA interrupt */ | 54 | /* Mask the DMA interrupt */ |
50 | void pcm_play_lock(void) | 55 | void pcm_play_lock(void) |
51 | { | 56 | { |
@@ -116,26 +121,27 @@ static void dma_callback(void) | |||
116 | 121 | ||
117 | void pcm_play_dma_start(const void *addr, size_t size) | 122 | void 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 | ||
136 | void pcm_play_dma_stop(void) | 141 | void 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) | |||
175 | void pcm_play_dma_init(void) | 183 | void 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 | ||
184 | void pcm_play_dma_postinit(void) | 192 | void pcm_play_dma_postinit(void) |
@@ -209,14 +217,15 @@ static inline unsigned char mclk_divider(void) | |||
209 | 217 | ||
210 | void pcm_dma_apply_settings(void) | 218 | void 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 | ||
222 | size_t pcm_get_bytes_waiting(void) | 231 | size_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 | ||
260 | static int rec_locked = 0; | 269 | static int rec_locked = 0; |
261 | static bool is_recording = false; | 270 | static uint32_t *rec_dma_addr; |
262 | static bool rec_callback_pending = false; | 271 | static size_t rec_dma_size; |
263 | static void *rec_dma_start_addr; | ||
264 | static size_t rec_dma_size, rec_dma_transfer_size; | ||
265 | static void rec_dma_callback(void); | ||
266 | #if CONFIG_CPU == AS3525 | ||
267 | /* points to the samples which need to be duplicated into the right channel */ | ||
268 | static int16_t *mono_samples; | ||
269 | #endif | ||
270 | |||
271 | 272 | ||
272 | void pcm_rec_lock(void) | 273 | void pcm_rec_lock(void) |
273 | { | 274 | { |
274 | ++rec_locked; | 275 | int oldlevel = disable_irq_save(); |
275 | } | ||
276 | |||
277 | 276 | ||
278 | void 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 | ||
293 | static 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 | 288 | void pcm_rec_unlock(void) |
309 | /* if needed, duplicate samples of the working channel until the given bound */ | ||
310 | static 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 */ | ||
342 | static 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 | ||
358 | static 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 | ||
302 | void 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 | |||
402 | void pcm_rec_dma_stop(void) | 366 | void 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 | ||
419 | void pcm_rec_dma_start(void *addr, size_t size) | 383 | void 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 | ||
442 | void pcm_rec_dma_close(void) | 400 | void 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 | ||
447 | void pcm_rec_dma_init(void) | 407 | void 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 | ||
456 | const void * pcm_rec_dma_get_peak_buffer(void) | 419 | const 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 |
190 | unsigned int pcm_sampr_type_rec_to_play(unsigned int samplerate) | 190 | unsigned 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 */ |