blob: 6d79ed08f17af20b28bd9e48e5808668d2c5b322 [file] [log] [blame]
Michael Sevakis5efee7c2006-11-06 18:18:05 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006 by Michael Sevakis
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#include <stdlib.h>
20#include "system.h"
21#include "kernel.h"
22#include "logf.h"
23#include "audio.h"
Michael Sevakisc2d21062007-03-11 06:21:43 +000024#include "sound.h"
Michael Sevakis8f659ae2007-05-20 20:26:36 +000025#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
Michael Sevakiscc50c142006-11-13 23:21:54 +000026#include "spdif.h"
27#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +000028
Michael Sevakis8867d002007-03-05 08:14:27 +000029#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
30 (IIS_PLAY & (7 << 8)) | \
31 (4 << 2) ) /* 64 bit clocks / word clock */
32#define IIS_FIFO_RESET (1 << 11)
33#define PDIR2_FIFO_RESET (1 << 9)
Michael Sevakis5efee7c2006-11-06 18:18:05 +000034
Jens Arnold88760182007-03-05 00:04:00 +000035#if defined(IAUDIO_X5) || defined(IAUDIO_M5)
Michael Sevakis8867d002007-03-05 08:14:27 +000036#define SET_IIS_PLAY(x) IIS1CONFIG = (x)
37#define IIS_PLAY IIS1CONFIG
38#else
39#define SET_IIS_PLAY(x) IIS2CONFIG = (x)
40#define IIS_PLAY IIS2CONFIG
41#endif
42
Michael Sevakis6077e5b2007-10-06 22:27:27 +000043struct dma_lock
44{
45 int locked;
46 unsigned long state;
47};
48
Michael Sevakis633f3882007-03-07 06:23:02 +000049static bool is_playback_monitoring(void)
50{
51 return (IIS_PLAY & (7 << 8)) == (3 << 8);
52}
53
54static void iis_play_reset_if_playback(bool if_playback)
55{
56 bool is_playback = is_playback_monitoring();
57
58 if (is_playback != if_playback)
59 return;
60
61 or_l(IIS_FIFO_RESET, &IIS_PLAY);
62}
63
Michael Sevakis5efee7c2006-11-06 18:18:05 +000064#define PLLCR_SET_AUDIO_BITS_DEFPARM \
65 ((freq_ent[FPARM_CLSEL] << 28) | (1 << 22))
Michael Sevakis5efee7c2006-11-06 18:18:05 +000066
67/** Sample rates **/
68#define FPARM_CLOCKSEL 0
69#define FPARM_CLSEL 1
70#define FPARM_FSEL 2
71#if CONFIG_CPU == MCF5249 && defined(HAVE_UDA1380)
72static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
73{
74 [HW_FREQ_88] = { 0x0c, 0x01, 0x03 },
75 [HW_FREQ_44] = { 0x06, 0x01, 0x02 },
76 [HW_FREQ_22] = { 0x04, 0x02, 0x01 },
77 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
78};
79#endif
80
81#if CONFIG_CPU == MCF5250 && defined(HAVE_TLV320)
82static const unsigned char pcm_freq_parms[HW_NUM_FREQ][3] =
83{
84 [HW_FREQ_88] = { 0x0c, 0x01, 0x02 },
85 [HW_FREQ_44] = { 0x06, 0x01, 0x01 },
86 [HW_FREQ_22] = { 0x04, 0x01, 0x00 },
87 [HW_FREQ_11] = { 0x02, 0x02, 0x00 },
88};
89#endif
90
Michael Sevakis6077e5b2007-10-06 22:27:27 +000091static unsigned long pcm_freq = 0; /* 44.1 is default */
Michael Sevakis5efee7c2006-11-06 18:18:05 +000092static const unsigned char *freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT];
93
94/* set frequency used by the audio hardware */
95void pcm_set_frequency(unsigned int frequency)
96{
97 int index;
98
99 switch(frequency)
100 {
101 case SAMPR_11:
102 index = HW_FREQ_11;
103 break;
104 case SAMPR_22:
105 index = HW_FREQ_22;
106 break;
107 default:
108 case SAMPR_44:
109 index = HW_FREQ_44;
110 break;
111 case SAMPR_88:
112 index = HW_FREQ_88;
113 break;
114 }
115
116 /* remember table entry and rate */
117 freq_ent = pcm_freq_parms[index];
118 pcm_freq = hw_freq_sampr[index];
119} /* pcm_set_frequency */
120
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000121/* apply audio settings */
Michael Sevakis633f3882007-03-07 06:23:02 +0000122bool _pcm_apply_settings(bool clear_reset)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000123{
Michael Sevakis633f3882007-03-07 06:23:02 +0000124 bool did_reset = false;
Michael Sevakis6c8772d2007-03-14 10:06:57 +0000125 unsigned long iis_play_defparm = IIS_PLAY_DEFPARM;
Michael Sevakis8867d002007-03-05 08:14:27 +0000126
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000127 if (pcm_freq != pcm_curr_sampr)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000128 {
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000129 pcm_curr_sampr = pcm_freq;
Michael Sevakis8867d002007-03-05 08:14:27 +0000130 /* Reprogramming bits 15-12 requires FIFO to be in a reset
131 condition - Users Manual 17-8, Note 11 */
132 or_l(IIS_FIFO_RESET, &IIS_PLAY);
Michael Sevakisabf41e32007-03-13 15:05:46 +0000133 /* Important for TLV320 - this must happen in the correct order
134 or starting recording will sound absolutely awful once in
135 awhile - audiohw_set_frequency then coldfire_set_pllcr_audio_bits
136 */
Michael Sevakis6c8772d2007-03-14 10:06:57 +0000137 SET_IIS_PLAY(iis_play_defparm | IIS_FIFO_RESET);
Marcoen Hirschberg77d039b2006-12-06 10:24:59 +0000138 audiohw_set_frequency(freq_ent[FPARM_FSEL]);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000139 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
Michael Sevakis633f3882007-03-07 06:23:02 +0000140 did_reset = true;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000141 }
142
Michael Sevakis6c8772d2007-03-14 10:06:57 +0000143 /* If a reset was done because of a sample rate change, IIS_PLAY will have
144 been set already, so only needs to be set again if the reset flag must
145 be cleared. If the frequency didn't change, it was never altered and
146 the reset flag can just be removed or no action taken. */
147 if (clear_reset)
148 SET_IIS_PLAY(iis_play_defparm & ~IIS_FIFO_RESET);
Michael Sevakis8867d002007-03-05 08:14:27 +0000149#if 0
150 logf("IISPLAY: %08X", IIS_PLAY);
151#endif
Michael Sevakis633f3882007-03-07 06:23:02 +0000152
153 return did_reset;
Michael Sevakis8867d002007-03-05 08:14:27 +0000154} /* _pcm_apply_settings */
155
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000156/* apply audio setting with all DMA interrupts disabled */
157void _pcm_apply_settings_irq_lock(bool clear_reset)
158{
159 int level = set_irq_level(DMA_IRQ_LEVEL);
160 _pcm_apply_settings(clear_reset);
161 set_irq_level(level);
162}
163
Michael Sevakis633f3882007-03-07 06:23:02 +0000164/* This clears the reset bit to enable monitoring immediately if monitoring
165 recording sources or always if playback is in progress - we might be
166 switching samplerates on the fly */
Michael Sevakis8867d002007-03-05 08:14:27 +0000167void pcm_apply_settings(void)
168{
Michael Sevakis633f3882007-03-07 06:23:02 +0000169 int level = set_irq_level(DMA_IRQ_LEVEL);
170 bool pbm = is_playback_monitoring();
171 bool kick = (DCR0 & DMA_EEXT) != 0 && pbm;
172
173 /* Clear reset if not playback monitoring or peripheral request is
174 active and playback monitoring */
175 if (_pcm_apply_settings(!pbm || kick) && kick)
176 PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
177
178 set_irq_level(level);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000179} /* pcm_apply_settings */
180
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000181void pcm_play_dma_init(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000182{
Michael Sevakis8867d002007-03-05 08:14:27 +0000183 AUDIOGLOB = (1 << 8) /* IIS1 fifo auto sync */
184 | (1 << 7) /* PDIR2 fifo auto sync */
185#ifdef HAVE_SPDIF_OUT
186 | (1 << 10) /* EBU TX auto sync */
187#endif
188 ;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000189 DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
Michael Sevakis8867d002007-03-05 08:14:27 +0000190 and_l(0xffffff00, &DMAROUTE);
191 or_l(DMA0_REQ_AUDIO_1, &DMAROUTE);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000192 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
193
Michael Sevakis8867d002007-03-05 08:14:27 +0000194 /* Call pcm_play_dma_stop to initialize everything. */
195 pcm_play_dma_stop();
Michael Sevakis5d637762007-03-11 05:04:48 +0000196
Michael Sevakisabf41e32007-03-13 15:05:46 +0000197 /* Setup Coldfire I2S before initializing hardware or changing
198 other settings. */
199 or_l(IIS_FIFO_RESET, &IIS_PLAY);
Michael Sevakis6c8772d2007-03-14 10:06:57 +0000200 SET_IIS_PLAY(IIS_PLAY_DEFPARM | IIS_FIFO_RESET);
Michael Sevakisabf41e32007-03-13 15:05:46 +0000201 pcm_set_frequency(HW_FREQ_DEFAULT);
202 audio_set_output_source(AUDIO_SRC_PLAYBACK);
Michael Sevakisabf41e32007-03-13 15:05:46 +0000203
Michael Sevakis5d637762007-03-11 05:04:48 +0000204 /* Initialize default register values. */
205 audiohw_init();
206
Michael Sevakis2d48d0f2007-06-08 23:42:04 +0000207 audio_input_mux(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000208
Michael Sevakisabf41e32007-03-13 15:05:46 +0000209 audiohw_set_frequency(freq_ent[FPARM_FSEL]);
210 coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000211
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000212#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
Michael Sevakiscc50c142006-11-13 23:21:54 +0000213 spdif_init();
214#endif
Michael Sevakis633f3882007-03-07 06:23:02 +0000215 /* Enable interrupt at level 6, priority 0 */
216 ICR6 = (6 << 2);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000217} /* pcm_play_dma_init */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000218
Michael Sevakisc2d21062007-03-11 06:21:43 +0000219void pcm_postinit(void)
220{
221 audiohw_postinit();
222}
223
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000224/** DMA **/
225
226/****************************************************************************
227 ** Playback DMA transfer
228 **/
229/* For the locks, DMA interrupt must be disabled when manipulating the lock
230 if the handler ever calls these - right now things are arranged so it
231 doesn't */
232static struct dma_lock dma_play_lock =
233{
234 .locked = 0,
235 .state = (0 << 14) /* bit 14 is DMA0 */
236};
237
238void pcm_play_lock(void)
239{
240 if (++dma_play_lock.locked == 1)
241 or_l((1 << 14), &IMR);
242}
243
244void pcm_play_unlock(void)
245{
246 if (--dma_play_lock.locked == 0)
247 and_l(~dma_play_lock.state, &IMR);
248}
249
250/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
251void pcm_play_dma_start(const void *addr, size_t size)
252{
253 logf("pcm_play_dma_start");
254
255 /* stop any DMA in progress */
256 DSR0 = 1;
257 DCR0 = 0;
258
259 /* Set up DMA transfer */
260 SAR0 = (unsigned long)addr; /* Source address */
261 DAR0 = (unsigned long)&PDOR3; /* Destination address */
262 BCR0 = (unsigned long)size; /* Bytes to transfer */
263
264 /* Enable the FIFO and force one write to it */
265 _pcm_apply_settings_irq_lock(is_playback_monitoring());
266
267 DCR0 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA |
268 DMA_SINC | DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
269
270 dma_play_lock.state = (1 << 14);
271} /* pcm_play_dma_start */
272
273/* Stops the DMA transfer and interrupt */
274void pcm_play_dma_stop(void)
275{
276 DSR0 = 1;
277 DCR0 = 0;
278 BCR0 = 0;
279
280 /* Place TX FIFO in reset condition if playback monitoring is on.
281 Recording monitoring something else should not be stopped. */
282 iis_play_reset_if_playback(true);
283
284 dma_play_lock.state = (0 << 14);
285} /* pcm_play_dma_stop */
286
287void pcm_play_dma_pause(bool pause)
288{
289 if (pause)
290 {
291 /* pause playback on current buffer */
292 and_l(~DMA_EEXT, &DCR0);
293 iis_play_reset_if_playback(true);
294 dma_play_lock.state = (0 << 14);
295 }
296 else
297 {
298 /* restart playback on current buffer */
299 /* Enable the FIFO and force one write to it */
300 _pcm_apply_settings_irq_lock(is_playback_monitoring());
301 or_l(DMA_EEXT | DMA_START, &DCR0);
302 dma_play_lock.state = (1 << 14);
303 }
304} /* pcm_play_dma_pause */
305
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000306size_t pcm_get_bytes_waiting(void)
307{
308 return BCR0 & 0xffffff;
309} /* pcm_get_bytes_waiting */
310
311/* DMA0 Interrupt is called when the DMA has finished transfering a chunk
312 from the caller's buffer */
313void DMA0(void) __attribute__ ((interrupt_handler, section(".icode")));
314void DMA0(void)
315{
316 int res = DSR0;
317
Michael Sevakis8867d002007-03-05 08:14:27 +0000318 DSR0 = 1; /* Clear interrupt */
319 and_l(~DMA_EEXT, &DCR0); /* Disable peripheral request */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000320 /* Stop on error */
321 if ((res & 0x70) == 0)
322 {
323 pcm_more_callback_type get_more = pcm_callback_for_more;
324 unsigned char *next_start;
325 size_t next_size = 0;
326
327 if (get_more)
328 get_more(&next_start, &next_size);
329
330 if (next_size > 0)
331 {
332 SAR0 = (unsigned long)next_start; /* Source address */
333 BCR0 = next_size; /* Bytes to transfer */
Michael Sevakis8867d002007-03-05 08:14:27 +0000334 or_l(DMA_EEXT, &DCR0); /* Enable peripheral request */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000335 return;
336 }
337 else
338 {
339 /* Finished playing */
340#if 0
341 /* int. logfs can trash the display */
342 logf("DMA0 No Data:0x%04x", res);
343#endif
344 }
345 }
346 else
347 {
Michael Sevakis8867d002007-03-05 08:14:27 +0000348 logf("DMA0 err: %02x", res);
349#if 0
350 logf(" SAR0: %08x", SAR0);
351 logf(" DAR0: %08x", DAR0);
352 logf(" BCR0: %08x", BCR0);
353 logf(" DCR0: %08x", DCR0);
354#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000355 }
356
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000357 /* Stop interrupt and futher transfers */
358 pcm_play_dma_stop();
359 /* Inform PCM that we're done */
360 pcm_play_dma_stopped_callback();
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000361} /* DMA0 */
362
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000363const void * pcm_play_dma_get_peak_buffer(int *count)
364{
365 unsigned long addr = SAR0;
366 int cnt = BCR0;
367 *count = (cnt & 0xffffff) >> 2;
368 return (void *)((addr + 2) & ~3);
369} /* pcm_play_dma_get_peak_buffer */
370
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000371/****************************************************************************
372 ** Recording DMA transfer
373 **/
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000374static struct dma_lock dma_rec_lock =
375{
376 .locked = 0,
377 .state = (0 << 15) /* bit 15 is DMA1 */
378};
379
380/* For the locks, DMA interrupt must be disabled when manipulating the lock
381 if the handler ever calls these - right now things are arranged so it
382 doesn't */
383void pcm_rec_lock(void)
384{
385 if (++dma_rec_lock.locked == 1)
386 or_l((1 << 15), &IMR);
387}
388
389void pcm_rec_unlock(void)
390{
391 if (--dma_rec_lock.locked == 0)
392 and_l(~dma_rec_lock.state, &IMR);
393}
394
Michael Sevakis51189b42006-12-06 08:34:55 +0000395void pcm_rec_dma_start(void *addr, size_t size)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000396{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000397 /* stop any DMA in progress */
398 and_l(~DMA_EEXT, &DCR1);
399 DSR1 = 1;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000400
Michael Sevakis8867d002007-03-05 08:14:27 +0000401 and_l(~PDIR2_FIFO_RESET, &DATAINCONTROL);
Michael Sevakis633f3882007-03-07 06:23:02 +0000402 /* Clear TX FIFO reset bit if the source is not set to monitor playback
Michael Sevakis8867d002007-03-05 08:14:27 +0000403 otherwise maintain independence between playback and recording. */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000404 _pcm_apply_settings_irq_lock(!is_playback_monitoring());
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000405
406 /* Start the DMA transfer.. */
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000407#ifdef HAVE_SPDIF_REC
Michael Sevakis521d6a52007-04-18 02:07:56 +0000408 /* clear: ebu1cnew, valnogood, symbolerr, parityerr */
409 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000410#endif
411
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000412 SAR1 = (unsigned long)&PDIR2; /* Source address */
413 pcm_rec_peak_addr = (unsigned long *)addr; /* Start peaking at dest */
414 DAR1 = (unsigned long)addr; /* Destination address */
415 BCR1 = (unsigned long)size; /* Bytes to transfer */
Michael Sevakis51189b42006-12-06 08:34:55 +0000416
Michael Sevakisf51df0d2006-12-12 04:25:52 +0000417 DCR1 = DMA_INT | DMA_EEXT | DMA_CS | DMA_AA | DMA_DINC |
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000418 DMA_DSIZE(DMA_SIZE_LINE) | DMA_START;
Michael Sevakis633f3882007-03-07 06:23:02 +0000419
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000420 dma_rec_lock.state = (1 << 15);
421} /* pcm_rec_dma_start */
Michael Sevakis633f3882007-03-07 06:23:02 +0000422
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000423void pcm_rec_dma_stop(void)
424{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000425 DSR1 = 1; /* Clear interrupt */
426 DCR1 = 0;
427 BCR1 = 0;
428 or_l(PDIR2_FIFO_RESET, &DATAINCONTROL);
Michael Sevakis633f3882007-03-07 06:23:02 +0000429
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000430 iis_play_reset_if_playback(false);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000431
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000432 dma_rec_lock.state = (0 << 15);
Michael Sevakis633f3882007-03-07 06:23:02 +0000433} /* pcm_rec_dma_stop */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000434
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000435void pcm_rec_dma_init(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000436{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000437 DIVR1 = 55; /* DMA1 is mapped into vector 55 in system.c */
438 DMACONFIG = 1; /* DMA0Req = PDOR3, DMA1Req = PDIR2 */
Michael Sevakis8867d002007-03-05 08:14:27 +0000439 and_l(0xffff00ff, &DMAROUTE);
440 or_l(DMA1_REQ_AUDIO_2, &DMAROUTE);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000441
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000442 pcm_rec_dma_stop();
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000443
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000444 /* Enable interrupt at level 6, priority 1 */
445 ICR7 = (6 << 2) | (1 << 0);
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000446} /* pcm_init_recording */
447
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000448void pcm_rec_dma_close(void)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000449{
Michael Sevakis8867d002007-03-05 08:14:27 +0000450 and_l(0xffff00ff, &DMAROUTE);
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000451 ICR7 = 0x00; /* Disable interrupt */
452 dma_rec_lock.state = (0 << 15);
453} /* pcm_rec_dma_close */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000454
455/* DMA1 Interrupt is called when the DMA has finished transfering a chunk
456 into the caller's buffer */
457void DMA1(void) __attribute__ ((interrupt_handler, section(".icode")));
458void DMA1(void)
459{
460 int res = DSR1;
Michael Sevakis51189b42006-12-06 08:34:55 +0000461 int status = 0;
462 pcm_more_callback_type2 more_ready;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000463
Michael Sevakis8867d002007-03-05 08:14:27 +0000464 DSR1 = 1; /* Clear interrupt */
465 and_l(~DMA_EEXT, &DCR1); /* Disable peripheral request */
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000466
467 if (res & 0x70)
468 {
Michael Sevakis51189b42006-12-06 08:34:55 +0000469 status = DMA_REC_ERROR_DMA;
Michael Sevakis8867d002007-03-05 08:14:27 +0000470 logf("DMA1 err: %02x", res);
471#if 0
472 logf(" SAR1: %08x", SAR1);
473 logf(" DAR1: %08x", DAR1);
474 logf(" BCR1: %08x", BCR1);
475 logf(" DCR1: %08x", DCR1);
476#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000477 }
Michael Sevakis8f659ae2007-05-20 20:26:36 +0000478#ifdef HAVE_SPDIF_REC
Michael Sevakisab1861a2006-11-23 19:21:15 +0000479 else if (DATAINCONTROL == 0xc038 &&
Michael Sevakis521d6a52007-04-18 02:07:56 +0000480 (INTERRUPTSTAT & ((1 << 24) | (1 << 23) | (1 << 22))))
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000481 {
Michael Sevakis521d6a52007-04-18 02:07:56 +0000482 /* reason: valnogood, symbolerr, parityerr */
483 /* clear: ebu1cnew, valnogood, symbolerr, parityerr */
484 INTERRUPTCLEAR = (1 << 25) | (1 << 24) | (1 << 23) | (1 << 22);
Michael Sevakis51189b42006-12-06 08:34:55 +0000485 status = DMA_REC_ERROR_SPDIF;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000486 logf("spdif err");
487 }
488#endif
489
490 more_ready = pcm_callback_more_ready;
491
Michael Sevakis51189b42006-12-06 08:34:55 +0000492 if (more_ready != NULL && more_ready(status) >= 0)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000493 return;
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000494
Michael Sevakis51189b42006-12-06 08:34:55 +0000495#if 0
496 /* int. logfs can trash the display */
497 logf("DMA1 done:%04x %d", res, status);
498#endif
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000499 /* Finished recording */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000500 pcm_rec_dma_stop();
501 /* Inform PCM that we're done */
502 pcm_rec_dma_stopped_callback();
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000503} /* DMA1 */
504
Michael Sevakis633f3882007-03-07 06:23:02 +0000505/* Continue transferring data in - call from interrupt callback */
Michael Sevakis51189b42006-12-06 08:34:55 +0000506void pcm_record_more(void *start, size_t size)
507{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000508 pcm_rec_peak_addr = (unsigned long *)start; /* Start peaking at dest */
509 DAR1 = (unsigned long)start; /* Destination address */
510 BCR1 = (unsigned long)size; /* Bytes to transfer */
Michael Sevakis8867d002007-03-05 08:14:27 +0000511 or_l(DMA_EEXT, &DCR1); /* Enable peripheral request */
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000512} /* pcm_record_more */
Michael Sevakis51189b42006-12-06 08:34:55 +0000513
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000514const void * pcm_rec_dma_get_peak_buffer(int *count)
Michael Sevakis5efee7c2006-11-06 18:18:05 +0000515{
Michael Sevakis6077e5b2007-10-06 22:27:27 +0000516 unsigned long addr = (unsigned long)pcm_rec_peak_addr;
517 unsigned long end = DAR1;
518 addr >>= 2;
519 *count = (end >> 2) - addr;
520 return (void *)(addr << 2);
521} /* pcm_rec_dma_get_peak_buffer */