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.c107
1 files changed, 98 insertions, 9 deletions
diff --git a/firmware/target/arm/as3525/pcm-as3525.c b/firmware/target/arm/as3525/pcm-as3525.c
index 20579806c0..f648908474 100644
--- a/firmware/target/arm/as3525/pcm-as3525.c
+++ b/firmware/target/arm/as3525/pcm-as3525.c
@@ -69,6 +69,10 @@ static void play_start_pcm(void)
69 69
70 CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE; 70 CGU_PERI |= CGU_I2SOUT_APB_CLOCK_ENABLE;
71 CGU_AUDIO |= (1<<11); 71 CGU_AUDIO |= (1<<11);
72#ifdef HAVE_RECORDING
73 CGU_PERI &= ~CGU_I2SIN_APB_CLOCK_ENABLE;
74 CGU_AUDIO &= ~(1<<23);
75#endif
72 76
73 clean_dcache_range((void*)addr, size); /* force write back */ 77 clean_dcache_range((void*)addr, size); /* force write back */
74 dma_enable_channel(1, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT, 78 dma_enable_channel(1, (void*)addr, (void*)I2SOUT_DATA, DMA_PERI_I2SOUT,
@@ -130,9 +134,7 @@ void pcm_play_dma_init(void)
130 /* clock source PLLA, minimal frequency */ 134 /* clock source PLLA, minimal frequency */
131 CGU_AUDIO |= (511<<2) | (1<<0); 135 CGU_AUDIO |= (511<<2) | (1<<0);
132 136
133 I2SOUT_CONTROL |= (1<<6) ; /* enable dma */ 137 I2SOUT_CONTROL = (1<<6)|(1<<3) /* enable dma, stereo */;
134 I2SOUT_CONTROL |= (1<<3) ; /* stereo */
135 I2SOUT_CONTROL &= ~(1<<2); /* 16 bit samples */
136 138
137 audiohw_preinit(); 139 audiohw_preinit();
138} 140}
@@ -153,7 +155,7 @@ void pcm_dma_apply_settings(void)
153 int cgu_audio = CGU_AUDIO; /* read register */ 155 int cgu_audio = CGU_AUDIO; /* read register */
154 cgu_audio &= ~(511 << 2); /* clear i2sout divider */ 156 cgu_audio &= ~(511 << 2); /* clear i2sout divider */
155 cgu_audio |= divider << 2; /* set new i2sout divider */ 157 cgu_audio |= divider << 2; /* set new i2sout divider */
156#if 0 158#ifdef HAVE_RECORDING
157 cgu_audio &= ~(511 << 14); /* clear i2sin divider */ 159 cgu_audio &= ~(511 << 14); /* clear i2sin divider */
158 cgu_audio |= divider << 14; /* set new i2sin divider */ 160 cgu_audio |= divider << 14; /* set new i2sin divider */
159#endif 161#endif
@@ -185,43 +187,130 @@ void * pcm_dma_addr(void *addr)
185 ** Recording DMA transfer 187 ** Recording DMA transfer
186 **/ 188 **/
187#ifdef HAVE_RECORDING 189#ifdef HAVE_RECORDING
190
191static int rec_locked = 0;
192static unsigned int *rec_start_addr;
193static size_t rec_size;
194
195
188void pcm_rec_lock(void) 196void pcm_rec_lock(void)
189{ 197{
198 if(++rec_locked == 1)
199 VIC_INT_EN_CLEAR = INTERRUPT_I2SIN;
190} 200}
191 201
202
192void pcm_rec_unlock(void) 203void pcm_rec_unlock(void)
193{ 204{
205 if(--rec_locked == 0)
206 VIC_INT_ENABLE |= INTERRUPT_I2SIN;
194} 207}
195 208
209
196void pcm_record_more(void *start, size_t size) 210void pcm_record_more(void *start, size_t size)
197{ 211{
198 (void)start; 212 rec_start_addr = start;
199 (void)size; 213 rec_size = size;
200} 214}
201 215
216
202void pcm_rec_dma_stop(void) 217void pcm_rec_dma_stop(void)
203{ 218{
219 VIC_INT_EN_CLEAR = INTERRUPT_I2SIN;
220
221 I2SOUT_CONTROL &= ~(1<<5); /* source = i2soutif fifo */
222 CGU_AUDIO &= ~((1<<23)|(1<<11));
223 CGU_PERI &= ~(CGU_I2SIN_APB_CLOCK_ENABLE|CGU_I2SOUT_APB_CLOCK_ENABLE);
204} 224}
205 225
226
227void INT_I2SIN(void)
228{
229 register int status;
230 register pcm_more_callback_type2 more_ready;
231
232 status = I2SIN_STATUS;
233
234#if 0 /* FIXME */
235 if ( status & ((1<<6)|(1<<0)) ) /* errors */
236 panicf("i2sin error: 0x%x = %s %s", status,
237 (status & (1<<6)) ? "push" : "",
238 (status & (1<<0)) ? "pop" : ""
239 );
240#endif
241
242 while (((I2SIN_RAW_STATUS & (1<<5)) == 0) && rec_size)
243 {
244 /* 14 bits per sample = 1 32 bits word */
245 *rec_start_addr++ = *I2SIN_DATA;
246 rec_size -= 4;
247 }
248
249 I2SIN_CLEAR = status;
250
251 if(!rec_size)
252 {
253 more_ready = pcm_callback_more_ready;
254 if(!more_ready || more_ready(0) < 0)
255 {
256 /* Finished recording */
257 pcm_rec_dma_stop();
258 pcm_rec_dma_stopped_callback();
259 }
260 }
261}
262
263
206void pcm_rec_dma_start(void *addr, size_t size) 264void pcm_rec_dma_start(void *addr, size_t size)
207{ 265{
208 (void)addr; 266 rec_start_addr = addr;
209 (void)size; 267 rec_size = size;
268
269 if((unsigned int)addr & 3)
270 panicf("unaligned pointer!");
271
272 CGU_PERI |= CGU_I2SIN_APB_CLOCK_ENABLE|CGU_I2SOUT_APB_CLOCK_ENABLE;
273 CGU_AUDIO |= ((1<<23)|(1<<11));
274
275 I2SOUT_CONTROL |= 1<<5; /* source = loopback from i2sin fifo */
276
277 /* 14 bits samples, i2c clk src = I2SOUTIF, sdata src = AFE,
278 * data valid at positive edge of SCLK */
279 I2SIN_CONTROL = (1<<5) | (1<<2);
280
281 unsigned long tmp;
282 while ( ( I2SIN_RAW_STATUS & ( 1<<5 ) ) == 0 )
283 tmp = *I2SIN_DATA; /* FLUSH FIFO */
284 I2SIN_CLEAR = (1<<6)|(1<<0); /* push error, pop error */
285 I2SIN_MASK = (1<<6) | (1<<0) |
286 (1<<3) | (1<<2) | (1<<1); /* half full, almost full, full */
287
288 VIC_INT_ENABLE |= INTERRUPT_I2SIN;
210} 289}
211 290
291
212void pcm_rec_dma_close(void) 292void pcm_rec_dma_close(void)
213{ 293{
294 pcm_rec_dma_stop();
214} 295}
215 296
216 297
217void pcm_rec_dma_init(void) 298void pcm_rec_dma_init(void)
218{ 299{
300 pcm_dma_apply_settings();
219} 301}
220 302
221 303
222const void * pcm_rec_dma_get_peak_buffer(int *count) 304const void * pcm_rec_dma_get_peak_buffer(int *count)
223{ 305{
224 (void)count; 306 const void *peak_buffer;
307
308 pcm_rec_lock();
309 *count = rec_size >> 2;
310 peak_buffer = (const void*)rec_start_addr;
311 pcm_rec_unlock();
312
313 return peak_buffer;
225} 314}
226 315
227#endif /* HAVE_RECORDING */ 316#endif /* HAVE_RECORDING */