summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/pcm-as3525.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/as3525/pcm-as3525.c')
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c72
1 files changed, 57 insertions, 15 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c
index 5a403bad83..9f31d623fe 100644
--- a/firmware/target/arm/as3525/pcm-as3525.c
+++ b/firmware/target/arm/as3525/pcm-as3525.c
@@ -39,21 +39,28 @@ static unsigned char *dma_start_addr;
39static size_t dma_size; /* in 4*32 bits */ 39static size_t dma_size; /* in 4*32 bits */
40static void dma_callback(void); 40static void dma_callback(void);
41static int locked = 0; 41static int locked = 0;
42 42static bool is_playing = false;
43static int play_irq_state; 43static bool play_callback_pending = false;
44 44
45/* Mask the DMA interrupt */ 45/* Mask the DMA interrupt */
46void pcm_play_lock(void) 46void pcm_play_lock(void)
47{ 47{
48 if(++locked == 1) 48 ++locked;
49 play_irq_state = disable_irq_save();
50} 49}
51 50
52/* Unmask the DMA interrupt if enabled */ 51/* Unmask the DMA interrupt if enabled */
53void pcm_play_unlock(void) 52void pcm_play_unlock(void)
54{ 53{
55 if(--locked == 0) 54 if(--locked == 0 && is_playing)
56 restore_irq(play_irq_state); 55 {
56 int old = disable_irq_save();
57 if(play_callback_pending)
58 {
59 play_callback_pending = false;
60 dma_callback();
61 }
62 restore_irq(old);
63 }
57} 64}
58 65
59static void play_start_pcm(void) 66static void play_start_pcm(void)
@@ -74,6 +81,12 @@ static void play_start_pcm(void)
74 81
75static void dma_callback(void) 82static void dma_callback(void)
76{ 83{
84 if(locked)
85 {
86 play_callback_pending = is_playing;
87 return;
88 }
89
77 if(!dma_size) 90 if(!dma_size)
78 { 91 {
79 pcm_play_get_more_callback((void **)&dma_start_addr, &dma_size); 92 pcm_play_get_more_callback((void **)&dma_start_addr, &dma_size);
@@ -95,11 +108,14 @@ void pcm_play_dma_start(const void *addr, size_t size)
95 108
96 dma_retain(); 109 dma_retain();
97 110
111 is_playing = true;
112
98 play_start_pcm(); 113 play_start_pcm();
99} 114}
100 115
101void pcm_play_dma_stop(void) 116void pcm_play_dma_stop(void)
102{ 117{
118 is_playing = false;
103 dma_disable_channel(1); 119 dma_disable_channel(1);
104 dma_size = 0; 120 dma_size = 0;
105 121
@@ -111,6 +127,8 @@ void pcm_play_dma_stop(void)
111 127
112void pcm_play_dma_pause(bool pause) 128void pcm_play_dma_pause(bool pause)
113{ 129{
130 is_playing = !pause;
131
114 if(pause) 132 if(pause)
115 dma_disable_channel(1); 133 dma_disable_channel(1);
116 else 134 else
@@ -192,6 +210,8 @@ void * pcm_dma_addr(void *addr)
192#ifdef HAVE_RECORDING 210#ifdef HAVE_RECORDING
193 211
194static int rec_locked = 0; 212static int rec_locked = 0;
213static bool is_recording = false;
214static bool rec_callback_pending = false;
195static unsigned char *rec_dma_start_addr; 215static unsigned char *rec_dma_start_addr;
196static size_t rec_dma_size, rec_dma_transfer_size; 216static size_t rec_dma_size, rec_dma_transfer_size;
197static void rec_dma_callback(void); 217static void rec_dma_callback(void);
@@ -200,19 +220,25 @@ static void rec_dma_callback(void);
200static int16_t *mono_samples; 220static int16_t *mono_samples;
201#endif 221#endif
202 222
203static int rec_irq_state;
204 223
205void pcm_rec_lock(void) 224void pcm_rec_lock(void)
206{ 225{
207 if(++rec_locked == 1) 226 ++rec_locked;
208 rec_irq_state = disable_irq_save();
209} 227}
210 228
211 229
212void pcm_rec_unlock(void) 230void pcm_rec_unlock(void)
213{ 231{
214 if(--rec_locked == 0) 232 if(--rec_locked == 0 && is_recording)
215 restore_irq(rec_irq_state); 233 {
234 int old = disable_irq_save();
235 if(rec_callback_pending)
236 {
237 rec_callback_pending = false;
238 rec_dma_callback();
239 }
240 restore_irq(old);
241 }
216} 242}
217 243
218 244
@@ -268,11 +294,24 @@ static inline void mono2stereo(int16_t *end)
268 294
269static void rec_dma_callback(void) 295static void rec_dma_callback(void)
270{ 296{
271 rec_dma_size -= rec_dma_transfer_size; 297 if(rec_dma_transfer_size)
272 rec_dma_start_addr += rec_dma_transfer_size; 298 {
299 rec_dma_size -= rec_dma_transfer_size;
300 rec_dma_start_addr += rec_dma_transfer_size;
301
302 /* don't act like we just transferred data when we are called from
303 * pcm_rec_unlock() */
304 rec_dma_transfer_size = 0;
273 305
274 /* the 2nd channel is silent when recording microphone on as3525v1 */ 306 /* the 2nd channel is silent when recording microphone on as3525v1 */
275 mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr)); 307 mono2stereo(AS3525_UNCACHED_ADDR((int16_t*)rec_dma_start_addr));
308
309 if(locked)
310 {
311 rec_callback_pending = is_recording;
312 return;
313 }
314 }
276 315
277 if(!rec_dma_size) 316 if(!rec_dma_size)
278 { 317 {
@@ -293,6 +332,7 @@ static void rec_dma_callback(void)
293 332
294void pcm_rec_dma_stop(void) 333void pcm_rec_dma_stop(void)
295{ 334{
335 is_recording = false;
296 dma_disable_channel(1); 336 dma_disable_channel(1);
297 dma_release(); 337 dma_release();
298 rec_dma_size = 0; 338 rec_dma_size = 0;
@@ -320,6 +360,8 @@ void pcm_rec_dma_start(void *addr, size_t size)
320 360
321 I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */ 361 I2SIN_CONTROL |= (1<<11)|(1<<5); /* enable dma, 14bits samples */
322 362
363 is_recording = true;
364
323 rec_dma_start(); 365 rec_dma_start();
324} 366}
325 367