summaryrefslogtreecommitdiff
path: root/firmware/target/arm/as3525/pcm-as3525.c
diff options
context:
space:
mode:
authorRafaël Carré <rafael.carre@gmail.com>2009-11-01 22:51:31 +0000
committerRafaël Carré <rafael.carre@gmail.com>2009-11-01 22:51:31 +0000
commit9b4057bbd43dfeaf69785605407e4625f01be069 (patch)
tree5d37bbedfcef2527629b1aae0ed184187832aaab /firmware/target/arm/as3525/pcm-as3525.c
parent6cdb80d7df997d3220efe03ea6779ba2c81ddf79 (diff)
downloadrockbox-9b4057bbd43dfeaf69785605407e4625f01be069.tar.gz
rockbox-9b4057bbd43dfeaf69785605407e4625f01be069.zip
Sansa AMS recording support (Microphone and FM)
Still disabled on all targets: - Fuze and e200v2 see spurious interrupts with no source defined - Clip/m200v4 deadlock instantly when starting recording (perhaps due to low memory size) Having the code in SVN will make working on this feature easier Also add keymaps for Fuze, and correct Frequency section of recording options : the 22.05kHz limitation of e200v1 and c200v1 doesn't apply to Sansa AMS (different I2S hardware, unrelated to as3514) Flyspray: FS#10371 Authors: Fred Bauer and myself git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23476 a1c6a512-1295-4272-9138-f99709370657
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 */