summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafaël Carré <rafael.carre@gmail.com>2009-11-24 17:59:25 +0000
committerRafaël Carré <rafael.carre@gmail.com>2009-11-24 17:59:25 +0000
commit231e54d80f27e2df33e3f3c8b56e81e15738d81a (patch)
treeba379976493670894db4356a22feb9850ca013ee
parentcb9dff0a95cc98d83d6e1445c20bdad53614fe00 (diff)
downloadrockbox-231e54d80f27e2df33e3f3c8b56e81e15738d81a.tar.gz
rockbox-231e54d80f27e2df33e3f3c8b56e81e15738d81a.zip
Sansa AMS : fix recording
Flyspray: FS#10371 Authors: Fred Bauer and myself Only enabled on e200v2 and Fuze (crashes on clipv1) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23739 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/export/as3525.h9
-rw-r--r--firmware/export/config-e200v2.h2
-rw-r--r--firmware/export/config-fuze.h2
-rw-r--r--firmware/target/arm/as3525/pcm-as3525.c81
4 files changed, 70 insertions, 24 deletions
diff --git a/firmware/export/as3525.h b/firmware/export/as3525.h
index 07f78dafcf..d23bc2b0c8 100644
--- a/firmware/export/as3525.h
+++ b/firmware/export/as3525.h
@@ -517,5 +517,14 @@ interface */
517#define I2SIN_DATA (volatile unsigned long*)(I2SIN_BASE+0x14) 517#define I2SIN_DATA (volatile unsigned long*)(I2SIN_BASE+0x14)
518#define I2SIN_SPDIF_STATUS (*(volatile unsigned long*)(I2SIN_BASE+0x18)) 518#define I2SIN_SPDIF_STATUS (*(volatile unsigned long*)(I2SIN_BASE+0x18))
519 519
520/* I2SIN_MASK */
521
522#define I2SIN_MASK_PUER ( 1<<6 ) /* push error */
523#define I2SIN_MASK_POE ( 1<<5 ) /* empty */
524#define I2SIN_MASK_POAE ( 1<<4 ) /* almost empty */
525#define I2SIN_MASK_POHF ( 1<<3 ) /* half full */
526#define I2SIN_MASK_POAF ( 1<<2 ) /* almost full */
527#define I2SIN_MASK_POF ( 1<<1 ) /* full */
528#define I2SIN_MASK_POER ( 1<<0 ) /* pop error */
520 529
521#endif /*__AS3525_H__*/ 530#endif /*__AS3525_H__*/
diff --git a/firmware/export/config-e200v2.h b/firmware/export/config-e200v2.h
index d42f28ac2f..110555aec5 100644
--- a/firmware/export/config-e200v2.h
+++ b/firmware/export/config-e200v2.h
@@ -10,7 +10,7 @@
10#define HW_SAMPR_CAPS SAMPR_CAP_ALL 10#define HW_SAMPR_CAPS SAMPR_CAP_ALL
11 11
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_ALL
16 16
diff --git a/firmware/export/config-fuze.h b/firmware/export/config-fuze.h
index cc6669af39..4370aef42e 100644
--- a/firmware/export/config-fuze.h
+++ b/firmware/export/config-fuze.h
@@ -10,7 +10,7 @@
10#define HW_SAMPR_CAPS SAMPR_CAP_ALL 10#define HW_SAMPR_CAPS SAMPR_CAP_ALL
11 11
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_ALL
16 16
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
184static int rec_locked = 0; 178static int rec_locked = 0;
185static unsigned int *rec_start_addr; 179static unsigned int *rec_start_addr;
186static size_t rec_size; 180static size_t rec_size;
187 181
188
189void pcm_rec_lock(void) 182void 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
196void pcm_rec_unlock(void) 192void 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
210void pcm_rec_dma_stop(void) 210void 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
288void pcm_rec_dma_init(void) 316void 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