diff options
Diffstat (limited to 'firmware/target/arm/as3525')
-rw-r--r-- | firmware/target/arm/as3525/audio-as3525.c | 61 | ||||
-rw-r--r-- | firmware/target/arm/as3525/pcm-as3525.c | 107 | ||||
-rw-r--r-- | firmware/target/arm/as3525/system-as3525.c | 4 |
3 files changed, 146 insertions, 26 deletions
diff --git a/firmware/target/arm/as3525/audio-as3525.c b/firmware/target/arm/as3525/audio-as3525.c index 410fdfad79..b616153eae 100644 --- a/firmware/target/arm/as3525/audio-as3525.c +++ b/firmware/target/arm/as3525/audio-as3525.c | |||
@@ -25,44 +25,71 @@ | |||
25 | #include "audiohw.h" | 25 | #include "audiohw.h" |
26 | #include "sound.h" | 26 | #include "sound.h" |
27 | 27 | ||
28 | int audio_channels = 2; | ||
29 | int audio_output_source = AUDIO_SRC_PLAYBACK; | ||
30 | |||
31 | void audio_set_output_source(int source) | 28 | void audio_set_output_source(int source) |
32 | { | 29 | { |
33 | if ((unsigned)source >= AUDIO_NUM_SOURCES) | 30 | (void)source; |
34 | source = AUDIO_SRC_PLAYBACK; | 31 | } |
35 | |||
36 | audio_output_source = source; | ||
37 | } /* audio_set_output_source */ | ||
38 | 32 | ||
39 | void audio_input_mux(int source, unsigned flags) | 33 | void audio_input_mux(int source, unsigned flags) |
40 | { | 34 | { |
41 | static int last_source = AUDIO_SRC_PLAYBACK; | 35 | static int last_source = AUDIO_SRC_PLAYBACK; |
42 | 36 | #ifdef HAVE_RECORDING | |
43 | (void)flags; | 37 | static bool last_recording = false; |
38 | const bool recording = flags & SRCF_RECORDING; | ||
39 | #else | ||
40 | (void) flags; | ||
41 | #endif | ||
44 | 42 | ||
45 | switch (source) | 43 | switch (source) |
46 | { | 44 | { |
47 | default: /* playback - no recording */ | 45 | default: /* playback - no recording */ |
48 | source = AUDIO_SRC_PLAYBACK; | 46 | source = AUDIO_SRC_PLAYBACK; |
49 | case AUDIO_SRC_PLAYBACK: | 47 | case AUDIO_SRC_PLAYBACK: |
50 | audio_channels = 2; | ||
51 | if (source != last_source) | 48 | if (source != last_source) |
52 | { | 49 | { |
53 | audiohw_set_monitor(false); | 50 | audiohw_set_monitor(false); |
51 | #ifdef HAVE_RECORDING | ||
52 | audiohw_disable_recording(); | ||
53 | #endif | ||
54 | } | ||
55 | break; | ||
56 | |||
57 | #ifdef HAVE_RECORDING | ||
58 | case AUDIO_SRC_MIC: /* recording only */ | ||
59 | if (source != last_source) | ||
60 | { | ||
61 | audiohw_set_monitor(false); | ||
62 | audiohw_enable_recording(true); /* source mic */ | ||
54 | } | 63 | } |
55 | break; | 64 | break; |
65 | #endif | ||
56 | 66 | ||
57 | case AUDIO_SRC_FMRADIO: /* recording and playback */ | 67 | case AUDIO_SRC_FMRADIO: /* recording and playback */ |
58 | audio_channels = 2; | 68 | if (source == last_source |
59 | if (source == last_source) | 69 | #ifdef HAVE_RECORDING |
70 | && recording == last_recording | ||
71 | #endif | ||
72 | ) | ||
60 | break; | 73 | break; |
61 | 74 | ||
62 | audiohw_set_monitor(true); | 75 | #ifdef HAVE_RECORDING |
76 | last_recording = recording; | ||
77 | |||
78 | if (recording) | ||
79 | { | ||
80 | audiohw_set_monitor(false); | ||
81 | audiohw_enable_recording(false); | ||
82 | } | ||
83 | else | ||
84 | #endif | ||
85 | { | ||
86 | #ifdef HAVE_RECORDING | ||
87 | audiohw_disable_recording(); | ||
88 | #endif | ||
89 | audiohw_set_monitor(true); /* line 2 analog audio path */ | ||
90 | } | ||
63 | break; | 91 | break; |
64 | } /* end switch */ | 92 | } |
65 | 93 | ||
66 | last_source = source; | 94 | last_source = source; |
67 | } /* audio_input_mux */ | 95 | } |
68 | |||
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 | |||
191 | static int rec_locked = 0; | ||
192 | static unsigned int *rec_start_addr; | ||
193 | static size_t rec_size; | ||
194 | |||
195 | |||
188 | void pcm_rec_lock(void) | 196 | void pcm_rec_lock(void) |
189 | { | 197 | { |
198 | if(++rec_locked == 1) | ||
199 | VIC_INT_EN_CLEAR = INTERRUPT_I2SIN; | ||
190 | } | 200 | } |
191 | 201 | ||
202 | |||
192 | void pcm_rec_unlock(void) | 203 | void pcm_rec_unlock(void) |
193 | { | 204 | { |
205 | if(--rec_locked == 0) | ||
206 | VIC_INT_ENABLE |= INTERRUPT_I2SIN; | ||
194 | } | 207 | } |
195 | 208 | ||
209 | |||
196 | void pcm_record_more(void *start, size_t size) | 210 | void 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 | |||
202 | void pcm_rec_dma_stop(void) | 217 | void 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 | |||
227 | void 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 | |||
206 | void pcm_rec_dma_start(void *addr, size_t size) | 264 | void 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 | |||
212 | void pcm_rec_dma_close(void) | 292 | void pcm_rec_dma_close(void) |
213 | { | 293 | { |
294 | pcm_rec_dma_stop(); | ||
214 | } | 295 | } |
215 | 296 | ||
216 | 297 | ||
217 | void pcm_rec_dma_init(void) | 298 | void pcm_rec_dma_init(void) |
218 | { | 299 | { |
300 | pcm_dma_apply_settings(); | ||
219 | } | 301 | } |
220 | 302 | ||
221 | 303 | ||
222 | const void * pcm_rec_dma_get_peak_buffer(int *count) | 304 | const 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 */ |
diff --git a/firmware/target/arm/as3525/system-as3525.c b/firmware/target/arm/as3525/system-as3525.c index dc335dfaad..5f01ed2dee 100644 --- a/firmware/target/arm/as3525/system-as3525.c +++ b/firmware/target/arm/as3525/system-as3525.c | |||
@@ -20,6 +20,7 @@ | |||
20 | * | 20 | * |
21 | ****************************************************************************/ | 21 | ****************************************************************************/ |
22 | 22 | ||
23 | #include "config.h" | ||
23 | #include "kernel.h" | 24 | #include "kernel.h" |
24 | #include "system.h" | 25 | #include "system.h" |
25 | #include "panic.h" | 26 | #include "panic.h" |
@@ -113,6 +114,9 @@ struct vec_int_src vec_int_srcs[] = | |||
113 | { INT_SRC_MCI0, INT_MCI0 }, | 114 | { INT_SRC_MCI0, INT_MCI0 }, |
114 | { INT_SRC_GPIOA, INT_GPIOA, }, | 115 | { INT_SRC_GPIOA, INT_GPIOA, }, |
115 | { INT_SRC_GPIOB, INT_GPIOB, }, | 116 | { INT_SRC_GPIOB, INT_GPIOB, }, |
117 | #ifdef HAVE_RECORDING | ||
118 | { INT_SRC_I2SIN, INT_I2SIN, }, | ||
119 | #endif | ||
116 | }; | 120 | }; |
117 | 121 | ||
118 | static void setup_vic(void) | 122 | static void setup_vic(void) |