diff options
Diffstat (limited to 'firmware/target')
-rw-r--r-- | firmware/target/arm/as3525/pcm-as3525.c | 81 |
1 files changed, 59 insertions, 22 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c index a0d983fe43..88aaaf9220 100644 --- a/firmware/target/arm/as3525/pcm-as3525.c +++ b/firmware/target/arm/as3525/pcm-as3525.c | |||
@@ -7,7 +7,7 @@ | |||
7 | * \/ \/ \/ \/ \/ | 7 | * \/ \/ \/ \/ \/ |
8 | * $Id$ | 8 | * $Id$ |
9 | * | 9 | * |
10 | * Copyright © 2008 Rafaël Carré | 10 | * Copyright © 2008-2009 Rafaël Carré |
11 | * | 11 | * |
12 | * This program is free software; you can redistribute it and/or | 12 | * This program is free software; you can redistribute it and/or |
13 | * modify it under the terms of the GNU General Public License | 13 | * modify it under the terms of the GNU General Public License |
@@ -93,13 +93,11 @@ void pcm_play_dma_start(const void *addr, size_t size) | |||
93 | dma_size = size; | 93 | dma_size = size; |
94 | dma_start_addr = (unsigned char*)addr; | 94 | dma_start_addr = (unsigned char*)addr; |
95 | 95 | ||
96 | dma_retain(); | ||
97 | |||
98 | I2SOUT_CONTROL |= 1<<6; /* dma */ | ||
99 | |||
100 | CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; | 96 | CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; |
101 | CGU_AUDIO |= (1<<11); | 97 | CGU_AUDIO |= (1<<11); |
102 | 98 | ||
99 | dma_retain(); | ||
100 | |||
103 | play_start_pcm(); | 101 | play_start_pcm(); |
104 | } | 102 | } |
105 | 103 | ||
@@ -126,9 +124,7 @@ void pcm_play_dma_init(void) | |||
126 | { | 124 | { |
127 | CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; | 125 | CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; |
128 | 126 | ||
129 | CGU_AUDIO = (CGU_AUDIO & ~(3<<0)) | (1<<0); /* clock source PLLA */ | 127 | I2SOUT_CONTROL = (1<<6)|(1<<3) /* enable dma, stereo */; |
130 | |||
131 | I2SOUT_CONTROL = (1<<3) /* stereo */; | ||
132 | 128 | ||
133 | audiohw_preinit(); | 129 | audiohw_preinit(); |
134 | } | 130 | } |
@@ -148,10 +144,6 @@ void pcm_dma_apply_settings(void) | |||
148 | int cgu_audio = CGU_AUDIO; /* read register */ | 144 | int cgu_audio = CGU_AUDIO; /* read register */ |
149 | cgu_audio &= ~(511 << 2); /* clear i2sout divider */ | 145 | cgu_audio &= ~(511 << 2); /* clear i2sout divider */ |
150 | cgu_audio |= divider << 2; /* set new i2sout divider */ | 146 | cgu_audio |= divider << 2; /* set new i2sout divider */ |
151 | #ifdef HAVE_RECORDING | ||
152 | cgu_audio &= ~(511 << 14); /* clear i2sin divider */ | ||
153 | cgu_audio |= divider << 14; /* set new i2sin divider */ | ||
154 | #endif | ||
155 | CGU_AUDIO = cgu_audio; /* write back register */ | 147 | CGU_AUDIO = cgu_audio; /* write back register */ |
156 | } | 148 | } |
157 | 149 | ||
@@ -180,23 +172,31 @@ void * pcm_dma_addr(void *addr) | |||
180 | ** Recording DMA transfer | 172 | ** Recording DMA transfer |
181 | **/ | 173 | **/ |
182 | #ifdef HAVE_RECORDING | 174 | #ifdef HAVE_RECORDING |
175 | #define I2SIN_RECORDING_MASK ( I2SIN_MASK_POER | I2SIN_MASK_PUER | \ | ||
176 | I2SIN_MASK_POHF | I2SIN_MASK_POAF | I2SIN_MASK_POF ) | ||
183 | 177 | ||
184 | static int rec_locked = 0; | 178 | static int rec_locked = 0; |
185 | static unsigned int *rec_start_addr; | 179 | static unsigned int *rec_start_addr; |
186 | static size_t rec_size; | 180 | static size_t rec_size; |
187 | 181 | ||
188 | |||
189 | void pcm_rec_lock(void) | 182 | void pcm_rec_lock(void) |
190 | { | 183 | { |
191 | if(++rec_locked == 1) | 184 | if(++rec_locked == 1) { |
185 | int vic_state = disable_irq_save(); | ||
192 | VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; | 186 | VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; |
187 | I2SIN_MASK = 0; | ||
188 | restore_irq( vic_state ); | ||
189 | } | ||
193 | } | 190 | } |
194 | 191 | ||
195 | |||
196 | void pcm_rec_unlock(void) | 192 | void pcm_rec_unlock(void) |
197 | { | 193 | { |
198 | if(--rec_locked == 0) | 194 | if(--rec_locked == 0) { |
195 | int vic_state = disable_irq_save(); | ||
199 | VIC_INT_ENABLE = INTERRUPT_I2SIN; | 196 | VIC_INT_ENABLE = INTERRUPT_I2SIN; |
197 | I2SIN_MASK = I2SIN_RECORDING_MASK; | ||
198 | restore_irq( vic_state ); | ||
199 | } | ||
200 | } | 200 | } |
201 | 201 | ||
202 | 202 | ||
@@ -209,7 +209,10 @@ void pcm_record_more(void *start, size_t size) | |||
209 | 209 | ||
210 | void pcm_rec_dma_stop(void) | 210 | void pcm_rec_dma_stop(void) |
211 | { | 211 | { |
212 | int vic_state = disable_irq_save(); | ||
212 | VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; | 213 | VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; |
214 | I2SIN_MASK = 0; | ||
215 | restore_irq( vic_state ); | ||
213 | 216 | ||
214 | I2SOUT_CONTROL &= ~(1<<5); /* source = i2soutif fifo */ | 217 | I2SOUT_CONTROL &= ~(1<<5); /* source = i2soutif fifo */ |
215 | CGU_AUDIO &= ~((1<<23)|(1<<11)); | 218 | CGU_AUDIO &= ~((1<<23)|(1<<11)); |
@@ -224,14 +227,40 @@ void INT_I2SIN(void) | |||
224 | 227 | ||
225 | status = I2SIN_STATUS; | 228 | status = I2SIN_STATUS; |
226 | 229 | ||
227 | #if 0 /* FIXME */ | ||
228 | if ( status & ((1<<6)|(1<<0)) ) /* errors */ | 230 | if ( status & ((1<<6)|(1<<0)) ) /* errors */ |
229 | panicf("i2sin error: 0x%x = %s %s", status, | 231 | panicf("i2sin error: 0x%x = %s %s", status, |
230 | (status & (1<<6)) ? "push" : "", | 232 | (status & (1<<6)) ? "push" : "", |
231 | (status & (1<<0)) ? "pop" : "" | 233 | (status & (1<<0)) ? "pop" : "" |
232 | ); | 234 | ); |
233 | #endif | ||
234 | 235 | ||
236 | /* called at half full so it's safe to pull 16 FIFO reads in one chunk */ | ||
237 | if( rec_size >= 16*4 ) | ||
238 | { | ||
239 | /* unrolled loop */ | ||
240 | *rec_start_addr++ = *I2SIN_DATA; | ||
241 | *rec_start_addr++ = *I2SIN_DATA; | ||
242 | *rec_start_addr++ = *I2SIN_DATA; | ||
243 | *rec_start_addr++ = *I2SIN_DATA; | ||
244 | |||
245 | *rec_start_addr++ = *I2SIN_DATA; | ||
246 | *rec_start_addr++ = *I2SIN_DATA; | ||
247 | *rec_start_addr++ = *I2SIN_DATA; | ||
248 | *rec_start_addr++ = *I2SIN_DATA; | ||
249 | |||
250 | *rec_start_addr++ = *I2SIN_DATA; | ||
251 | *rec_start_addr++ = *I2SIN_DATA; | ||
252 | *rec_start_addr++ = *I2SIN_DATA; | ||
253 | *rec_start_addr++ = *I2SIN_DATA; | ||
254 | |||
255 | *rec_start_addr++ = *I2SIN_DATA; | ||
256 | *rec_start_addr++ = *I2SIN_DATA; | ||
257 | *rec_start_addr++ = *I2SIN_DATA; | ||
258 | *rec_start_addr++ = *I2SIN_DATA; | ||
259 | |||
260 | rec_size -= 16*4; /* 16x4byte reads */ | ||
261 | } | ||
262 | |||
263 | /* read out any odd samples left */ | ||
235 | while (((I2SIN_RAW_STATUS & (1<<5)) == 0) && rec_size) | 264 | while (((I2SIN_RAW_STATUS & (1<<5)) == 0) && rec_size) |
236 | { | 265 | { |
237 | /* 14 bits per sample = 1 32 bits word */ | 266 | /* 14 bits per sample = 1 32 bits word */ |
@@ -272,8 +301,7 @@ void pcm_rec_dma_start(void *addr, size_t size) | |||
272 | while ( ( I2SIN_RAW_STATUS & ( 1<<5 ) ) == 0 ) | 301 | while ( ( I2SIN_RAW_STATUS & ( 1<<5 ) ) == 0 ) |
273 | tmp = *I2SIN_DATA; /* FLUSH FIFO */ | 302 | tmp = *I2SIN_DATA; /* FLUSH FIFO */ |
274 | I2SIN_CLEAR = (1<<6)|(1<<0); /* push error, pop error */ | 303 | I2SIN_CLEAR = (1<<6)|(1<<0); /* push error, pop error */ |
275 | I2SIN_MASK = (1<<6) | (1<<0) | | 304 | I2SIN_MASK = I2SIN_RECORDING_MASK; |
276 | (1<<3) | (1<<2) | (1<<1); /* half full, almost full, full */ | ||
277 | 305 | ||
278 | VIC_INT_ENABLE = INTERRUPT_I2SIN; | 306 | VIC_INT_ENABLE = INTERRUPT_I2SIN; |
279 | } | 307 | } |
@@ -287,8 +315,17 @@ void pcm_rec_dma_close(void) | |||
287 | 315 | ||
288 | void pcm_rec_dma_init(void) | 316 | void pcm_rec_dma_init(void) |
289 | { | 317 | { |
290 | CGU_AUDIO = (CGU_AUDIO & ~(3<<12)) | (1<<12); /* clock source = PLLA */ | 318 | unsigned long frequency = pcm_sampr; |
291 | pcm_dma_apply_settings(); | 319 | |
320 | /* TODO : use a table ? */ | ||
321 | const int divider = (((AS3525_PLLA_FREQ/128) + (frequency/2)) / frequency) - 1; | ||
322 | |||
323 | int cgu_audio = CGU_AUDIO; /* read register */ | ||
324 | cgu_audio &= ~(3 << 12); /* clear i2sin clocksource */ | ||
325 | cgu_audio |= (1 << 12); /* set to PLLA */ | ||
326 | cgu_audio &= ~(511 << 14); /* clear i2sin divider */ | ||
327 | cgu_audio |= divider << 14; /* set new i2sin divider */ | ||
328 | CGU_AUDIO = cgu_audio; /* write back register */ | ||
292 | } | 329 | } |
293 | 330 | ||
294 | 331 | ||